更新:这篇文章有点老了。如果你现在想要延迟加载图片,我建议你看看
使用一个 blank.gif
作为图片的 src
,并包含最终图片的 width
和 height
。
<img src="blank.gif" class="lazy" data-src="/images/full-size.jpg" width="240" height="152">
/* lazyload.js (c) Lorenzo Giuliani
* MIT License (https://open-source.org.cn/licenses/mit-license.html)
*
* expects a list of:
* `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">`
*/
!function(window){
var $q = function(q, res){
if (document.querySelectorAll) {
res = document.querySelectorAll(q);
} else {
var d=document
, a=d.styleSheets[0] || d.createStyleSheet();
a.addRule(q,'f:b');
for(var l=d.all,b=0,c=[],f=l.length;b<f;b++)
l[b].currentStyle.f && c.push(l[b]);
a.removeRule(0);
res = c;
}
return res;
}
, addEventListener = function(evt, fn){
window.addEventListener
? this.addEventListener(evt, fn, false)
: (window.attachEvent)
? this.attachEvent('on' + evt, fn)
: this['on' + evt] = fn;
}
, _has = function(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
;
function loadImage (el, fn) {
var img = new Image()
, src = el.getAttribute('data-src');
img.onload = function() {
if (!! el.parent)
el.parent.replaceChild(img, el)
else
el.src = src;
fn? fn() : null;
}
img.src = src;
}
function elementInViewport(el) {
var rect = el.getBoundingClientRect()
return (
rect.top >= 0
&& rect.left >= 0
&& rect.top <= (window.innerHeight || document.documentElement.clientHeight)
)
}
var images = new Array()
, query = $q('img.lazy')
, processScroll = function(){
for (var i = 0; i < images.length; i++) {
if (elementInViewport(images[i])) {
loadImage(images[i], function () {
images.splice(i, i);
});
}
};
}
;
// Array.prototype.slice.call is not callable under our lovely IE8
for (var i = 0; i < query.length; i++) {
images.push(query[i]);
};
processScroll();
addEventListener('scroll',processScroll);
}(this);
查看笔
延迟加载图片 by Chris Coyier (@chriscoyier)
在 CodePen 上。
你有演示吗?
上面的链接叫“参考 URL”
尝试在我的网站上测试。工作正常。
这里有一个演示,来自这个很棒的关联库(我还没在这里找到链接):http://afarkas.github.io/lazysizes/
那里有更多的代码,我不知道它还处理什么,但它运行得完美无缺!
看看吧。
https://css-tricks.cn/examples/LazyLoading/
我的错。它在 iPad 上不起作用,是吗?我的 iPad2 什么也没发生。
我的 iPad 3 也一样 - 什么也没发生,没有备用方案可以看,即使是 2014 年 2 月 23 日更新的最新版本…
为了让它在 iPad 上工作,你只需要更改
addEventListener(‘scroll’,processScroll);
为
addEventListener(‘touchmove’,processScroll);
我知道这已经过时了,但我也有这个问题。在触控设备上,它会等到滚动完成后才加载,这意味着在 iPhone 上,在它慢慢停止时会显示一个空白图片几秒钟。我按照 Matt 的建议修复了它,方法是添加
然后写另一个函数,它不会检查是否在视窗中,而是在第一次滚动时加载图片
我的问题解决了!希望这对你也有帮助。
Chris,没有 JS 的用户会怎么样?这似乎不是一个好主意… 就像你在 iPad 等设备上看到的那样;)
@Anselm:iPad 不是没有 JS 的用户。它是一个触控/移动用户(可能是不同的滚动事件?)。
我认为我们已经很久没有再为没有 JS(标准)的用户构建备用方案了。尤其是在图片方面。
你可以在标记中使用一个简单的备用方案
并在 CSS 中使用 modernizr.js
@Robin,你应该始终为没有 JavaScript 支持的用户提供备用方案。
你也可以添加一个函数,它解析 DOM 以在页面加载后创建数据源,该数据源动态替换 src 属性。
我一直都在构建一个快速、独立且健壮的延迟加载器。
你可以在此处找到它:https://github.com/fasterize/lazyload
为什么不加入我们?:)
你的延迟加载器没有解决很多用例,例如在视窗中加载的图片(因此没有滚动事件)。等等(参见 test/)。
很高兴阅读你的代码并进行比较。
谢谢
我在 dailyjs 上看到你的代码几天后,如果我有补丁,我会给你发一个拉取请求。
这里有一个更新的 Gist:2171438,不记得提交的版本和 gist 之间有什么区别。
嗨,Vincent!这个插件可以用于 background-image 属性,而不是使用标签吗?谢谢!
在我的博客上,这不起作用,
请帮助我…
我可能问了一个愚蠢的问题,但是… 这有什么用?让图片加载速度比它们应该的慢?为什么?
拜托,我不是想苛刻,我只是不明白。
这是为了防止不必要的图片加载并优化带宽使用。
如果用户点击你的页面,为什么你要浪费带宽加载文章底部的照片,而用户根本没有滚动到那里查看它?
是为了节省带宽。在一个流量很大的网站上,假设 500 万用户中有 200 万用户访问一篇包含大量图片的博文,但从未滚动到底部。在页面折叠下方,有 750k 的图片。这将为你节省大量的带宽(150 万兆字节…)。
这是为了确保人们在阅读文章时保持在线状态。如果一些笔记本电脑用户决定在家里通过 Wi-Fi 加载页面并打开一个标签页,然后上车,在离线状态下继续阅读,那么他就无法看到图片。
嗨,为了获得 PageSpeed Insights 的最佳分数。但为了获得更好的移动体验…
但是它在 Firefox 和隐私保护严格设置下不起作用 :-(
延迟加载图片是为了推迟加载浏览器视窗之外的图片。这样,这些图片在需要之前就不需要占用带宽,从而为其他资源留出空间,使它们加载得更快。
最终使网页加载更快。
避免由于多个繁重的加载请求导致服务器挂起
我给你…
一个 jQuery 版本!
看看,随时批评或提出改进建议
http://jsfiddle.net/g8THY/6/
它比原来的小,但做了同样的事情,如果你正好在使用 jQuery,这可能是一件好事…
我个人喜欢这个网站的实现方式
http://www.nomachetejuggling.com/2011/11/11/the-star-wars-saga-suggested-viewing-order/
(快速滚动。)
我喜欢它使用了真实的 src 属性,像平常一样。它更容易实现,不需要为每个图片使用特殊的标记或 JS 备用方案。
不幸的是,这似乎违背了延迟加载的初衷。查看网络检查器后,我发现每个图片在页面加载时都被加载,并在滚动到底部时再次加载。暂时隐藏图片可能会带来一些性能优势,例如在内存较低的设备(如旧款 iPhone)中,但它不会像 Coyier 的解决方案那样防止不必要的网络流量。
如果我们能够兼得两全其美——普通的标记和真正的延迟图像加载——那就太好了,但我对此表示怀疑。使用真正的 src 属性基本上保证了图像将在 JS 干预之前开始加载。
是的,这个特别好用。
在 FF11 上,向下滚动,什么也没发生:\
之前的评论没有出现(可能是垃圾邮件文件夹?)
你的脚本在并发性方面存在问题。当你延迟加载图像时,如果占位符仍在剪裁矩形内,而你正在滚动,你将一次又一次地请求图像,直到图像完全加载。你必须将回调函数移出,以在第一次请求图像时从数组中移除它。
我在 IE(不出所料)中使用 WordPress 并通过 PHP 加载图像时遇到了麻烦。有什么想法可以解决这个问题吗?
嗨,克里斯:
只想提一下,我认为代码中存在错误。我认为你在 processScroll 函数中错误地使用了 splice 方法——第二个参数应该是 '1' 而不是 'i'。我在使用 splice(i, i) 时遇到了一些奇怪的结果(当然)。
我错了?
问候
多米尼克
不仅仅是那个。我认为存在几个错误。
splice(i,1) 而不是 (i,i) ,正如多米尼克提到的。
lambda 并没有绑定到当前迭代的 i——它最终等于终止 i。也就是说,i==images.length。这就是为什么 splice(i,i) 没有破坏任何东西——你始终是在说 splice(images.length, images.length),这是一个空操作。
即使你创建了 i 的本地副本,以便 lambda 获取正确的索引,它仍然是循环运行时时的索引。触发几个 lambda,一个触发,突然其他 lambda 中的索引可能就错了,因为数组在它们下方发生了变异。
我最终将 images 变成一个对象,并将索引作为属性。这样,当东西被删除时,索引就不会失效。
搜索引擎将无法找到这些图像,是吗?
嘿!搜索引擎会读取图像元素的 alt 标签,如果你提到了 alt 标签,那么搜索引擎就会找到这些图像。
我不这么认为……图像搜索怎么办?搜索引擎会从 data-src 属性中获取图像 URL 吗?
不会……我也想不出一个好的方法来以另一种方式嵌入它们,这样 SE 就能看到它们。你可以为 SE 提供一个替代的标准 HTML 页面,在这个页面中,图像不会被延迟加载(捕获它们并重定向,或者在页面底部/顶部放置一个链接)。
嘿,可能比人们喜欢的要复杂得多,但一种方法是检查用户代理以查看它是否是任何流行的搜索引擎,如果是,就按平常的方式加载图像。虽然我不确定这是否会引起红旗。我想他们可能会向网站发送替代的 user_agents 并比较内容,以检测潜在的 SE 操纵。只是一个想法。
克里斯:“是为了节省带宽。”
它不会也减少页面加载时间吗?这可能是一个 SEO 因素(如果它足够糟糕)。以及一个可用性因素,因为似乎页面功能在 DOM 加载之前无法工作(在我们当地报纸网站上让我很抓狂——页面在他们的功能失调的服务器加载所有广告之前是“冻结”的)。
感谢你提供脚本。有没有一种简单的方法可以添加效果?比如淡入或延迟?
还没有尝试过,但在我看来,一种优雅降级(可能更利于 SEO)的方法是提供指向完整图像的链接。
你可以在链接中包含一些图像数据(
width
、height
、alt
/title
),作为data-
属性。然后,通过 JS,你可以
1) 创建
<img />
标签。在src
属性上,你使用blank.gif
,在data-src
上,你放置指向完整图像的 URL(从a
元素的href
属性获取)。可选:为了获得更好的用户体验,你还可以设置width
、height
、alt
和title
,这些属性可以从a
元素的data-
属性中获取。2) 你像往常一样延迟加载它们,当用户滚动页面时。
抓取程序/蜘蛛/机器人通常不会触发大多数 JS 事件,因此这些属性永远不会触发。
我认为你忽略了一些东西。
如果禁用了 JavaScript,则根本不会显示任何图像,这从用户的角度来看是不好的。
有些人更喜欢在没有启用 JavaScript 的情况下浏览,网站应该能够相应地降低其功能。
在这种情况下,如果禁用了 JavaScript,最好显示所有图像。
即使在带宽方面成本更高,但至少用户会得到一个可读的页面。
只有 Web 开发人员认为延迟加载很酷。(和以前认为 Ajax 很酷的人一样……在那之前是框架……无论当今的设计潮流是什么)
延迟加载的问题在于它阻止了人眼快速扫描。事实上,延迟加载假设人眼无法扫描图像。
谷歌用延迟加载毁了他们的图像搜索。
为什么这么多 Web 开发人员喜欢退化浏览的便捷性?
试着在一个页面上放置一百张图像,即使是小的图像。
不是关于设计,而是使视觉密集的页面更流畅。
是的,谷歌也认为他们的图像搜索很好。
猴子工程师
延迟加载在首页有效,但在其他页面无效。问题可能是什么?
如果我使用框架或 CMS,如何使用这个脚本?
搜索引擎会抓取“data-src”属性中的链接吗?
感谢你的启发。我知道那里有一些延迟加载图像脚本,但我自己创建了一个:https://github.com/dinbror/blazy,我认为它更容易使用,并且具有更多功能,比如水平延迟加载、根据大小的多服务图像、回调等。
我很乐意收到关于它的反馈。
我复制粘贴了你的 js,但它没有生效,但你的演示页面上的脚本却生效了!
在最后一行
它在这里:-
addEventListener(‘scroll’,processScroll);
}(this); ———————————> 这个没有生效
在你的演示页面中:-
addEventListener(‘scroll’,processScroll);
我还是个新手。对于我来说,你的大多数答案第一次都没有生效:/
遇到了同样的问题,你有没有找到解决方案?
我也是。
嗨,你是在“严格”模式下运行代码吗?
我遇到了同样的问题。我发现它在非严格模式下是可以的。
希望这能帮到你。
谢谢。
我安装了 4 个版本的 lazyload,这个特定的脚本取得了最佳的页面测试结果。
我有一个问题,如何延迟加载背景图像。我的网站上有很多背景图像。
抱歉,什么是延迟加载器?
我必须承认,我是一个网页开发者,并不认为延迟加载有什么特别酷的地方(参考 Harlowe Thrombey 的评论),原因是:它会导致页面拖动。如果图片在滚动时加载速度不够快,浏览器就会卡住,导致页面拖动,体验非常糟糕,令人沮丧。我宁愿在页面开始加载时多等几秒钟,然后能够流畅地滚动到页面底部,也不愿意开始滚动后每 300 像素就卡住。
我见过它被很好地运用,如果添加了特效并且没有拖动,效果看起来相当不错——客户似乎很喜欢它,并经常要求使用它。
我在第一次查看这篇文章中的参考链接时就注意到拖动问题……除了预加载(这会违背延迟加载的初衷)之外,有没有办法确保没有拖动?是慢速连接还是图片太大导致了这个问题?
顺便说一下,感谢你的辛勤工作,Chris!我认为这篇文章中的一些评论真的很没有必要,而且越界了——虽然我不是延迟加载的粉丝,但我经常参考你的文章,感谢你所有的工作。
直到你拥有一个因为图片而占用过多带宽的网站,你才会发现它有用。
嘿,img html 代码末尾的闭合标签 < / a > 是不是一个错误?
是的,这是一个错误,已修复,谢谢!
有没有人遇到过不需要 data-src 属性,并且适用于所有 img 标签的延迟加载解决方案?我有几个网站,里面有很多图片,但它们都使用 CMS,我不希望重新输入 5 年的图片,这些图片都是通过 WYSIWYG 内容输入的。
解析数据库中的图片标签。
那就懒一点吧 ;)
https://github.com/dinbror/blazy
你们中的一些人可能会发现这个解决方案很有趣。
http://codepen.io/Merri/pen/IiqEu
没有 data-src 属性,只是包装了 img 标签。它也不会在 IE9 及以下版本中进行延迟加载,因此你不会在 IE8 中遇到页面拖动,当执行 JS 时,页面拖动会停止所有内容。并且在 iPad 上也能正常工作。
我想在我的网站上所有 div 中应用延迟加载。我该怎么做?
这种技术对于内联图片非常有效,但它是否可以适应通过 CSS 加载的图片,或者,出于我个人好奇,是否可以适应第三方 JS 加载的图片?
如果能够将这种功能整合到 ResponsiveSlides 中,或者与它兼容,那就太好了。
或者,也许,与 Supersized 兼容,虽然它允许在 JSON 结构中定义图片(这对于 API 消费者来说很棒),但它会不必要地预加载图片,我认为。
效果不错。
谢谢!
它在 iPad 上也能正常工作——http://www.mr-box.com
我怎样才能在图片即将进入视野时加载图片?如果我想让图片在出现在视窗之前 200 像素加载,我可以将
rect.top >= 0
更改为rect.top >= 200
吗?谢谢。效果很好。
这只能用 png 吗?它能用 jpg 吗?我的图片是空白的。
我写了一个延迟加载器,可以应用于所有元素,代码量比这个少 80%。它加载速度也快得多,不会拖慢网站速度。
典型的“代码或它没有发生”案例。谈论这种神奇的代码,它只创造奇迹,并不能带来任何东西。
图片设置为 blank.gif 可能会不被 Google 索引,如何使用这种方法并使其对搜索引擎友好?有什么想法吗?谢谢!
您好
也许另一个解决方案
当 JavaScript 扫描图片时,它可以将 src 替换为 load gif,然后图片被触发,它将 load gif 替换为 title 属性中的 url(与第一个相同),可以吗?
对于基于 isotope/packery 的布局,它将延迟加载与具有不同纵横比的流体图片结合在一起,我看到除了应用内联 padding-bottom(由服务器上的 php 计算)之外,没有其他选择,就像在本主题中提到的那样。
https://stackoverflow.com/questions/23416880/lazy-loading-with-responsive-images-unknown-height/23417812#23417812
它工作正常,但应用内联 CSS 似乎是一种不好的做法。另一种方法是在 data 属性中放置此信息,然后在调用 packery/isotope 布局之前使用 JavaScript 应用内联 CSS。对此有什么想法吗?
有没有办法在不缩小图片并且不为每个图片标签放置 width 和 height 属性的情况下让它工作?
是的,有。
我写了一篇简短的文章,解释了如何操作:http://afroleft.com/lazy-loading-responsive-images/
太棒了,非常感谢!
我刚在我的网站上添加了这个,效果很好 :)
对不起
不要写 data-src=””
意思是不要查看图片
您好,
这段代码有一个小问题,就是定义了 “_has” 函数,但从未使用过。
谢谢,效果很好。
您好,
我想向您展示一个更新,使代码对搜索引擎友好。在 http://ivopetkov.com/b/lazy-load-responsive-images/ 中,您可以看到我保留了
src
属性,因为它应该保留(path/to/image.jpg),并且我添加了一个带有特殊值的srcset
,它可以防止它加载。该代码可以在 https://github.com/ivopetkov/responsively-lazy 中找到。这很酷,但我唯一的问题是内容会弹跳。换句话说,占位符图片没有以正确的大小呈现,然后原始图片被延迟加载,图片周围的内容就会四处移动。
有没有办法解决这个问题?我可以将 “lazy” 类限制在只出现在页面折叠位置以下的图片上,但我的页面是模板化的,所以这很难自动化。
Kick,几年前我写了一篇关于这个问题的文章 http://afroleft.com/lazy-loading-responsive-images/
希望对您有所帮助 :)
我使用了这段代码,它运行良好,但对于隐藏的图片不起作用,你能否提供一些关于如何为隐藏图片实现它的想法?
提前感谢。
为什么这段代码使用
el.parent
而不是el.parentNode
。el.parent
属性在我的所有尝试过演示页面的浏览器中(IE11、Firefox、Chrome、Edge)都未定义。因此,脚本从未使用过.replaceChild()
选项,这让我很奇怪它为什么会在那里。我并不是说我的版本更好,但它更简洁。我并不支持旧版浏览器,除了一个必须等到 jQuery 加载才能生效的回退。
有没有简单的 JavaScript 代码?阅读代码会占用我太多脑力和处理器资源。哈哈 :D
我写了一个非常简单的延迟加载脚本,它也使用 noscript 标签,以便无 JS 用户也能看到图片。我在尝试和测试不同的脚本后创建了它(但我没有 100% 喜欢任何一个),我决定将所有这些脚本的优点结合起来。在这里获取我的脚本,并告诉我你的想法:https://jsfiddle.net/nhed5ojy/3/
很棒的脚本,但我遇到一个问题,它会在每次滚动事件中用 data-src 替换图像。这意味着当你滚动经过它时,图像会反复替换。对于静态图像来说不明显,但如果放一个 gif,你就会发现这是一个大问题。对 loadImage() 函数进行一个小更新,将确保在进行切换之前图像未加载。
谢谢 Matt K,
这使得滚动变得更加流畅!
谢谢!但是,我有一个问题:如果图片处于绝对定位,它不起作用,这里有截图 http://joxi.ru/VrwogogCO4bdpr
在线页面的加载时间是关键,因为它最大限度地降低了页面加载时间。提高这方面的一种方法是使用延迟加载,它包括在页面加载后加载内容!在这个 DevCast 中,我们谈到了 DevMedia 的开发时间,它最近使用了这种技术,并在本视频中展示了为此所需的内容。
http://www.devmedia.com.br/adoramos-ajax/37919
你好,你能更新一下 background: url(); 吗?
我需要这个。
此致
:)
非常有用,感谢你提供的原生 JS 解决方案。
不过,这里有一个简单的问题。在 loadImage() 函数中创建一个新的 Image() 然后用它来替换标记中的
<img>
,就像提供的代码那样,和直接覆盖标记中<img>
的源代码(例如el.src = el.getAttribute('data-src');
)有什么区别吗?这个例子在
img
标签中有srcset=""
和sizes=""
时有效吗?我在此处看到了几个请求,要求使这个插件能够与背景图片一起使用,我也需要这个功能,所以我调整了你的插件并添加了这个功能。
不错!
您好,您有演示吗?
此致
是的!这里有一个。
https://css-tricks.cn/examples/LazyLoading/
一个问题,使用延迟加载,这些图片会在谷歌中被索引吗?
这对于来自目录的任意数量的图像如何工作?假设你使用的是 PHP 脚本来生成图像列表,例如... 到目前为止它对我来说还没有生效。
你好,感谢分享这样的代码片段 :-)
我经常使用另一种方法,可能对一些人来说很有趣:https://medium.com/@iliketoplay/lazy-loading-a-flexible-and-performant-approach-5a46b97ef60f
感谢您提供这篇很棒的文章。如果你们正在使用 React,我已经构建了一个组件,非常易于使用和集成。
在此处查看演示
https://react-simple-img.now.sh/
现在你不应该使用交叉观察者吗?我已经读到它比使用 getBoundingRect 进行手动计算要好得多。
非常有用,我通常会卡在那里。谢谢你。
这是我对我的网站进行的修改,这个修改使得你不需要添加 "lazy" 类,只需要添加 "data-src"。它还为背景图片 css 添加了 "data-background",而不是 src。
images.splice(i, i);
你不认为这里错了嗎?
您在每次迭代中都拼接了 'i' 个元素。
拼接在循环时不会改变索引吗?
终于在我的网站上实现了延迟加载。谢谢你,伙计!