Sitecore Image Lazy Load Module

The package and code for this module can be found at: Github – aceanindita

The bLazy.js plugin – A lazyload image script can be used to enable lazyload on your site, to reduce initial page load times drastically, especially if your site is image heavy.

While you can directly integrate your site with the bLazy plugin, you will need to ensure that your images are not loaded on page load, for which you will need to transform your html accordingly. This can also bring with it experience editor compatibility concerns.

This module will make all your images rendered from Sitecore Image and Rich Text fields, lazy loaded automatically without you having to make ANY html updates at all.

For this, we are usign the following config which does 2 things

  • Processor added to mvc.renderRendering – to include and initialize the bLazy plugin
  • Processor added to renderField – to transform html for all images rendered from the Sitecore Image field and Rich Text field, to move the src url to a different attribute recognized by the plugin, and also add a selector to tell the plugin this html needs to be transformed to lazy load the image.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <mvc.renderRendering>
        <processor type="ImageLazyLoadModule.Pipelines.MVC.InsertbLazyInit, ImageLazyLoadModule"             patch:before="processor[@type='Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer, Sitecore.Mvc']" />
      </mvc.renderRendering>
      <renderField>
        <processor type="ImageLazyLoadModule.Pipelines.RenderField.ImageLazyLoad, ImageLazyLoadModule" />
      </renderField>
    </pipelines>
    <settings>
      <setting name="ImageLazyLoadModule.Offset" value="200" />
      <setting name="ImageLazyLoadModule.Selector" value="b-lazy" />
    </settings>
  </sitecore>
</configuration>

You can see 2 configurable settings above, which are used when the bLazy plugin is initialized.

  • The offset controls how early you want the elements to be loaded before they’re visible.
  • The selector is the class that will be added to the img tags dynamically, which will be used by the plugin to lazy load images.

The code for mvc.renderRendering for including the script and plugin initialization

using Sitecore.Configuration;
using Sitecore.Mvc.Pipelines.Response.RenderRendering;
using Sitecore.Mvc.Presentation;

namespace ImageLazyLoadModule.Pipelines.MVC
{
    public class InsertbLazyInit : RenderRenderingProcessor
    {
        public override void Process(RenderRenderingArgs args)
        {
            Renderer renderer = args.Rendering.Renderer;
            if (renderer == null)
                return;

            bool isLayout = renderer is ViewRenderer &&
                               ((ViewRenderer)renderer).Rendering.RenderingType == "Layout";

            if (isLayout)
            {
                args.Writer.Write("<script src=\"../../sitecore modules/Lazy Load/blazy.min.js\"></script>"
                                  + "<script>"
                                  + "var bLazy = new Blazy({ selector: '."
                                  + Settings.GetSetting("ImageLazyLoadModule.Selector", "b-lazy")
                                  + "', offset: " 
                                  + Settings.GetIntSetting("ImageLazyLoadModule.Offset", 200)
                                  + ", src: 'responsive-src'});"
                                  + "</script>");
            }
        }
    }
}

The code for renderField which will transform img tag html

using HtmlAgilityPack;
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.RenderField;
using System;

namespace ImageLazyLoadModule.Pipelines.RenderField
{
    public class ImageLazyLoad
    {
        public void Process(RenderFieldArgs args)
        {
            try
            {
                if (args == null)
                    return;

                // Trigger the code to transform the img tags only for rich text and image fields
                if (!(args.FieldTypeKey != "rich text" || args.FieldTypeKey != "image") || string.IsNullOrEmpty(args.FieldValue) ||
                     !Context.PageMode.IsNormal)
                    return;

                if (!string.IsNullOrWhiteSpace(args.Result?.FirstPart))
                {
                    HtmlDocument doc = new HtmlDocument { OptionWriteEmptyNodes = true };
                    doc.LoadHtml(args.Result.FirstPart);

                    if (doc.DocumentNode != null)
                    {
                        // Search for all img tags
                        HtmlNodeCollection imgTag = doc.DocumentNode.SelectNodes("//img");
                        if (imgTag == null || imgTag.Count == 0)
                            return;

                        foreach (HtmlNode node in imgTag)
                        {
                            if (node.Attributes["src"] != null && node.ParentNode != null)
                            {
                                string imgUrl = node.Attributes["src"].Value;
                                node.Attributes.Add("responsive-src", imgUrl);
                                node.Attributes["src"].Value = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
                                string currentClass = node.Attributes["class"] != null ? node.Attributes["class"].Value : "";
                                node.Attributes.Remove("class");
                                node.Attributes.Add("class", (string.IsNullOrWhiteSpace(currentClass) ? "" : currentClass + " ")
                                    + Settings.GetSetting("ImageLazyLoadModule.Selector", "b-lazy"));
                                node.Attributes.Remove("width");
                                node.Attributes.Remove("height");
                            }
                        }

                        args.Result.FirstPart = doc.DocumentNode.OuterHtml;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error("Error in ImageLazyLoadModule.ImageLazyLoad:" + ex.Message, ex);
            }
        }
    }
}

You can also choose to add image transitions using css as is specified in the bLazy Documentation

.b-lazy {
-webkit-transition: opacity 500ms ease-in-out;
-moz-transition: opacity 500ms ease-in-out;
-o-transition: opacity 500ms ease-in-out;
transition: opacity 500ms ease-in-out;
max-width: 100%;
opacity: 0;
}
.b-lazy.b-loaded {
opacity: 1;
}

Here’s a very simple example of this module in use (Rich text field example)

We have a simple content item, where an image has been embedded in the rich text field from the media library

The view rendering code, simply outputs the rich text field using the Sitecore renderer (observe there are no additional classes added either)

Now for the output! When you load up the page with this ViewRendering, you see the following

Observe that the selector ‘b-lazy’ was added dynamically by our RenderField customization, and it was further picked up by the bLazy plugin and transformed successfully, evident by the ‘b-loaded’ class.

Now to see the html loaded on page load

Here you can see that the bLazy script and its initialization was added dynamically by our mvc.renderRendering pipeline update, and the img tag on page load, has a different src! This src is the base64 code of a pixel. The actual image source has been moved to a different attribute (responsive-src) which is recognized by the plugin (supplied during plugin initialization)

Hence proved.

The package and code for this module can be found at: Github – aceanindita

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s