圖片懶加載

判斷一個元素是否在視口內(nèi):

offsetTop-scroolTop-clientHeight<0乃坤,則圖片進入了可視區(qū)內(nèi)童漩。

offsetTop-scroolTop-clientHeight<0


document.documentElement.clientHeight 可視區(qū)域

進入視口后怎么讓圖片加載出來呢弄贿,使用data-src的方式存儲圖片地址,再用dom方法修改src矫膨。H5中有一個新的是dataset差凹。

如何實現(xiàn)不下載圖片,但能出現(xiàn)圖片


懶加載侧馅,也叫延遲加載危尿,指的是在長網(wǎng)頁中延遲加載圖像,是一種很好優(yōu)化網(wǎng)頁性能的方式馁痴,在長網(wǎng)頁上使用延遲加載將使網(wǎng)頁加載更快谊娇。用戶沒滾動到它們之前,可視區(qū)域外的圖像不會加載罗晕。在某些情況下济欢,它還可以幫助減少服務器負載。適用圖片很多小渊,頁面很長的電商網(wǎng)站場景中法褥。


為什么要用懶加載

能提升用戶的體驗。如果長頁面上所有的圖片都需要加載酬屉,由于圖片數(shù)目較大半等,等待時間很長,用戶難免會心生抱怨,這就嚴重影響用戶體驗酱鸭。

減少無效資源的加載,這樣能明顯減少了服務器的壓力和流量垛吗,也能夠減小瀏覽器的負擔凹髓。

防止并發(fā)加載的資源過多,阻塞js的加載怯屉,影響網(wǎng)站的正常使用蔚舀。



getBoundingClientRect()

將頁面上的圖片的src屬性設為空字符串,而圖片的真實路徑則設置在data-original屬性中锨络。

監(jiān)聽scroll事件赌躺,在scroll事件的回調(diào)中,判斷懶加載的圖片是否進入可視區(qū)域羡儿。如果圖片在可視區(qū)內(nèi)礼患,將圖片的src屬性設置為data-original的值,這樣就可以實現(xiàn)延遲加載掠归。

<html lang="en">

<head>

? ? <meta charset="UTF-8">

? ? <title>Lazyload</title>

? ? <style>

????.image-item {

? ? ????display: block;

? ? ????margin-bottom: 50px;

? ? ????height: 200px; //一定記得設置圖片高度

????}

? ? </style>

</head>

<body>

<img? class="image"? src="images/1.png"/>

<img class="image" src="images/2.png"/>

<img? class="image" src="images/3.png"/>

<img src="" class="image" lazyload="true"? data-original="images/4.png"/>

<img src="" class="image" lazyload="true"? data-original="images/5.png"/>

<img src="" class="image" lazyload="true"? data-original="images/6.png"/>

<img src="" class="image" lazyload="true"? data-original="images/7.png"/>

<img src="" class="image" lazyload="true"? data-original="images/8.png"/>

<img src="" class="image" lazyload="true"? data-original="images/9.png"/>

<script>

document.addEventListener("scroll"缅叠,lazyload)


var clientHeight=document.documentElement.clientHeight; //獲取可視區(qū)高度

function lazyload(){

????var imgs = document.querySelectorAll('img[lazyload]')

????Array.prototype.forEach.call(imgs,(item,index)=>{

? ? ????//用于獲得頁面中某個元素的左,上虏冻,右和下分別相對瀏覽器視窗的位置

????????var rect = item.getBoundingClientRect();

????????if(rect.top<clientHeight?&&?rect.bottom>=0?){

? ? ? ????????item.src=item.dataset.original

? ? ? ????????item.removeAttribute("lazyload") //移除屬性肤粱,下次不再遍歷

????????}

????})

}

</script>

</body>

</html>

reference:?https://css-tricks.com/the-complete-guide-to-lazy-loading-images/

Lazy loading images means loading images on websites asynchronously — that is, after the above-the-fold content is fully loaded, or even conditionally, only when they appear in the browser’s viewport. This means that if users don’t scroll all the way down, images placed at the bottom of the page won’t even be loaded.

Since most lazy loading solutions work by loading images only if the user has scrolled to the location where images would be visible inside the viewport, those images will never be loaded if users never get to that point. This means considerable savings in bandwidth, for which most users, especially those accessing the Web on mobile devices and slow-connections, will be thanking you.


1. loading?attribute

loading?can take any of these three values:

lazy: works great for lazy loading

eager: instructs the browser to load the specified content right away

auto: leaves the option to lazy load or not to lazy load up to the browser.

<img src="myimage.jpg" loading="lazy"?alt="..."/>

<iframe src="content.html" loading="lazy"></iframe>

The?loading?attribute gives us the option to delay off-screen images and iframes until users scroll to their location on the page.?

This method has no rivals: it has zero overhead, it’s clean and simple. However, although at the time of writing most major browsers have?good support for the?loading?attribute, not all browsers are on board yet.


2. omit src attr

<img src="/path/to/some/image.jpg"/>

Step one is to prevent the image load up front. The browser uses the?src?attribute of the tag to trigger the image load. It doesn’t matter if it is the first or the 1,000th image in your HTML. If the browser gets the?src?attribute, it will trigger the image to be downloaded, regardless of whether it is in or out of current view.

To defer the load, put the image URL in an attribute other than?src. Let’s say we specify the image URL in the?data-src?attribute of the image tag. Now that?src?is empty and the browser won’t trigger the image load:

<img data-src="https://ik.imagekit.io/demo/default-image.jpg"/>

Now that we’re preventing the image from loading, we need to tell the browser when to load it. Otherwise, it will never happen. For this, we check that as soon as the image (i.e. its placeholder) enters the viewport, we trigger the load.

There are two ways to check when an image enters the viewport.?

Method 1: Trigger the image load using Javascript events

This technique uses event listeners on the?scroll,?resize?and?orientationChange?events in the browser.?

We can use these three events to recognize a change in the screen and determine the number of images that become visible on the screen and trigger them to load accordingly.

When any of these events occur, we find all the images on the page that are deferred and, from these images, we check which ones are currently in the viewport. This is done using an image’s top offset, the current document top position, and window height. If an image has entered the viewport, we pick the URL from the?data-src?attribute and move it to the?src?attribute and the image will load as a result.

Note that we will ask JavaScript to select images that contain a?lazy?class. Once the image has loaded, we’ll remove the class because it no longer needs to trigger an event. And, once all the images are loaded, we remove the event listeners as well.

When we scroll, the scroll event triggers multiple times rapidly. Thus, for performance, we are adding a small timeout to our script that throttles the lazy loading function execution so it doesn’t block other tasks running in the same thread in the browser.

Here is a working example of this approach.

Note that the first three images in this example are loaded up front. The URL is present directly in the?src?attribute instead of the?data-src?attribute. This is essential for a good user experience. Since these images are at the top of the page, they should be made visible as soon as possible. There’s no need to wait for JavaScript to load them.

document.addEventListener("DOMContentLoaded",function() {

var lazyloadImages=document.querySelectorAll("img.lazy");

var lazyloadThrottleTimeout;

function lazyload() {

????if(lazyloadThrottleTimeout) {

????clearTimeout(lazyloadThrottleTimeout);

}

lazyloadThrottleTimeout=setTimeout(function() {

????var scrollTop=window.pageYOffset;

????lazyloadImages.forEach(function(img) {

????????if(img.offsetTop<(window.innerHeight+scrollTop)) {

????????????img.src=img.dataset.src;

????????????img.classList.remove('lazy');

????}

});

if(lazyloadImages.length==0) {

????document.removeEventListener("scroll",lazyload);

????window.removeEventListener("resize",lazyload);

????window.removeEventListener("orientationChange",lazyload);

}

},20);

}

document.addEventListener("scroll",lazyload);

window.addEventListener("resize",lazyload);

window.addEventListener("orientationChange",lazyload);

});

Method 2: Trigger the image load using the Intersection Observer API

The?Intersection Observer API?is relatively new. It makes it simple to detect when an element enters the viewport and take an action when it does. In the previous method, we had to bind events, keep performance in mind and implement a way to calculate if the element was in the viewport or not. The Intersection Observer API removes all that overhead by avoiding the math and delivering great performance out of the box.

Below is an example using the API to lazy load images. We attach the observer on all the images to be lazy loaded. Once the API detects that the element has entered the viewport, using the?isIntersecting?property, we pick the URL from the?data-src?attribute and move it to the?src?attribute for the browser to trigger the image load. Once this is done, we remove the?lazy?class from the image and also remove the observer from that image.

document.addEventListener("DOMContentLoaded",function() {

????var lazyloadImages;

????if("IntersectionObserver" in window) {

????????lazyloadImages=document.querySelectorAll(".lazy");

????????var imageObserver=new IntersectionObserver(function(entries,observer) {

????????????entries.forEach(function(entry) {

????????????????if(entry.isIntersecting) {

????????????????????var image=entry.target;

????????????????????image.src=image.dataset.src;

????????????????????image.classList.remove("lazy");

????????????????????imageObserver.unobserve(image);

????????????????}});

????????});

????????lazyloadImages.forEach(function(image) {

????????????imageObserver.observe(image);

????????});

}else{

????var lazyloadThrottleTimeout;

????lazyloadImages=document.querySelectorAll(".lazy");

????function lazyload() {

????????if(lazyloadThrottleTimeout) {

????????????clearTimeout(lazyloadThrottleTimeout);

????????}

????????lazyloadThrottleTimeout=setTimeout(function() {

????????????var scrollTop=window.pageYOffset;

????????????lazyloadImages.forEach(function(img) {

????????????????if(img.offsetTop<(window.innerHeight+scrollTop)) {

????????????????????img.src=img.dataset.src;

????????????????????img.classList.remove('lazy');

????????????????}

????????});

if(lazyloadImages.length==0) {

????document.removeEventListener("scroll",lazyload);

????window.removeEventListener("resize",lazyload);

????window.removeEventListener("orientationChange",lazyload);

}

},20);

}

document.addEventListener("scroll",lazyload);

window.addEventListener("resize",lazyload);

window.addEventListener("orientationChange",lazyload);

}

})

If you compare the image loading times for the two methods (event listeners vs. Intersection Observer), you will find that images load much faster using the Intersection Observer API and that the action is triggered quicker as well— and yet the site doesn’t appear sluggish at all, even in the process of scrolling. In the method involving event listeners, we had to add a timeout to make it performant, which has a slightly negative impact on the user experience as the image load is triggered with a slight delay.

However, like any new feature, the support for Intersection Observer API is not available across all browsers.


CSS Background Images

CSS background images are not as straightforward as the image tag. To load them, the browser needs to build the?DOM?tree as well as the?CSSOM?tree to decide if the CSS style applies to a DOM node in the current document. If the CSS rule specifying the background image does not apply to an element in the document, then the browser does not load the background image. If the CSS rule is applicable to an element in the current document, then the browser loads the image.

This may seem complex at first, but this same behavior forms the basis of the technique for lazy loading background images. Simply put, we trick the browser into not applying the?background-image?CSS property to an element, till that element comes into the viewport.

Here is a working example that lazy loads a CSS background image.

One thing to note here is that the JavaScript code for lazy loading is still the same. We are still using the Intersection Observer API method with a fallback to the event listeners. The “trick” lies in the CSS.

We have an element with ID?bg-image?that has a?background-image. However, when we add the?lazy?class to the element, we can override the?background-image?property by setting the value of it to?none?in the CSS.

#bg-image.lazy{

????background-image:none;

????background-color:#F1F1FA;

}

#bg-image{

????background-image:url("https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-600,h-400");

????max-width:600px;

????height:400px;

}

Since an element with an ID and a class has higher specificity in CSS than an ID alone, the browser applies the property?background-image: none?to the element initially. When we scroll down, the Intersection Observer API (or event listeners, depending on which method you choose) detects that the image is in the viewport, it removes the?lazy?class from the element. This changes the applicable CSS and applies the actual?background-image?property to the element, triggering the load of the background image.


Tip 1. Use the Right Placeholder

A placeholder is what appears in the container until the actual image is loaded. Normally, we see developers using a solid color placeholder for images or a single image as a placeholder for all images.

The examples we’ve looked at so far have used a similar approach: a box with a solid light gray background. However, we can do better to provide a more pleasing user experience. Below are some two examples of using better placeholders for our images.

Dominant Color Placeholder

Instead of using a fixed color for the image placeholder, we find the dominant color from the original image and use that as a placeholder. This technique has been used for quite some time by Google in its image search results as well as by Pinterest in its grid design.

This might look complex to achieve, but?Manuel Wieser has an elegant solution?to accomplishing this by scaling down the image to down to a 1×1 pixel and then scale it up to the size of the placeholder—a very rough approximation but a simple, no-fuss way to get a single dominant color. Using?ImageKit, the dominant color placeholder can be obtained using a chained transform in ImageKit as shown below.

<!-- Original image at 400x300 -->

<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300"alt="original image"/>

<!-- Dominant color image with same dimensions --><imgsrc="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-1,h-1:w-400,h-300"alt="dominant color placeholder"/>

The placeholder image is just 661 bytes in size compared to the original image that is 12700 bytes—19x smaller. And it provides a nicer transition experience from placeholder to the actual image.

Low Quality Image Placeholder (LQIP)

We can extend the above idea of using a dominant color placeholder further. Instead of using a single color, we use a very low-quality, blurred version of the original image as the placeholder. Not only does it look good, but it also gives the user some idea about what the actual image looks like and the perception that the image load is in progress. This is great for improving the perceived loading experience. This technique has been utilized by the likes of Facebook and Medium.

LQIP image URL example using ImageKit:

<!-- Original image at 400x300 -->

<img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300"alt="original image"/>

<!-- Low quality image placeholder with same dimensions --><img src="https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300,bl-30,q-50"alt="dominant color placeholder"/>

The LQIP is 1300 bytes in size, still almost?10x smaller?than the original image and a significant improvement in terms of visual experience over any other placeholder technique.

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市厨相,隨后出現(xiàn)的幾起案子领曼,更是在濱河造成了極大的恐慌,老刑警劉巖蛮穿,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庶骄,死亡現(xiàn)場離奇詭異,居然都是意外死亡践磅,警方通過查閱死者的電腦和手機瓢姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來音诈,“玉大人幻碱,你說我怎么就攤上這事∠附Γ” “怎么了褥傍?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喇聊。 經(jīng)常有香客問我恍风,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任朋贬,我火速辦了婚禮凯楔,結果婚禮上,老公的妹妹穿的比我還像新娘锦募。我一直安慰自己摆屯,他們只是感情好,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布糠亩。 她就那樣靜靜地躺著虐骑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赎线。 梳的紋絲不亂的頭發(fā)上廷没,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音垂寥,去河邊找鬼颠黎。 笑死,一個胖子當著我的面吹牛滞项,可吹牛的內(nèi)容都是我干的盏缤。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼蓖扑,長吁一口氣:“原來是場噩夢啊……” “哼唉铜!你這毒婦竟也來了?” 一聲冷哼從身側響起律杠,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤潭流,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柜去,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灰嫉,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年嗓奢,在試婚紗的時候發(fā)現(xiàn)自己被綠了讼撒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡股耽,死狀恐怖根盒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情物蝙,我是刑警寧澤炎滞,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站诬乞,受9級特大地震影響册赛,放射性物質(zhì)發(fā)生泄漏钠导。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一森瘪、第九天 我趴在偏房一處隱蔽的房頂上張望牡属。 院中可真熱鬧,春花似錦扼睬、人聲如沸逮栅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞳浦,卻和暖如春担映,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背叫潦。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工蝇完, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人矗蕊。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓短蜕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親傻咖。 傳聞我的和親對象是個殘疾皇子朋魔,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容