Skip to content

Instantly share code, notes, and snippets.

@gormus
Last active April 8, 2018 05:18
Show Gist options
  • Save gormus/67602f9d4973c40bba87a9e61adefa98 to your computer and use it in GitHub Desktop.
Save gormus/67602f9d4973c40bba87a9e61adefa98 to your computer and use it in GitHub Desktop.
Lazy load any image rendered via theme_image(). This is a simple Drupal 7 module to lazy-load all images generated via theme_image()

bLazy (*) for Drupal 7

This is a very simple Drupal 7 module to lazy-load all images generated via theme_image() using the bLazy image script.

This simply means every single image fields; and all images generated programmatically.

Also, static HTML image markups could easily be changed to use theme_image(). For example, in Bartik theme the site logo is created with old-school image markup:

<img src="<?php print $logo; ?>" alt="<?php print t('Home'); ?>" />

To lazy-load via theme_image() + bLazy:

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

or

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

Both examples will be lazy-loaded.

Images added to node's body must have class="b-lazy" and their src attribute must be renamed to data-src to lazy-load. Any changes in settings.CUSTOMMODULE.bLazy options must reflect to manually added image markups.

Drupal 8

There is already a module available to integrate bLazy with Drupal 8: Blazy

  • bLazy is a lightweight lazy loading and multi-serving image script created by Bjoern Klinggaard. See its website for details.
/*!
hey, [be]Lazy.js - v1.8.2 - 2016.10.25
A fast, small and dependency free lazy load script (https://github.com/dinbror/blazy)
(c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy
*/
(function(q,m){"function"===typeof define&&define.amd?define(m):"object"===typeof exports?module.exports=m():q.Blazy=m()})(this,function(){function q(b){var c=b._util;c.elements=E(b.options);c.count=c.elements.length;c.destroyed&&(c.destroyed=!1,b.options.container&&l(b.options.container,function(a){n(a,"scroll",c.validateT)}),n(window,"resize",c.saveViewportOffsetT),n(window,"resize",c.validateT),n(window,"scroll",c.validateT));m(b)}function m(b){for(var c=b._util,a=0;a<c.count;a++){var d=c.elements[a],e;a:{var g=d;e=b.options;var p=g.getBoundingClientRect();if(e.container&&y&&(g=g.closest(e.containerClass))){g=g.getBoundingClientRect();e=r(g,f)?r(p,{top:g.top-e.offset,right:g.right+e.offset,bottom:g.bottom+e.offset,left:g.left-e.offset}):!1;break a}e=r(p,f)}if(e||t(d,b.options.successClass))b.load(d),c.elements.splice(a,1),c.count--,a--}0===c.count&&b.destroy()}function r(b,c){return b.right>=c.left&&b.bottom>=c.top&&b.left<=c.right&&b.top<=c.bottom}function z(b,c,a){if(!t(b,a.successClass)&&(c||a.loadInvisible||0<b.offsetWidth&&0<b.offsetHeight))if(c=b.getAttribute(u)||b.getAttribute(a.src)){c=c.split(a.separator);var d=c[A&&1<c.length?1:0],e=b.getAttribute(a.srcset),g="img"===b.nodeName.toLowerCase(),p=(c=b.parentNode)&&"picture"===c.nodeName.toLowerCase();if(g||void 0===b.src){var h=new Image,w=function(){a.error&&a.error(b,"invalid");v(b,a.errorClass);k(h,"error",w);k(h,"load",f)},f=function(){g?p||B(b,d,e):b.style.backgroundImage='url("'+d+'")';x(b,a);k(h,"load",f);k(h,"error",w)};p&&(h=b,l(c.getElementsByTagName("source"),function(b){var c=a.srcset,e=b.getAttribute(c);e&&(b.setAttribute("srcset",e),b.removeAttribute(c))}));n(h,"error",w);n(h,"load",f);B(h,d,e)}else b.src=d,x(b,a)}else"video"===b.nodeName.toLowerCase()?(l(b.getElementsByTagName("source"),function(b){var c=a.src,e=b.getAttribute(c);e&&(b.setAttribute("src",e),b.removeAttribute(c))}),b.load(),x(b,a)):(a.error&&a.error(b,"missing"),v(b,a.errorClass))}function x(b,c){v(b,c.successClass);c.success&&c.success(b);b.removeAttribute(c.src);b.removeAttribute(c.srcset);l(c.breakpoints,function(a){b.removeAttribute(a.src)})}function B(b,c,a){a&&b.setAttribute("srcset",a);b.src=c}function t(b,c){return-1!==(" "+b.className+" ").indexOf(" "+c+" ")}function v(b,c){t(b,c)||(b.className+=" "+c)}function E(b){var c=[];b=b.root.querySelectorAll(b.selector);for(var a=b.length;a--;c.unshift(b[a]));return c}function C(b){f.bottom=(window.innerHeight||document.documentElement.clientHeight)+b;f.right=(window.innerWidth||document.documentElement.clientWidth)+b}function n(b,c,a){b.attachEvent?b.attachEvent&&b.attachEvent("on"+c,a):b.addEventListener(c,a,{capture:!1,passive:!0})}function k(b,c,a){b.detachEvent?b.detachEvent&&b.detachEvent("on"+c,a):b.removeEventListener(c,a,{capture:!1,passive:!0})}function l(b,c){if(b&&c)for(var a=b.length,d=0;d<a&&!1!==c(b[d],d);d++);}function D(b,c,a){var d=0;return function(){var e=+new Date;e-d<c||(d=e,b.apply(a,arguments))}}var u,f,A,y;return function(b){if(!document.querySelectorAll){var c=document.createStyleSheet();document.querySelectorAll=function(a,b,d,h,f){f=document.all;b=[];a=a.replace(/\[for\b/gi,"[htmlFor").split(",");for(d=a.length;d--;){c.addRule(a[d],"k:v");for(h=f.length;h--;)f[h].currentStyle.k&&b.push(f[h]);c.removeRule(0)}return b}}var a=this,d=a._util={};d.elements=[];d.destroyed=!0;a.options=b||{};a.options.error=a.options.error||!1;a.options.offset=a.options.offset||100;a.options.root=a.options.root||document;a.options.success=a.options.success||!1;a.options.selector=a.options.selector||".b-lazy";a.options.separator=a.options.separator||"|";a.options.containerClass=a.options.container;a.options.container=a.options.containerClass?document.querySelectorAll(a.options.containerClass):!1;a.options.errorClass=a.options.errorClass||"b-error";a.options.breakpoints=a.options.breakpoints||!1;a.options.loadInvisible=a.options.loadInvisible||!1;a.options.successClass=a.options.successClass||"b-loaded";a.options.validateDelay=a.options.validateDelay||25;a.options.saveViewportOffsetDelay=a.options.saveViewportOffsetDelay||50;a.options.srcset=a.options.srcset||"data-srcset";a.options.src=u=a.options.src||"data-src";y=Element.prototype.closest;A=1<window.devicePixelRatio;f={};f.top=0-a.options.offset;f.left=0-a.options.offset;a.revalidate=function(){q(a)};a.load=function(a,b){var c=this.options;void 0===a.length?z(a,b,c):l(a,function(a){z(a,b,c)})};a.destroy=function(){var a=this._util;this.options.container&&l(this.options.container,function(b){k(b,"scroll",a.validateT)});k(window,"scroll",a.validateT);k(window,"resize",a.validateT);k(window,"resize",a.saveViewportOffsetT);a.count=0;a.elements.length=0;a.destroyed=!0};d.validateT=D(function(){m(a)},a.options.validateDelay,a);d.saveViewportOffsetT=D(function(){C(a.options.offset)},a.options.saveViewportOffsetDelay,a);C(a.options.offset);l(a.options.breakpoints,function(a){if(a.width>=window.screen.width)return u=a.src,!1});setTimeout(function(){q(a)})}});
(function ($) {
Drupal.behaviors.CUSTOMMODULE = {
attach: function (context, settings) {
// @see http://dinbror.dk/blog/blazy/?ref=example-page#Options
var options = settings.CUSTOMMODULE.bLazy ? settings.CUSTOMMODULE.bLazy : {};
var bLazy = new Blazy(options);
}
};
}(jQuery));
<?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';
}
}
/**
* 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) . ' />';
}
}
/**
* Implements hook_page_build().
*/
function CUSTOMMODULE_page_build(&$page) {
$path = drupal_get_path('module', 'CUSTOMMODULE');
$page['page_bottom']['CUSTOMMODULE'] = array(
'#attached' => array(),
);
$attached = &$page['page_bottom']['CUSTOMMODULE']['#attached'];
$options = array('every_page' => TRUE);
// Default settings.
// @see http://dinbror.dk/blog/blazy/?ref=example-page#Options
$settings = array(
'selector' => '.b-lazy',
'src' => 'data-src',
'offset' => 100,
);
$attached['js'][] = array(
'data' => array('CUSTOMMODULE' => array('bLazy' => $settings)),
'type' => 'setting',
);
$attached['js'][$path . '/assets/blazy.min.js'] = $options + array('group' => JS_LIBRARY);
$attached['js'][$path . '/assets/CUSTOMMODULE.blazy.js'] = $options;
}
@gormus
Copy link
Author

gormus commented Apr 8, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment