Share

blog-header

Lazy Load and SEO Compatibility

Site performance is one of the main subjects for websites targeting high traffic performance. In such projects, it is necessary to avoid any elements that will slow down the page’s loading process. 

Lazy load is one of the most popular ways to optimize page load. Some benefits of well performed pages are:

1. Because the browser ignores loading unnecessarily off-screen contents, page loads faster.

2. Fast loading page means better user experience.

3. After loading fast, the page allows the user to reach information faster. That means lesser traffic.

4. Your website, crawled by Google bots with better traffic and loading results, will be more visible in search results and becomes more accessable.

Along with lazy load, there are several other ways to increase website performance. These ways are being covered by using CDNs, writing and loading codes more optimized, accurate image formats and loading fonts. You can check all these in Google’s fast load times article.

Various Ways

There are many ways to maintain SEO compatibility with lazy loading. I’ve gathered some of these below:

1- As of now, the lazy loading attribute to images is supported by all browsers. In addition, the same feature can be added to the <iframe> element (although, not all browsers supported it when I write these). That way, lazy loading will be well-performed without extra codes.

<img width="400" height="300" src="article.jpg" 
alt="..." loading="lazy">
<iframe loading="lazy">

Pre-specifying image width and height beforehand steps forward as a small but important factor. Mostly the browser doesn’t know the dimensions of an image until injecting it. However, with specific definitions that have been made inline, the browser creates the structure faster since it knows all sizes and dimensions. That means much more saving time during rendering. 

2- In default, videos are insinuated and loaded directly through browser. But they are called as embed videos as well. That will reduce off the encumbrance on the browser during loading the page. Similarly, you can add smaller images in video thumbs. 

3- One can determine the rendering process of the pages’ content via Intersection Observer API (Application Programming Interface). API allows you to determine when and how fast will be the rendering process of images, sections, divs and even menus.   

In this example below, the intersection observer calls its constructor and pass a callback function. The callback will be invoked when 100% of  the target is visible, specified by threshold as 1.0.

let options = {
root: document.querySelector('#scrollArea'),
rootMargin: '20px',
threshold: 1.0
}
let observer = new IntersectionObserver(callback, 
options);

Once the target is visible, one can use various events and classes. Furthermore, one can add lazy loading property to each one of the elements such as paragraphs, buttons, and images by using DOMContentLoaded. Hereby, it wont be necessary to deal with each element individually and will save time.  

In this example below, we simply said that when the browser detects that the target element has been obscured by the window dimensions, the API becomes activated, reaches the lazy images source, and removes the ‘lazy’ class. 

if ("IntersectionObserver" in window) {
 let lazyImageObserver = new IntersectionObserver(
function(entries, observer) {
 entries.forEach(function(entry) {
 if (entry.isIntersecting) {
 let lazyImage = entry.target;
 lazyImage.src = lazyImage.dataset.src;
 lazyImage.classList.remove("lazy");
 }
 });

4- If you are designing a page which a huge amount of content and title flow just like Twitter, you can provideintersection observerandcontinuous scroll features. To be able to do this, as I mentioned before, requires determining each texts loading time. Thus and so, the browser tries to download only one text and image of a single part. But in such a case, Google doesnt indexes the content below. 

5- With code splitting, you can slip your code into various bundles or components. You can make it clear in your code that the browser load or demand each one of them only when they are required. That way you will prevent the requirement of injecting a bunch of files, and scripts one at a time, and splitting them into multiple partitions instead. This method is especially handy when your project becomes very complex. 

Code splitting is also supported by many bundlers.

You can check Chrome Developer Team’s related article and code below to have a snapshot.

try { var scripts = [{{{scripts}}}], src, 
pendingScripts = [], firstScript = document.scripts[0]; 
//polyfil checks and loads here
 if (typeof IntersectionObserver === "undefined" || 
IntersectionObserver.toString().
indexOf("[native code]") === -1) { 
scripts.unshift(
"js/libs/polyfil/intersection-observer.js"
); 
} 
// Watch scripts load in IE 
function stateChange() {
// Execute as many scripts in order as we can 
var pendingScript; 
while (pendingScripts[0] && pendingScripts[0]
.readyState == 'loaded') { 
pendingScript = pendingScripts.shift(); 
// avoid future loading events from this script
// (eg, if src changes) 
pendingScript.onreadystatechange = null; 
// can't just appendChild
// old IE bug if element isn't closed 
firstScript.parentNode.insertBefore(pendingScript, 
firstScript); 
} 
console.log("scripts should be loaded now"); } 
// loop through our script urls 
while (src = scripts.shift()) { 
if ('async' in firstScript) { 
// modern browsers 
script = document.createElement('script'); 
script.async = true; 
script.src = src; document.body.appendChild(script); 
} else if (firstScript.readyState) { 
// IE<10 
// create a script and add it to our todo pile 
script = document.createElement('script'); 
pendingScripts.push(script); 
// listen for state changes 
script.onreadystatechange = stateChange; 
// must set src AFTER adding onreadystatechange
// else we’ll miss the loaded event for cached scripts 
script.src = src; 
} else { 
// fall back to defer 
document.write(
'<script src="' + src + '" defer></' + 'script>'
); 
} 
} 
} 
catch (error) { alert(error); 
} 

6- History APIallows you to manipulate the browser’s session history. Generally, the browser’s session history can be accessed by the DOM Window object. Different types of methods and properties let you navigate back and forth through the user’s history and manipulate the contents from there. That way, the page URL renews itself every necessary time without any refreshing.

While there are a bunch of methods, although the example below uses calling pushState(), similarly to setting window. location That way a history topic can be created and activated. Its advantage is injecting data with new history entries. That way the browse uses AJAX and gets the HTML that is required. 

var stateObj = { foo: "bar" }; 
history.pushState(stateObj, "page 2", "bar.html"); 

In addition to all these methods, you can use some plugins in CMS to increase the page performance which allows you to do almost nothing. While these plugins are very simple and user-friendly designed, there are also handicaps such as having an additional fee and being difficult when moving the site, as they can only support a single platform. 

author image

Volkan Levent Soylu

Jr. Frontend Developer

linkedin icon

Perfist Blog

Similar Articles

Other Articles