PHPackages                             styletools/lazy - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. styletools/lazy

ActiveProject[Image &amp; Media](/categories/media)

styletools/lazy
===============

A lightweight lazy loader based on `window.IntersectionObserver` with tiny fallback for old browsers.

1.3.0(3y ago)5132MITJavaScriptCI failing

Since May 23Pushed 3y ago1 watchersCompare

[ Source](https://github.com/pagespeed-pro/lazy)[ Packagist](https://packagist.org/packages/styletools/lazy)[ RSS](/packages/styletools-lazy/feed)WikiDiscussions master Synced 5d ago

READMEChangelog (10)DependenciesVersions (18)Used By (0)

[![Build Status](https://camo.githubusercontent.com/daa980257c6aec8e2253dd995466796315cf13c4355d2ea131de47461651de92/68747470733a2f2f7472617669732d63692e636f6d2f7061676573706565642d70726f2f6c617a792e7376673f6272616e63683d6d6173746572)](https://travis-ci.com/pagespeed-pro/lazy) [![Version](https://camo.githubusercontent.com/db58ae6e50029b8d1c7f12961a90970015b36af153cfb9df4029405ee2fc9f1e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f7061676573706565642d70726f2f6c617a792e737667)](https://github.com/pagespeed-pro/lazy/releases) [![npm version](https://camo.githubusercontent.com/ea9941c660eabb47f7ee9b3dfec09c31148bc67dfc13efb9443d05a935a451e6/68747470733a2f2f62616467652e667572792e696f2f6a732f2534307061676573706565642d70726f2532466c617a792e737667)](http://badge.fury.io/js/%40pagespeed-pro%2Flazy) [![Latest Stable Version](https://camo.githubusercontent.com/396fe09c68c646b41254134f69dc40b939e7be04b10f4790a12e6adf237a0100/68747470733a2f2f706f7365722e707567782e6f72672f7374796c65746f6f6c732f6c617a792f762f737461626c652e706e67)](https://packagist.org/packages/styletools/lazy)

`$lazy` Lazy Loader
===================

[](#lazy-lazy-loader)

A lightweight and high performance lazy loader and `element-in-view` callback based on [Intersection Observer V2](https://developers.google.com/web/updates/2019/02/intersectionobserver-v2) with an efficient polyfill for old browsers.

```
// simple: lazy load images
$lazy('[data-src]');

// simple: in-view callback
$lazy('#element', function() {
  // inview callback
});
```

$lazy can be configured using an async script element.

```

```

The script element accepts the following parameters:

ParameterDescriptionType`data-z`Selector or config object.`String``data-zz`Multiple selector or config objects.`Array``data-b`Base path (URL rebasing) for HTML size compression.`String`When using [$async](https://github.com/pagespeed-pro/async/), $lazy can be used as a timing method with automated polyfill loading.

```

```

### Documentation is available on [pagespeed.pro/lazy](https://pagespeed.pro/lazy/#documentation).

[](#documentation-is-available-on-pagespeedprolazy)

Install via npm
===============

[](#install-via-npm)

```
npm install @optimization/lazy --save
```

Description
===========

[](#description)

$lazy is designed as the ultimate lazy loader and `element-in-view` callback for frontend optimization (FEO). It provides state of the art features such as client-side Google `.webp` rewrite, the absolute best performance and the tiniest HTML footprint. $lazy supports all browsers including iPhone5 and IE9+. IE8 would be supported but isn't supported by Google's [IntersectionObserver polyfill](https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js).

- 100% JSON control.
- tiny: the `$z()` version is merely 300 bytes in size.
- support for old browsers with a 0% performance hit for modern browsers.

Advanced control of `IntersectionObserver`
------------------------------------------

[](#advanced-control-of-intersectionobserver)

$lazy provides full control of the `IntersectionObserver` and supports the latest features.

```
// simple settings
$lazy({
   "selector": "[data-src]",
   "threshold": 0.006,
   "rootMargin": "0px"
});

// advanced observer config
$lazy({
  "selector": "[data-src]",
  "observer": {
    "threshold": 0.006,
    "rootMargin": "0px",
    "trackVisibility": true,
    "delay": 100
  }
);
```

To save size, the configuration can be provided as an array.

```
// simple settings
$lazy(["[data-src]",0.006,"0px"]);

// advanced observer config
$lazy(["[data-src]",{
  "threshold": 0.006,
  "rootMargin": "0px",
  "trackVisibility": true,
  "delay": 100
}]);
```

$lazy returns a DOM `NodeList` with elements watched by the observer.

```
var elements = $lazy('[data-src]');
```

Security
--------

[](#security)

$lazy supports a strict `Content-Security-Policy` and can be controlled by a `async` HTML script tag.

```

```

Multiple configurations are supported via the attribute `data-zz`. The attributes accepts a JSON array with configurations.

```

```

Compressed `srcset`
-------------------

[](#compressed-srcset)

$lazy enables to compress `srcset` to save HTML document size using the attribute `data-z`.

```

```

Advanced `in-view` and `out-of-view` callback
---------------------------------------------

[](#advanced-in-view-and-out-of-view-callback)

$lazy enables to make full use of the `IntersectionObserver` for any purpose and supports a simple `in-view` callback, an `out-of-view` callback or a custom `IntersectionObserver` callback.

```
$lazy(".selector", function() {
  // element in view
});
```

By returning `false` from a custom inview callback, the observer will not be removed and will trigger the callback again when the element moves in or out of view. The third parameter is a boolean with the `in-view` status.

```
$lazy(".selector", function(target, observer, is_inview) {

  if (is_inview) {

    // element is in view

  } else {

    // element is out of view

  }

  return false; // persist observer to enable out-of-view callback
});
```

For advanced usage, the inview argument accepts an array with 3 index positions:

1. `inview`: a function to call when the element moves into view.
2. `out-of-view` a function to call when the element moves out of view
3. `after_inview` a function to call when using the default inview-method (the image resolver) after `src` and `srcset` have been rewritten.

When `out-of-view` is null, the `inview` method is used as the `out-of-view` callback.

```
$lazy(".selector", [
  function inview(target, observer) {

    // element is in view

    return false; // persist observer
  },
  function out_of_view(target, observer) {

    // element is out of view

    return false; // persist observer
  }]);
```

The `after_inview` callback enables to easily extend resolved images by the default image resolver.

```
$lazy(".selector", [,,function after_inview(target) {

  // target (image) has been lazy-loaded and resolved
  target.classList.add('custom-class');
}]);
```

Custom `IntersectionObserver` callback
--------------------------------------

[](#custom-intersectionobserver-callback)

The third argument enables to manually define the `IntersectionObserver` callback which makes it possible to use $lazy for easy access to the functionality provided by `IntersectionObserver`.

```
$lazy('div#id', 0, function(entries) {
  // native IntersectionObserver callback
})
```

Events
------

[](#events)

$lazy provides an extension that watches for `mouseover`, `click` and the custom `z` event to fire the in-view callback manually. This feature ensures that images are resolved in the case of issues with the IntersectionObserver polyfill and it enables to manually trigger the callback, for example before printing.

```
// load all images before printing
window.onbeforeprint = function() {

  // get all applicable elements by using an empty inview handler
  var images = $lazy('[data-z]', function() {});

  // fire `z` event on images
  if (images) {
    images.forEach(function(i) {
      try {
            var EventName = 'z';
            if( i.fireEvent ) {
                i.fireEvent( 'on' + EventName );
            } else {
                var evObj = document.createEvent( 'Events' );
                evObj.initEvent( EventName, true, false );
                i.dispatchEvent( evObj );
            }
        } catch (e) {

        }
    });
  }
};
```

It is possible to manually define events to watch using the configuration parameter `events` or the array index `4`.

```
{
  "selector": "[data-src]",
  "events": ["mouseover", "custom-event"]
}
```

Manually resolve images
-----------------------

[](#manually-resolve-images)

$lazy enables to manually resolve images using the default image resolver by providing `1` as the in-view callback.

```
$lazy('[data-src]', 1); // resolve all images
```

Client-side `.webp` rewrite
---------------------------

[](#client-side-webp-rewrite)

$lazy provides an extension to automatically rewrite images to `.webp` in browsers that support Google's [WebP](https://developers.google.com/speed/webp/) image format. The solution prevents a server-side redirect which improves performance.

The solution is fail safe and uses `` as a fallback to the original image when the `.webp` image is 404 or fails to load.

It is possible to manually disable the `.webp` rewrite for an image by defining the HTML attribute `data-webp="no"` or by using the $lazy configuration parameter `webp` or array index `3`.

```
{
  "selector": "[data-src]",
  "webp": false
}
```

`$lazybg` supports `.webp` rewrites as well.

`$lazybg` lazy loading of `background-image`
--------------------------------------------

[](#lazybg-lazy-loading-of-background-image)

$lazy provides a unique innovation to lazy load `background-image` in stylesheets using [CSS Variables](https://www.w3schools.com/css/css3_variables.asp) with a fallback for old browsers.

There are four options to resolve images:

1. manually define images via `:root {}` within the stylesheet
2. base64 encode image URLs
3. provide a JSON source list as resolver
4. provide a javascript function as resolver

```
/* :root based pre-configured value */
:root {
  --z--lazy-img: url('/image.jpg');
}
footer {
  background-image: url('/image.jpg'); // old browsers
  background-image: var(--z-lazy-img, none);
}

/* base64 encoded value */
p#out-of-view {
  background-image: url('/image.jpg'); // old browsers
  background-image: var(--z-base64_value, none); /* note: requires character replacements, see documentation */
}

/* JSON object or javascript function based custom resolver */
div#out-of-view {
  background-image: url('/image.jpg'); // old browsers
  background-image: var(--z-custom-resolved, none);
}
```

```

// default: document.styleSheets
$lazybg();

// custom $lazy config
$lazybg(
  document.querySelectorAll('link[rel=stylesheet], style#other'),
  {
    observer: {
      threshold: 0,
      rootMargin: '100px'
    }
  }
);

// custom JSON based resolver
$lazybg(
  0,0, // default config

  // resolver
  {
    "custom-resolved": "url('/image.jpg')"
  }
);

// custom javascript based resolver
$lazybg(
  0,0, // default config

  // resolver
  function(key) {

    // resolve key "custon-resolved"
    return "url('/"+key+".jpg');"
  }
);

```

Note: CSS variables are limited to `DOMString`. When using inline base64 encoding, the following characters need to be replaced in the encoded value:

`/`: `—`

`=`: `•`

Polyfill
--------

[](#polyfill)

`$lazy` provides support for Google's [IntersectionObserver polyfill](https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js) with 0% performance hit for modern browsers.

When using the polyfill extension, `$lazy` checks for the parameter `window.$lazypoly` when IntersectionObserver is not supported by the browser.

When `window.$lazypoly` is defined as a function, $lazy will fire it and expect a `.then` method to be resolved when the polyfill is loaded.

When `window.$lazypoly` is defined as a string, the string is passed to [$async.js](https://github.com/pagespeed-pro/async/) that could load anything.

```
// manually load a polyfill
window.$lazypoly = function() {

   // load polyfill manually
   // ...

   return {
      then: function(callback) {

         // wait until polyfill is loaded and resolve callback

         callback();
      }
   }
};

// load a polyfill using $async.js
window.$lazypoly = 'dist/intersectionobserver-polyfill.js';
```

`$lazy` as a timing method in `$async`
--------------------------------------

[](#lazy-as-a-timing-method-in-async)

$lazy and the polyfill can be efficienty loaded using [$async](https://github.com/pagespeed-pro/async/) and it's `just-in-time` timing method. $lazy then becomes available as a timing method within $async which enables to load stylesheets and scripts using the `IntersectionObserver`.

$async enables to load the `$lazy` script and its optional polyfill from `localStorage` for exceptional speed.

```

```

Note: to use `$lazy` as a timing method in `$async` you need to set the `ref` of the lazy.js script to `$z`.

When including the `$lazy` script inline, the `data-poly` attribute enables to define a string to pass to `$async` to load a polyfill.

```

```

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~86 days

Recently: every ~279 days

Total

17

Last Release

1167d ago

Major Versions

0.0.1 → 1.0.02019-07-06

### Community

Maintainers

![](https://www.gravatar.com/avatar/6c2fe161ce09eac571f4be80cedda3a8fcaaf35678c60c9df8d1df7b22475162?d=identicon)[pagespeed.pro](/maintainers/pagespeed.pro)

---

Top Contributors

[![optimalisatie](https://avatars.githubusercontent.com/u/8843669?v=4)](https://github.com/optimalisatie "optimalisatie (104 commits)")

---

Tags

intersection-observerintersectionobserverlazy-loadlazy-loadingimageloaderimageslazyiframeintersectionobserver

### Embed Badge

![Health badge](/badges/styletools-lazy/health.svg)

```
[![Health](https://phpackages.com/badges/styletools-lazy/health.svg)](https://phpackages.com/packages/styletools-lazy)
```

###  Alternatives

[jbzoo/image

A PHP class that simplifies working with images

171126.9k3](/packages/jbzoo-image)[andrewgjohnson/imagettftextblur

imagettftextblur is a drop in replacement for imagettftext with added parameters to add blur, glow and shadow effects to your PHP GD images

27198.4k1](/packages/andrewgjohnson-imagettftextblur)[simonvomeyser/commonmark-ext-lazy-image

Adds support for lazy images to the phpleague/commonmark markdown parser package

1821.3k1](/packages/simonvomeyser-commonmark-ext-lazy-image)[ayvazyan10/nova-imagic

Imagic is a Laravel Nova field package that allows for image manipulation capabilities, such as cropping, resizing, quality adjustment, and WebP conversion. It utilizes the powerful Intervention Image class for image manipulation.

144.3k1](/packages/ayvazyan10-nova-imagic)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
