不要加载隐藏的图像
Posted
技术标签:
【中文标题】不要加载隐藏的图像【英文标题】:Don't load hidden images 【发布时间】:2011-04-18 14:22:09 【问题描述】:我的网站上有一堆隐藏的图片。他们的容器 DIV 有 style="display: none"。根据用户的操作,某些图像可能会通过 javascript 显示。问题是我的所有图像都是在打开页面时加载的。我想通过只加载最终变得可见的图像来减轻服务器的压力。我想知道是否有一种纯 CSS 方法可以做到这一点。这是我目前正在做的两种 hacky/complicated 方式。如您所见,这不是干净的代码。
<div id="hiddenDiv">
<img src="spacer.gif" />
</div>
.reveal .img
background-image: url(flower.png);
$('hiddenDiv').addClassName('reveal');
这里是方法二:
<img id="flower" fakeSrc="flower.png" />
function revealImage(id)
$('id').writeAttribute(
'src',
$('id').readAttribute('fakeSrc')
);
revealImage('flower');
【问题讨论】:
【参考方案1】:浏览器将加载任何设置了src
属性的图像,因此您要做的是在标记中使用data-src
,并在您希望加载时使用JavaScript 设置src
属性。
<img class="hidden" data-src="url/to/image.jpg" />
我创建了这个小插件来解决这个问题:
(function($)
// Bind the function to global jQuery object.
$.fn.reveal = function()
// Arguments is a variable which is available within all functions
// and returns an object which holds the arguments passed.
// It is not really an array, so by calling Array.prototype
// he is actually casting it into an array.
var args = Array.prototype.slice.call(arguments);
// For each elements that matches the selector:
return this.each(function()
// this is the dom element, so encapsulate the element with jQuery.
var img = $(this),
src = img.data("src");
// If there is a data-src attribute, set the attribute
// src to make load the image and bind an onload event.
src && img.attr("src", src).load(function()
// Call the first argument passed (like fadeIn, slideIn, default is 'show').
// This piece is like doing img.fadeIn(1000) but in a more dynamic way.
img[args[0]||"show"].apply(img, args.splice(1));
);
);
(jQuery));
在您要加载/显示的图像上执行.reveal
:
$("img.hidden").reveal("fadeIn", 1000);
见test case on jsFiddle。
【讨论】:
+1。非常感谢。我知道这是“标准”javascript,但仍然如此。你介意解释一下后面的部分吗?谢谢,桑尼。 @SunnyRed 从什么时候 jQuery 成为标准 javascript?我正在编辑答案以添加一些 cmets,检查答案以了解会发生什么。【参考方案2】:这是一个 jQuery 解决方案:
$(function ()
$("img").not(":visible").each(function ()
$(this).data("src", this.src);
this.src = "";
);
var reveal = function (selector)
var img = $(selector);
img[0].src = img.data("src");
);
它与您的解决方案类似,只是它不使用标记中的fakeSrc
属性。它清除src
属性以阻止其加载并将其存储在其他位置。一旦准备好显示图像,就可以像在解决方案中一样使用reveal
函数。如果您不使用 jQuery,我深表歉意,但该过程应该可以转移到您使用的任何框架(如果有)。
注意:此代码必须在窗口触发 load
事件之前但在加载 DOM 之后运行。
【讨论】:
如何在加载窗口之前加载它,但在加载 DOM 之后? @Kenneth B:这段代码应该做到这一点。将函数传递给jQuery/$
对象是$(document).ready
的快捷方式。
不保证会起作用。浏览器的推测预扫描器可以在此脚本代码运行之前很久就下载标记中的图像。
如果您想停止加载隐藏在 <div>
内的图像,解决方案会是什么样子?
这没有意义。图像将在 jQuery 加载时被调用。【参考方案3】:
这部分取决于您的图像必须如何放置在您的代码中。您是否能够将图像显示为
的背景,或者您是否需要使用 标签?如果你需要 标签,你可能会被使用的浏览器搞砸。一些浏览器足够聪明,可以识别图像何时位于隐藏对象内部或宽度/高度为 0 的对象中,并且不会加载它,因为无论如何它本质上是不可见的。出于这个原因,如果您希望图像被预加载但不可见,许多人会建议将图像放在 1x1 像素 中。如果您不需要 标签,大多数浏览器不会加载 CSS 引用的图像,直到相关元素变得可见。
请注意,如果不使用 AJAX 下载图像,则无法 100% 确定浏览器不会预加载图像。为了“加快”平均加载时间,浏览器想要预加载它假定以后可能使用的任何东西,这并不令人难以置信。
【讨论】:
img 标签不是必需的,但它使更多的 html 在语义上更正确,更容易让同事理解。 明白了。总是要帮助同事理解。不过,我建议看看丹尼尔的回答。他想到了一些我什至没有想到的事情。也可能是最好的解决方案。【参考方案4】:奇怪的是,对于已经在大多数浏览器中实现的本机延迟加载,没有答案。
您可以通过将loading="lazy"
属性添加到您的图像来做到这一点。
Addy Osmani 写了一篇很棒的文章。您可以在此处阅读有关延迟加载的更多信息:https://addyosmani.com/blog/lazy-loading/
【讨论】:
请注意,这不会按预期工作。如果隐藏图像在视口中,即使使用loading="lazy"
也会加载它们。 jsfiddle.net/jnrhycdg/1
实际上你给我的例子在 chrome 上可以正常工作。它仅在删除 display:none 后加载。但是,是的,我听说惰性有一些怪癖,但总的来说,我认为这是一种很好的未来证明方法,与 js 解决方案相比,它的开销非常小。【参考方案5】:
使用 CSS 将图像置于未使用的类中,然后使用 javascript 将该类添加到元素中将是您最好的选择。如果你根本不使用图像标签,这个解决方案会变得更加明显。
不过,从透视角度来看,大多数人都有相反的问题,他们希望预加载图像,以便在被告知显示时立即显示。
【讨论】:
【参考方案6】:如果你可以依赖脚本,还有背景图片方法和图片src方法。简而言之,将所有隐藏图像设置为一些非常小的图像(减少服务器的压力)或根本不存在的图像(谁在乎?访问者无论如何都看不到图像丢失 [X],div 被隐藏)然后用脚本改变它...
<img src="I_do_not_exist.jpg" id="my_image" />
<input type="button" onclick="document.getElementById('my_image').src='I_exist.jpg';" Value="change image" />
<br /><br /><br />
<div id="mydiv" style="width:40px; height:40px; border:2px solid blue"></div>
<input type="button" onclick="document.getElementById('my_div').style.width='455px';document.getElementById('my_div').style.height='75px';document.getElementById('my_div').style.backgroundImage='url(I_exist.jpg)';" Value="change background image" />
我在上面的示例中留下了一个宽度,以表明在您要求加载之前,div 图像中没有任何内容。
【讨论】:
谁在乎?好吧,每个 HTTP 请求都会对服务器本身造成性能损失,所以这仍然会导致问题。这不是一个好的解决方案。【参考方案7】:If you make the image a background-image of a div in CSS, when that div is set to 'display: none', the image will not load.
您可以对纯 CSS 解决方案执行以下操作,它还可以使 img 框在响应式设计设置中实际上表现得像一个 img 框(这就是透明 png 的用途),如果您的设计使用响应式,这尤其有用- 动态调整图像大小。
<img style="display: none; height: auto; width:100%; background-image:
url('img/1078x501_1.jpg'); background-size: cover;" class="center-block
visible-lg-block" src="img/400x186_trans.png" >
只有在触发与 visible-lg-block 相关的媒体查询并将 display:none 更改为 display:block 时才会加载图像。透明 png 用于允许浏览器在流畅的设计(高度:自动;宽度:100%)中为您的 块(以及背景图像)设置适当的高度:宽度比率。
1078/501 = ~2.15 (large screen)
400/186 = ~2.15 (small screen)
因此,对于 3 个不同的视口,您最终会得到以下内容:
<img style="display: none; height: auto; width:100%; background-image: url('img/1078x501_1.jpg'); background-size: cover;" class="center-block visible-lg-block" src="img/400x186_trans.png" >
<img style="display: none; height: auto; width:100%; background-image: url('img/517x240_1.jpg'); background-size: cover;" class="center-block visible-md-block" src="img/400x186_trans.png" >
<img style="display: none; height: auto; width:100%; background-image: url('img/400x186_1.jpg'); background-size: cover;" class="center-block visible-sm-block" src="img/400x186_trans.png" >
在初始加载期间仅加载默认媒体视口大小的图像,然后根据您的视口动态加载图像。
而且没有 javascript!
【讨论】:
以上是关于不要加载隐藏的图像的主要内容,如果未能解决你的问题,请参考以下文章