判断一个元素是否在视口内:
offsetTop-scroolTop-clientHeight<0,则图片进入了可视区内。
进入视口后怎么让图片加载出来呢,使用data-src的方式存储图片地址,再用dom方法修改src。H5中有一个新的是dataset。
如何实现不下载图片,但能出现图片
懒加载,也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式,在长网页上使用延迟加载将使网页加载更快。用户没滚动到它们之前,可视区域外的图像不会加载。在某些情况下,它还可以帮助减少服务器负载。适用图片很多,页面很长的电商网站场景中。
为什么要用懒加载
能提升用户的体验。如果长页面上所有的图片都需要加载,由于图片数目较大,等待时间很长,用户难免会心生抱怨,这就严重影响用户体验。
减少无效资源的加载,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。
防止并发加载的资源过多,阻塞js的加载,影响网站的正常使用。
将页面上的图片的src属性设为空字符串,而图片的真实路径则设置在data-original属性中。
监听scroll事件,在scroll事件的回调中,判断懒加载的图片是否进入可视区域。如果图片在可视区内,将图片的src属性设置为data-original的值,这样就可以实现延迟加载。
.image-item {
display: block;
margin-bottom: 50px;
height: 200px; //一定记得设置图片高度
}
document.addEventListener("scroll",lazyload)
var clientHeight=document.documentElement.clientHeight; //获取可视区高度
function lazyload(){
var imgs = document.querySelectorAll('img[lazyload]')
Array.prototype.forEach.call(imgs,(item,index)=>{
//用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
var rect = item.getBoundingClientRect();
if(rect.top
item.src=item.dataset.original
item.removeAttribute("lazyload") //移除属性,下次不再遍历
}
})
}
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.
loading="lazy" alt="..."/>
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
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:
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.
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:
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.