预加载 CSS 图像

Posted

技术标签:

【中文标题】预加载 CSS 图像【英文标题】:Preloading CSS Images 【发布时间】:2010-11-25 06:43:52 【问题描述】:

我有一个隐藏的联系表单,通过单击按钮进行部署。它的字段被设置为 CSS 背景图像,并且它们总是比被切换的 div 显示得晚一点。

我在<head> 部分使用了这个sn-p,但没有运气(在我清除缓存之后):

<script>
$(document).ready(function() 
        pic = new Image();
        pic2 = new Image();
        pic3 = new Image();
        pic.src="<?php bloginfo('template_directory'); ?>/images/inputs/input1.png";
        pic2.src="<?php bloginfo('template_directory'); ?>/images/inputs/input2.png";
        pic3.src="<?php bloginfo('template_directory'); ?>/images/inputs/input3.png";
);
</script>

我正在使用 jQuery 作为我的库,如果我也可以使用它来安排这个问题,那就太棒了。

感谢您的考虑。

【问题讨论】:

请出示您的代码。你如何切换这个表单? n1313,我使用最简单的方法:$('#toggle').click(function() $('#contact').slideToggle(); ); 【参考方案1】:

仅使用 CSS 预加载图片

在下面的代码中,我随机选择了body 元素,因为它是唯一保证存在于页面上的元素之一。

为了使“技巧”发挥作用,我们将使用content 属性,它可以轻松设置要加载的多个 URL,但如图所示,::after 伪元素被保留隐藏所以图像不会被渲染:

body::after
   position:absolute; width:0; height:0; overflow:hidden; z-index:-1; // hide images
   content:url(img1.png) url(img2.png) url(img3.gif) url(img4.jpg);   // load images

Demo


最好使用sprite image 来减少http 请求...(如果有许多相对较小的图像)并确保将图像托管在使用HTTP2 的位置。

【讨论】:

迄今为止最好的技术,因为它的简单性和纯 CSS 方法!唯一的缺点是这些图像与立即可见的内容同时加载,并且不会延迟到主要内容加载之后,这需要 javascript。但是,除非您要预加载几十张图片,否则这不应该是一个交易破坏者。 这对于为 CSS 按钮等预加载悬停资源非常棒 - 这样在资源加载时您在按钮上方时不会出现任何闪烁 很好的解决方案。不过,我建议不要将其应用于body,因为这些图像将被加载到引用样式表的每个页面上。相反,您应该使用.contact_form:after ... 或其他一些不那么全局的类。当然,除非您的联系表格在每一页上;) @CloudMagick - 不能在这里提出建议。每个用例都是独一无二的。我自己确实在body上使用它,因为有svg和gif图片,就是所谓的“加载动画”,可以随时随地显示,所以必须跨站预加载。 @vsync,这是有道理的,尤其是对于 gif 和小型可重用文件。我最近遇到的情况是内容丰富的轮播的大型 bg 图像,我当然不希望到处加载这些大文件 :)【参考方案2】:

使用 html 标签预加载图片

我相信这个问题的大多数访问者都在寻找“如何在页面渲染开始之前预加载图像?”的答案,这个问题的最佳解决方案是使用@987654325 @ 标记,因为&lt;link&gt; 标记能够阻止页面的进一步呈现。见preemptive

rel当前文档与链接文档之间的关系)属性的这两个值选项与问题最相关:

prefetch : 在页面渲染时加载给定的资源 preload : 在页面渲染开始之前加载给定的资源

所以如果你想在&lt;body&gt;标签的渲染过程开始之前加载一个资源(在这种情况下是一个图像),使用:

<link rel="preload" as="image" href="IMAGE_URL">

如果您想在 &lt;body&gt; 呈现时加载资源,但您计划稍后动态使用它并且不想在加载时间上打扰用户,请使用:

<link rel="prefetch" href="RESOURCE_URL">

【讨论】:

值得注意的是,Mozilla浏览器引擎只会在浏览器空闲时加载prefetch,这是由nsIWebProgressListener API决定的。请参阅this 了解更多信息。 我不认为这实际上会阻塞渲染:w3c.github.io/preload "例如,应用程序可以使用 preload 关键字来启动 CSS 的早期、高优先级和非渲染阻塞获取然后可以由应用程序在适当的时间应用的资源" @MichaelCrenshaw 是正确的,&lt;link rel="preload"&gt; 确实 not 阻止渲染,我相信作者误解了定义。来自 MDN Preloading content with rel="preload",“......您希望在页面生命周期的早期开始加载,在浏览器的主要渲染机制启动之前。”这个想法是尽快获取资源,从而更有可能在需要时提供资源,例如在呈现&lt;img&gt; 元素时。 我想将图像用作带有 css 的background-image,这对我有用,而接受的答案却没有。【参考方案3】:

我可以确认我的原始代码似乎有效。我随便贴了一张路径错误的图片。

这是一个测试:http://paragraphe.org/slidetoggletest/test.html

<script>
    var pic = new Image();
    var pic2 = new Image();
    var pic3 = new Image();
    pic.src="images/inputs/input1.png";
    pic2.src="images/inputs/input2.png";
    pic3.src="images/inputs/input3.png";
</script>

【讨论】:

在使用 CSS-ONLY 和这个解决方案进行了几次测试之后,特别是在我的情况下,这是最好的一个。 感谢它是最简单的:) 答案中的网址不再有效。 嗨,我重新上传了那个 URL (paragraphe.org/slidetoggletest/test.html) 上的内容,很抱歉错过了这个。干杯,【参考方案4】:

http://css-tricks.com/snippets/css/css-only-image-preloading/

技巧#1

在元素的常规状态下加载图像,仅将其与背景位置移开。然后移动背景位置以在悬停时显示。

#grass  background: url(images/grass.png) no-repeat -9999px -9999px; 
#grass:hover  background-position: bottom left; 

技巧#2

如果有问题的元素已经应用了背景图像并且您需要更改该图像,则上述方法将不起作用。通常你会在这里选择一个精灵(一个组合的背景图像),然后移动背景位置。但如果这不可能,试试这个。将背景图片应用到另一个已在使用但没有背景图片的页面元素。

#random-unsuspecting-element  background: url(images/grass.png) no-repeat -9999px -9999px; 
#grass:hover  background: url(images/grass.png) no-repeat; 

【讨论】:

始终提供外部链接的内容。否则,如果链接断开,您的答案将毫无价值! @Fatih +1 非常好的链接。链接文章的最新版本有 3 种不同的方式在这里perishablepress.com/3-ways-preload-images-css-javascript-ajax @xmojmr 您的链接中没有纯 CSS 解决方案。【参考方案5】:

试试这个:

var c=new Image("Path to the background image");
c.onload=function()
   //render the form

使用此代码,您可以预加载背景图像并在加载时呈现表单

【讨论】:

mck89,谢谢,这看起来不错。但是,我应该在 'head' 或 inline 中使用此代码吗?我的意思是,我必须用 html 填充它吗? 你必须在头部使用它。我认为你可以在 $(document).ready 中使用它【参考方案6】:

对于使用 CSS 设置的预加载背景图像,我想出的最有效的答案是我发现一些代码的修改版本不起作用:

$(':hidden').each(function() 
  var backgroundImage = $(this).css("background-image");
  if (backgroundImage != 'none') 
    tempImage = new Image();
    tempImage.src = backgroundImage;
  
);

这样做的巨大好处是,当您将来引入新的背景图像时,您无需更新它,它会找到新的并预加载它们!

【讨论】:

我是否理解正确,您确实为每个图像添加了隐藏元素?不是说它能够扫描您的 CSS 文件中的图像吗? :)【参考方案7】:

如果您在网站上的其他任何地方重复使用这些 bg 图片作为表单输入,您可能希望使用图片精灵。这样您就可以集中管理您的图像(而不是拥有 pic1、pic2、pic3 等......)。

对于客户端来说,Sprite 通常更快,因为它们只从服务器请求一个(尽管稍微大一点)文件,而不是多个文件。有关更多好处,请参阅 SO 文章:

CSS image sprites

再一次,如果您只是将这些用于一个表单并且您真的只想在用户请求联系表单时加载它们,这可能根本没有帮助......不过可能有意义。

http://www.alistapart.com/articles/sprites

【讨论】:

是的,CSS Sprites 是要走的路。只需确保该精灵中的一张图片在隐藏表单启动之前出现(例如在页面加载时)。【参考方案8】:

如何在隐藏的地方加载该背景图像。 这样它会在页面打开时加载,并且在使用 ajax 创建表单后不会花费任何时间:

body 
background: #ffffff url('img_tree.png') no-repeat -100px -100px;

【讨论】:

【参考方案9】:

你可以使用这个 jQuery 插件 waitForImage 或者你可以把你的图片放到一个隐藏的 div 或(width:0 and height:0)中,然后在图片上使用 onload 事件。

如果您只有 2-3 张图片,您可以绑定事件并以链的形式触发它们,因此您可以在每张图片之后执行一些代码。

【讨论】:

【参考方案10】:

唯一的方法是对图像进行 Base64 编码并将其放在 HTML 代码中,这样它就不需要联系服务器来下载图像。

This 将从 url 编码图像,因此您可以复制图像文件代码并将其插入到您的页面中...

body 
  background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...);

【讨论】:

如果您想在 CSS 中再次使用同一张图片...它不会被缓存,您必须再次加载它。【参考方案11】:

如果无法修改 CSS 代码并使用 :before:after 伪元素的 CSS 规则预加载图像,则可以使用另一种 JavaScript 代码遍历已加载样式表的 CSS 规则的方法。为了使它在 HTML 中工作 scripts should be included after stylesheets,例如,在关闭 body 标记之前或在样式表之后。

getUrls() 
    const urlRegExp = /url\(('|")?([^'"()]+)('|")\)?/;

    let urls = [];
    for (let i = 0; i < document.styleSheets.length; i++) 
        let cssRules = document.styleSheets[i].cssRules;
        for (let j = 0; j < cssRules.length; j++) 
            let cssRule = cssRules[j];
            if (!cssRule.selectorText) 
                continue;
            

            for (let k = 0; k < cssRule.style.length; k++) 
                let property = cssRule.style[k],
                    urlMatch = cssRule.style[property].match(urlRegExp);
                if (urlMatch !== null) 
                    urls.push(urlMatch[2]);
                
            
        
    
    return urls;


preloadImages() 
    return new Promise(resolve => 
        let urls = getUrls(),
            loadedCount = 0;

        const onImageLoad = () => 
            loadedCount++;
            if (urls.length === loadedCount) 
                resolve();
            
        ;

        for (var i = 0; i < urls.length; i++) 
            let image = new Image();
            image.src = urls[i];
            image.onload = onImageLoad;
        
    );


document.addEventListener('DOMContentLoaded', () => 
    preloadImages().then(() => 
        // CSS images are loaded here
    );
);

【讨论】:

【参考方案12】:

如果页面元素及其背景图像已经在 DOM 中(即您没有动态创建/更改它们),那么它们的背景图像将已经加载。到那时,你可能想看看压缩方法:)

【讨论】:

mmmm...cpharmston 好点,这就解释了为什么即使缓存了图像,问题仍然存在。那么,这确实意味着没有解决方法? 创建更小的图像! JPEG 很容易压缩,有用于减小 PNG 大小的命令行工具 (pmt.sourceforge.net/pngcrush),并且您可以减少图像中的颜色数量以减小 GIF 的大小。当然,您也可以享受更快的互联网服务;)【参考方案13】:

我也想补充一点小提示。

如果您没有在网络选项卡的开发控制台设置中禁用缓存,则回答“仅使用 CSS 预加载图像”非常有效。 否则它将双重加载图像。

【讨论】:

以上是关于预加载 CSS 图像的主要内容,如果未能解决你的问题,请参考以下文章

预加载隐藏的 CSS 图像

CSS 使用CSS预加载图像

预加载 CSS 图像

如何在 HTML 5 中为音频、视频、css、图像创建预加载器?

图像预加载技术(用作悬停状态 CSS 背景图像)似乎不适用于 Chrome

css 图像预加载