判斷一個元素是否在視口內(nèi):
offsetTop-scroolTop-clientHeight<0乃坤,則圖片進入了可視區(qū)內(nèi)童漩。
進入視口后怎么讓圖片加載出來呢弄贿,使用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)站的正常使用蔚舀。
將頁面上的圖片的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.