Lazyloading
How to Lazyload Everything!
Getting Started
Make sure that lazysizes.js has been added to your Resources Snippet
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js" integrity="sha512-q583ppKrCRc7N5O0n2nzUiJ+suUv7Et1JGels4bXOaMFQcamPk9HjdUknZuuFjBNs7tsMuadge5k9RzdmO+1GQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Lazysizes Unveilhooks Extension
The unveilhooks plugin extends lazySizes to also unveil / lazyload scripts/widgets, background images, styles and video/audio elements.
Please Note: This extension code has already been added to the bottom of the master.js on newer templates.
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/plugins/unveilhooks/ls.unveilhooks.min.js" integrity="sha512-hQ7LIAYhD17CZh6bDzdQI7NThUHmZGcAbGDfCWHO/sOEPRAdlkQFg4gTsKhWWbI1PMUvjD7JjA+5x3pH23Bnyg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
CSS (optional)
Add an animation to fade in image after lazyloaded
.lazyload, .lazyloading { opacity: 0; }
.lazyloaded { opacity: 1; transition: opacity 300ms; }
How to Use LazySizes
LazySizes is the ultimate and lightweight lazyLoader which lazy loads images (including responsive images (picture/srcset)), iframes and scripts.
Simply add class="lazyload"
and change all src to data-src
for all images and iframes below the fold.
Make sure to lazyload every image and iframe below the fold!
Images
<img class="lazyload" data-src="/images/your-image.jpg" alt="Your Image">
iFrames
This can be used on any iframe (videos, maps, widgets, etc.)
<iframe class="lazyload" data-src="https://www.youtube.com/embed/NpEaa2P7qZI"></iframe>
Background Images
Add class="lazyload"
and data-bg="/images/image-name.jpg"
to the element you want the background image to appear.
** Remove background-image url from CSS.
<section class="lazyload" data-bg="/images/image-name.jpg">
<!-- [ content goes here ] -->
</section>
Scripts/Widgets
<div class="lazyload" data-script="/js/script-name.js">
<!-- [ content can go here ] -->
</div>
CSS
<div class="lazyload" data-link="/css/my-style.css">
<!-- [ content can go here ] -->
</div>
CSS & Scripts Combined
<div class="lazyload" data-script="/js/script-name.js" data-link="/css/my-style.css">
<!-- [ content can go here ] -->
</div>
Blogs
Lazyload featured images & iframes on blogs
{% if post.featuredImageUrl contains 'youtu' %}
<div class="video-wrapper">
<iframe class="lazyload" title="{{ post.title }}" data-src="{{ post.featuredImageUrl | replace: 'youtu.be/', 'youtube.com/embed/' | replace: 'watch?v=', 'embed/' }}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<span class="sr-only">Video</span>
</div>
{% elsif post.featuredImageUrl contains '.jpg' or post.featuredImageUrl contains '.png' or post.featuredImageUrl contains '.gif' or post.featuredImageUrl contains '.jpeg' %}
<div class="post-image">
<img class="lazyload" data-src="{{ post.featuredImageUrl }}" alt="{{ post.title }}" width="100%">
</div>
{% endif %}
Vcard Images
Hidden Vcard images may still show up on PageSpeed Insights even if lazyloaded, make sure to change it from <img>
to <object>
instead:
<object class="photo" itemprop="image" data="/images/social-sharing.jpg" type="image/jpg">social sharing</object>
View Full lazySizes Guide >
Image Optimization
Alway optimize ALL of your images! This even includes FB Offer Images & social sharing images.
Resizing Your Images
Make sure to save the image as close as possible to the same size that it will be displayed on your site. Example: if your image will be 900px wide, save your image at 900px wide.
Full-width Background/Banner images are typically saved at 2000px. Please also create a cropped mobile version of background images at 500px wide.
Compress Your Images
There are multiple ways to reduce your image file sizes:
If you have Photoshop, make sure to use "Save for Web". You can find it in the upper menu under File > Export > Save for Web (Legacy) or use the keyboard shortcut option + shift + command + s
If you don't have photoshop, there are many online image compressors available online. Here is one below:
Online Image Compressor >
Large Images (above the fold)
Create Mobile versions of banner images at 500px wide and use CSS to swap the image on moble devices:
@media (max-width: 500px){
#home-banner { background-image: url('/images/home-banner-mobile.jpg');}
}
Google PageSpeed Insights
How to Make Sense of it all
More Info Coming Soon!
Resources Snippet
How to Optimize Your Resources Snippet
Preconnect & DNS Prefetch
Make sure that to add a preconnect for fonts. This can be used for Google Font or Adobe Font. Add a dns-prefetch to your CDN
Google Fonts
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
Adobe Fonts
<link rel="preconnect" href="https://use.typekit.net" crossorigin>
<link rel="preconnect" href="https://p.typekit.net" crossorigin>
<link rel="preload" href="https://p.typekit.net" crossorigin>
CDN
<link rel="dns-prefetch" href="https://cdnjs.cloudflare.com" crossorigin>
Fonts
Make sure to only load the font and it's specific weights that the site is actually using.
Example of too many font weights (don't do this!):
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
Your font url should only contain what you need!
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
Animations
Make sure that the animation.css only loads on mobile by adding media="screen and (min-width: 992px)"
<link rel="stylesheet" href="/css/animate.css" media="screen and (min-width: 992px)">
Lazy Animations
Sometimes animations are called "lazy". This does not affect site speed.
"Lazy animations" is just another way to refer to scroll-triggered animations where the animations don't play until the user scrolls down.
Learn More About Lazy Animations >
Scripts
Defer every script tag (except for jquery)
Please Note: Deferring jQuery will break Nesthub forms!
Use the same CDN for all external Script files
The example below is using https://cdnjs.cloudflare.com
Search for scripts on cdnjs >
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha512-+NqPlbbtM1QqiK8ZAo4Yrj2c4lNQoGv8P79DPtKzj++l5jnN39rHA/xsqn8zE9l0uSoxaCdrOgFs6yjyfbBxSg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js" integrity="sha512-i9cEfJwUwViEPFKdC1enz4ZRGBj8YQo6QByFTF92YXHi7waCqyexvRD75S5NVTsSiTv7rKWqG9Y5eFxmRsOn0A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery.scrollfire/1.4.0/jquery.scrollfire.min.js"></script>
<script defer src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<script defer src="https://kit.fontawesome.com/8e7537a24b.js" crossorigin="anonymous"></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.0/lazysizes.min.js"></script>
<script defer src="https://www.google.com/recaptcha/api.js?onload=onIonRecaptchaLoad&render=explicit"></script>
<script defer src="/js/master-v3.js?v2"></script>
Lazyload LiveChat
Add the Javascript below and then add class="lazy-chat"
to the body tag of any template (or specific page) you need the chat to load
Make sure to update the license number in the Javascript to match the client's LiveChat license ID
Javascript
Standard Version
// Load Chat on Scroll - Make sure to update Lazy Chat ID code in JS with the client's LiveChat ID
$('.lazy-chat:not(.chat-loaded)').scrollfire({
offset: 0,
topOffset: 0,
bottomOffset: -500,
onScroll: function (elm, distance) {
if ($('.chat-loaded').length < 1) {
window.__lc = window.__lc || {};
window.__lc.license = 11083912; // <--- Update ID Here
// window.__lc.chat_between_groups = false; <--- add for Homeriver only
(function () {
var lc = document.createElement('script');
lc.type = 'text/javascript';
lc.async = true;
lc.src = (
'https:' == document.location.protocol
? 'https://'
: 'http://'
) + 'cdn.livechatinc.com/tracking.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(lc, s);
})();
$(elm).addClass("chat-loaded");
}
}
});
Hidden Chat on Mobile Version
// Lazy chat - no mobile
$(document).ready(function() {
var $window = $(window);
function checkWidth() {
var windowsize = $window.width();
if (windowsize > 500) {
// Load Chat on Scroll - Make sure to update Lazy Chat ID code in JS with the client's LiveChat ID
$('.lazy-chat:not(.chat-loaded)').scrollfire({
offset: 0,
topOffset: 0,
bottomOffset: -500,
onScroll: function (elm, distance) {
if ($('.chat-loaded').length < 1) {
window.__lc = window.__lc || {};
window.__lc.license = 11083912; // <--- Update ID Here
// window.__lc.chat_between_groups = false; <--- add for Homeriver only
(function () {
var lc = document.createElement('script');
lc.type = 'text/javascript';
lc.async = true;
lc.src = (
'https:' == document.location.protocol
? 'https://'
: 'http://'
) + 'cdn.livechatinc.com/tracking.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(lc, s);
})();
$(elm).addClass("chat-loaded");
}
}
});
}
}
// Execute on load
checkWidth();
// Bind event listener
$(window).resize(checkWidth);
});
Lazyload Reputation Widgets
This can be done easily by using LazySizes!
Learn more about LazySizes >
Grade.Us
Remove all separate Grade.Us scripts, insert data-script="//platform.grade.us/widgets.js"
and add class="lazyload"
<div class="reviewmgr-stream lazyload" data-script="//platform.grade.us/widgets.js" data-include-empty="false" data-last-initial="true" data-review-limit="3" data-url="https://reviews.nesthub.com/testing-pm/"></div>
Reputation
This can be done basically the same way as above.
Remove all separate Reputation scripts, insert data-script="https://widgets.reputation.com/src/client/widgets/widgets.js"
and add class="lazyload"
to the widget code that was copied from Reputation.com
FRS
If there is an FRS widget on the page, FRS will automatically load. If you have an FRS widget below the fold (example: properties widget on Home Page), add class "lazy-frs" to the section containing the FRS widget to prevent FRS from
loading until you scroll to that section.
Javascript
// Replace FRS API Script
function loadFrs() {
(function(d, s, id, k) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//www.freerentalsite.com/widgets/v2/?apiKey=" + ((k) ? encodeURIComponent(k) : '');
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'frs-jssdk', null));
};
// Only Load FRS if FRS Widget is on Page or if class lazy-frs is present
if ($('[data-frs]').length > 0 && $('.lazy-frs').length == 0) {
loadFrs();
};
// Trigger FRS on Scroll - add class lazy-frs to FRS widget containers on Home Page
$('.lazy-frs:not(.frs-loaded)').scrollfire(
{
offset: 0,
topOffset: 0,
bottomOffset: -500,
onScroll: function (elm, distance) {
if ($('.frs-loaded').length < 1) {
loadFrs();
$(elm).addClass("frs-loaded")
}
}
}
);