WP lazy loading using intercooler.js 02

Going responsive.

I’m calling home so better make it count

The flow I’m using in the lazy-loading-theme experiment to lazy load images when scrolled into view has a big disadvantage over a totally JavaScript based approaches and that’s a “call home” done to the server to the /lazy-load-images route

<div class="lazy-img centered" ic-trigger-on="scrolled-into-view"
      ic-src="/lazy-load-image?url=<?php echo urlencode( 'http://lorempixel.com/800/400/sports/3' ) ?>">
</div>

I’m not being fanatic about this approach but before dumping it as “not worth it” I will try to reap all the benefits I can get from it; namely: responsive images.

As small as I can get it

Let’s make an example where I have a viewport of 300 pixels and have the code below

<div class="lazy-img centered" ic-trigger-on="scrolled-into-view"
      ic-src="/lazy-load-image?url=<?php echo urlencode( 'http://lorempixel.com/800/400/sports/3' ) ?>">
</div>

The request handling will return an img tag referring an 800px wide image that will be squeezed down to fit inside a 300 pixels viewport: this is hardly the best use of the user bandwidth.

// file functions.php

add_action( 'wp-routes/register_routes', function () {

    // Image lazy loading requests        
    respond( 'GET', '/lazy-load-image', function () {
        echo "<img src='{$_REQUEST['url']}'>";
    } );

} );

The code uses wp-routes to handle the routing but is hardly doing the best possible job.

How wide the viewport?

Ideally I would like to return a link to the smallest possible image needed in the application. And this does not mean “as wide as the viewport” as images could use an half of it and the smallest possible image I could return would then be 150 pixels wide in place of 300 pixels.
How to know the smallest possible size the returned image can be for each request?
The second component of the game is the intercooler.js library and I will tap into its events to add some data to each request I make for a lazy image.
I will get the width of the element that’s sending the request and add it to the data intercooler.js is sending along with each request using a small theme JavaScript file

// file js/lazy.js 

(function ( $, undefined ) {
    'use strict';

    $( document ).on( 'beforeSend.ic', function ( evt, elt, data, settings, xhr, requestId ) {
        settings.url += '&width=' + elt.width();
    } );

})( jQuery )

this is being queued in the theme functions.php file

// file functions.php

add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_script( 'lazy-js', get_template_directory_uri() . '/js/lazy.js', [ 'jquery' ] );
} );

and the request handling will take care of returning the smallest possible image

// file functions.php

add_action( 'wp-routes/register_routes', function () {
    respond( 'GET', '/lazy-load-image', function () {
        $width   = filter_var( $_REQUEST['width'], FILTER_SANITIZE_NUMBER_INT );
        $url     = filter_var( $_REQUEST['url'], FILTER_SANITIZE_URL );
        $matches = array();
        preg_match( "~(?<=/)(\\d*)/(\\d*)(?=/)~u", $url, $matches );

        if ( empty( $matches ) ) {
            echo "<img src='{$_REQUEST['url']}'>";

            return;
        }
        $ratio  = $width / $matches[1];
        $height = ceil( $matches[2] * $ratio );
        $url    = str_replace( $matches[1], ceil( $width ), str_replace( $matches[2], $height, $url ) );

        echo "<img src='{$url}'>";
    } );
} );

I’ve added two and three columns to the layout to make sure fractions of the viewport are handled.
Two columns
Three columns

On GitHub

I’ve pushed the version of the theme (an experiment) contemporary to this post to GitHub.
Different sizes

Next

I will stop pulling images from lorempixel and start using WordPress media files and do some size juggling.

I appreciate your input