drupal lazyload images plugin or implementation?
Asked Answered
U

2

5

Is there any solid drupal plugin to lazyload images or has anybody implemented this?

Ideally, I would like to apply this only to a certain content type and use a plugin rather than having to code a lot / manually replace all individual nodes with references to images.

Most plugin search results are quite old or have limited documentation and litle proof of concept. I found only one interesting question here Lazy load making pages freeze/load very slow on IE? which is refering to justlazy, anybody implemented this or can recommend something please?

FYI - I already tried https://www.drupal.org/project/lazyloader but didn't seem to have any effect / couldn't make it work. I have inserted images in nodes via CKEditor. I understand that module relies on drupal image module, perhaps thats why it didn't work, i just hoped there is a plugin that replaces any normal image references with lazy load to eliminate custom setups.

Upward answered 7/4, 2018 at 19:38 Comment(0)
P
6

Creating your own module might be the easiest route though. That's what I did.

In my custom module I used bLazy, a lightweight lazy loading and multi-serving image script.

The module is quite straight-forward, I'll walk you through it:

In Drupal 7, theme_image() is responsible for outputting the <img ... /> markup for all the images rendered programmatically. That includes field images and any manual usage of theme('image', $variables).

For example;

<?php print theme('image', array('path' => $logo, 'alt' => t('Home'))); ?>

So first, you need to override the theme_image() function via hook_theme_registry_alter(), because we want to change some of the attributes of the IMG tag based on the default requirements of the bLazy script.

<?php
/**
 * Implements hook_theme_registry_alter().
 */
function CUSTOMMODULE_theme_registry_alter(&$theme_registry) {
  if (isset($theme_registry['image'])) {
    $theme_registry['image']['function'] = 'theme_CUSTOMMODULE_image';
  }
}

Then, alter the output of <img /> markup in that new theme_CUSTOMMODULE_image() function. Compare the following with theme_image() theming function:

<?php
/**
 * Overrides theme_image().
 */
function theme_CUSTOMMODULE_image($variables) {
  // Skip Blazy rendering if variables contain `.no-b-lazy` CSS class name.
  if (!empty($variables['attributes']['class']) && in_array('no-b-lazy', $variables['attributes']['class'])) {
    return theme_image($variables);
  }
  else {
    $attributes = $variables['attributes'];
    $attributes['src'] = file_create_url(drupal_get_path('module', 'CUSTOMMODULE') . '/assets/clear.gif');
    $attributes['data-src'] = file_create_url($variables['path']);
    $attributes['class'][] = 'b-lazy';
    foreach (array(
      'width',
      'height',
      'alt',
      'title',
    ) as $key) {
      if (isset($variables[$key])) {
        $attributes[$key] = $variables[$key];
      }
    }
    return '<img' . drupal_attributes($attributes) . ' />';
  }
}

I used a 1x1 pixel transparent GIF image as the placeholder image as the src attribute value, and the original image path as the data-src value. Lastly, added .b-lazy class name as the default selector.

Only remaining piece is loading the bLazy library and a simple script to load bLazy on every page, or on every theme page (non-admin).

(function ($) {
  Drupal.behaviors.CUSTOMMODULE = {
    attach: function (context, settings) {
      // @see http://dinbror.dk/blog/blazy/?ref=example-page#Options
      var options = {};
      var bLazy = new Blazy(options);
    }
  };
}(jQuery));

Within the same module, I implemented a hook_page_build() hook to attach those 2 javascript files. This way everything would be in one place.

I recommend reading the official tutorial for Adding JavaScript to your theme or module to find most suitable method for your project.

Once the module is enabled all the images passed through theme_image() would be lazy-loaded.

ADDED:

For the images added directly in .tpl.php templates, or the ones added via CKEditor in node add/edit forms, their markup should follow the same pattern as defined in the custom module, otherwise they won't lazy-load.

To make this happen I can think of two ways:

  1. Manually alter each image markup to meet bLazy's defaults. i.e.
<img src="low-res-placeholder.jpg" data-src="original-image.jpg" class="b-lazy" />
  1. Ignore everything above and use bLazy with following options to lazy load every single image on the site:
var options = {
  selector: "img",
  src: "src",
};
var bLazy = new Blazy(options);

I think both options have their pros and cons. However I think the first option is much safer and more stable over the second. Enabling lazy-load on all images may cause unexpected problems depending on site configuration.

Check out bLazy's available options. You may need to investigate further for what suits your project better.

Hope this helps.

EDIT (April 25, 2018):

I contributed my solution to the Drupal community as a module:
https://www.drupal.org/project/lazy

(I'll be adding a D8 port soon as well)

Procurable answered 8/4, 2018 at 20:21 Comment(15)
Wow thanks for sharing and yes in context of using ckeditor, allthough I would have thought it should be possible independently of that to apply it via a custom module, that will replace those IMG tags and lazyload them within the nodes, Meaning not necessarily preprocess but post?!?Upward
I need to do some more reading but think to have seen it mentioned that avoiding jQuery would be better? I'll definitely review yours tomorrow to see if I can make it work, would be good to know how to apply/limit it also only to certain content type.Upward
Make sure to read bLazy documentation too. How to use bLazy (lazy load images) If you’re using jQuery (or simliar) do it in document.readyProcurable
Additionally you may consider creating a text-format plugin. I just replied to another similar question for D8: drupal.stackexchange.com/a/259444/63081Procurable
Great thanks @Procurable , #2 I think is better way to go since I have too many nodes to manually edit otherwise and would be invasive, thus a module will have the benefit to apply it to many, hopefully even limit to certain content types / nodes and able to change lazy load setup within the module that way. Might you know how to insert a condition for content type 'xyz' into that text format module?Upward
can you please clarify if I can create that text-format "plugin" also for D7 which you explained in the other post for D8? Does that code go into a custom module or is it a different approach? This would be my preference, to avoid editing HTML of the nodes to implement blazy. I looked at #2 above but unsure how to start with a module to "use blazy". Would I still need (function ($) { Drupal.behaviors.CUSTOMMODULE = { attach: function (context, settings) { ? How to start that module? Thanks Osman.Upward
Check out the answer for the link Adding JavaScript to your theme or moduleProcurable
You may also want to check out the Examples module for creating a filter module that you need.Procurable
@osmann I managed to create a custom module to load the blazy.min.js and loaded the code from #2 into blazy_load.js but it seems it doesn't execute, using the options with the 'img' selector (which I expect should work with my current <img alt scr= /myimage.jpg"> tags). Am i loading this wrongly? Got confused as you mentioned jQuery before...Upward
seeing that there is a need for it, I just released a D7 module at drupal.org/project/lazy I'll add D8 version soon as well.Procurable
Wow you're awesome, I'll try it out and let you know :) definitely a need given the many search results but lack for inline images. Perhaps at a later stage might be worthwhile to consider to join it into the blazy module to enhance it. For my own understanding, re my question, did I execute blazy right by loading #2 in a .js or were i misisng something ?Upward
I tried your module, thanks, looks great work, especially providing configuragble parameters! Nice. I can see blazy.min.js is loaded and markup changed, however unfortunatelly it's not triggering the loading yet. I think due to multiple nodes (faq module) displayed on one page but first loaded with .collapsible (display:block) .collapsed (display:none) and after clicking tabs to show the content it removes .collapsed (display:none). Would this be invisible (hidden) elements? I tried the loadInvisible but it's loading all images and thus no more lazy loading. Any way around this?Upward
Happy to have a chat if you're free some time/day, much appreciated. I looked at the .js responsible for the toggleClass collapsed and while I'm no js expert I'm wondering if I might need to initiate the blazy function somehow again so it can trigger?Upward
Thanks again for this great module and continuing to improve it. I discovered one issue now that it breaks anchor links and wondering if we could solve this somehow? drupal.org/project/lazy/issues/2999351#comment-12771971Upward
thanks again for creating the lazy module you rock! Can you kindly advise re "Disabled Pages" if it supports only specific full paths or can it skip all paths starting for example with events/ ? I tried many combinations but it seems to only accept full paths. drupal.org/project/lazy/issues/3209086Upward
E
1

I've built a lazy load module for drupal 8. Should work out-of-the-box: Fancyload - lazy load images pinterest-style

Fancyload will automatically provide lazyloading of images on your website in a pinterest-style color scheme. It fetches the main color of your image and serves it until your image is loaded.

Expenditure answered 30/10, 2019 at 12:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.