Coder Social home page Coder Social logo

apoorvsaxena / lozad.js Goto Github PK

View Code? Open in Web Editor NEW
7.4K 115.0 449.0 5.92 MB

🔥 Highly performant, light ~1kb and configurable lazy loader in pure JS with no dependencies for responsive images, iframes and more

Home Page: https://apoorv.pro/lozad.js/demo/

License: MIT License

JavaScript 100.00%
performance javascript lazy-loading lazyload html images hacktoberfest

lozad.js's Introduction

Lozad.js npm version Build Status npm

Highly performant, light and configurable lazy loader in pure JS with no dependencies for images, iframes and more, using IntersectionObserver API

lozad.js lazy loading javascript library

Lozad.js:

  • lazy loads elements performantly using pure JavaScript,
  • is a light-weight library, just minified & gzipped,
  • has NO DEPENDENCIES :)
  • allows lazy loading of dynamically added elements as well,
  • supports <img>, <picture>, iframes, videos, audios, responsive images, background images and multiple background images etc.
  • even supports LQIP (Low Quality Image Placeholder)
  • is completely free and open source.
  • it will reload when the valid attributes change.

It is written with an aim to lazy load images, iframes, ads, videos or any other element using the recently added Intersection Observer API and MutationObserver with tremendous performance benefits.

Featured in:

Brands using Lozad.js:

Tesla          Binance          Domino's          BNP Paribas          Mi          Amway          TATA          Verizon Atlassian BNP Paribas JLM Couture          New Balance          BBC

and many more...

Table of Contents

Yet another Lazy Loading JavaScript library, why?

Existing lazy loading libraries hook up to the scroll event or use a periodic timer and call getBoundingClientRect() on elements that need to be lazy loaded. This approach, however, is painfully slow as each call to getBoundingClientRect() forces the browser to re-layout the entire page and will introduce considerable jank to your website.

Making this more efficient and performant is what IntersectionObserver is designed for, and it’s landed in Chrome 51. IntersectionObservers let you know when an observed element enters or exits the browser’s viewport.

Install

# You can install lozad with npm
$ npm install --save lozad

# Alternatively you can use Yarn
$ yarn add lozad

# Another option is to use Bower
$ bower install lozad

Then with a module bundler like rollup or webpack, use as you would anything else:

// using ES6 modules
import lozad from 'lozad'

// using CommonJS modules
var lozad = require('lozad')

Or load via CDN and include in the head tag of your page.

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>

When loading from CDN, you can find the library on window.lozad.


Usage

In HTML, add an identifier to the element (default selector identified is lozad class):

<img class="lozad" data-src="image.png">

All you need to do now is just instantiate Lozad as follows:

const observer = lozad(); // lazy loads elements with default selector as '.lozad'
observer.observe();

or with a DOM Element reference:

const el = document.querySelector('img');
const observer = lozad(el); // passing a `NodeList` (e.g. `document.querySelectorAll()`) is also valid
observer.observe();

or with custom options:

const observer = lozad('.lozad', {
    rootMargin: '10px 0px', // syntax similar to that of CSS Margin
    threshold: 0.1, // ratio of element convergence
    enableAutoReload: true // it will reload the new image when validating attributes changes
});
observer.observe();

Reference:

or if you want to give custom function definition to load element:

lozad('.lozad', {
    load: function(el) {
        console.log('loading element');

        // Custom implementation to load an element
        // e.g. el.src = el.getAttribute('data-src');
    }
});

If you would like to extend the loaded state of elements, you can add the loaded option:

Note: The "data-loaded"="true" attribute is used by lozad to determine if an element has been previously loaded.

lozad('.lozad', {
    loaded: function(el) {
        // Custom implementation on a loaded element
        el.classList.add('loaded');
    }
});

If you want to lazy load dynamically added elements:

const observer = lozad();
observer.observe();

// ... code to dynamically add elements
observer.observe(); // observes newly added elements as well

for use with responsive images

<!-- responsive image example -->
<img class="lozad" data-src="image.png" data-srcset="image.png 1000w, image-2x.png 2000w">

for use with background images

<!-- background image example -->
<div class="lozad" data-background-image="image.png">
</div>

for use with multiple background images

<!-- multiple background image example -->
<div class="lozad" data-background-image="path/to/first/image,path/to/second/image,path/to/third/image">
</div>

for use with responsive background images (image-set)

<!-- responsive background image-set example -->
<div class="lozad" data-background-image-set="url('photo.jpg') 1x, url('[email protected]') 2x">
</div>

To change the delimiter that splits background images:

<!-- custom delimiter for background images example -->
<div
  class="lozad"
  data-background-image="/first/custom,image,path/image.png-/second/custom,image,path/image.png"
  data-background-delimiter="-"
>
</div>

If you want to load the images before they appear:

const observer = lozad();
observer.observe();

const coolImage = document.querySelector('.image-to-load-first');
// ... trigger the load of a image before it appears on the viewport
observer.triggerLoad(coolImage);

Large image improvment

Sometimes image loading takes a long time. For this case, you can add a placeholder background:

<img class="lozad" data-placeholder-background="red" data-src="image.png">

Lozad sets a placeholder background color of img element and users will see the fallback till the image loads.

Example with picture tag

Create a broken picture element structure.

IE browser don't support picture tag! You need to set data-iesrc attribute (only for your picture tags) with source for IE browser

data-alt attribute can be added to picture tag for use in alt attribute of lazy-loaded images

<!-- For an element to be caught, add a block type that is different from the inline and some min-height for correct caught into view -->
<picture class="lozad" style="display: block; min-height: 1rem" data-iesrc="images/thumbs/04.jpg" data-alt="">
    <source srcset="images/thumbs/04.jpg" media="(min-width: 1280px)">
    <source srcset="images/thumbs/05.jpg" media="(min-width: 980px)">
    <source srcset="images/thumbs/06.jpg" media="(min-width: 320px)">
    <!-- NO img element -->
    <!-- instead of img element, there will be the last source with the minimum dimensions -->
    <!-- for disabled JS you can set <noscript><img src="images/thumbs/04.jpg" alt=""></noscript> -->
</picture>

When lozad loads this picture element, it will fix it.

If you want to use image placeholder (like low quality image placeholder), you can set a temporary img tag inside your picture tag. It will be removed when lozad loads the picture element.

<picture class="lozad" style="display: block; min-height: 1rem" data-iesrc="images/thumbs/04.jpg" data-alt="">
    <source srcset="images/thumbs/04.jpg" media="(min-width: 1280px)">
    <source srcset="images/thumbs/05.jpg" media="(min-width: 980px)">
    <source srcset="images/thumbs/06.jpg" media="(min-width: 320px)">
    <!-- you can define a low quality image placeholder that will be removed when the picture is loaded -->
    <img src="data:image/jpeg;base64,/some_lqip_in_base_64==">
</picture>

Example with video

<video class="lozad" data-poster="images/backgrounds/video-poster.jpeg">
    <source data-src="video/mov_bbb.mp4" type="video/mp4">
    <source data-src="video/mov_bbb.ogg" type="video/ogg">
</video>

Example with iframe

<iframe data-src="embed.html" class="lozad"></iframe>

That's all, just add the lozad class.

Example toggling class

<div data-toggle-class="active" class="lozad">
    <!-- content -->
</div>

The active class will be toggled on the element when it enters the browser’s viewport.

Browser Support

Available in latest browsers. If browser support is not available, then make use of polyfill.

For IE11 support, please make use of these polyfills.

FAQs

Checkout the FAQ Wiki for some common gotchas to be aware of while using lozad.js

Contribute

Interested in contributing features and fixes?

Read more on contributing.

Changelog

See the Changelog

License

MIT © Apoorv Saxena

lozad.js's People

Contributors

apoorvsaxena avatar deltaepsilon avatar dependabot[bot] avatar dooman87 avatar fatihbatal avatar fregante avatar gchtr avatar huaoguo avatar i-like-robots avatar iam-frankqiu avatar igorkamyshev avatar joshwhatk avatar keithamus avatar levdbas avatar lionralfs avatar lptn avatar lsarni avatar mahish avatar niketpathak avatar nuoyz avatar olehdutchenko avatar pedroborges avatar pekkapleppanen avatar rashidul0405 avatar saadeghi avatar srogier avatar stephenkingsley avatar steveoh avatar thiamsantos avatar zabawaba99 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lozad.js's Issues

Feature request: Low Quality Image Placeholders (LQIP)

Would it be possible to keep the current behavior but once the image appears on the screen first load a lower quality image and then the final image?
This would reduce the time in which the image isn't display once the user reaches it.

Remove dist folder from git

Remove dist folder from to git as it is a file automatically generated and we don't need to keep track of them. In that way would be possible to keep the pull requests more clean. To accomplish this just add the dist folder to the gitignore file and add a files property to the package.json specifying the files to be included in the package when download it from npm. Right now all the repo is included.

The only problem that I can see on doing this is that the demo uses a relative path to the dist folder. But the demo can pull the project from a cdn (related #17).

Testing for image element

Hi! Thanks for the awesome library!

I was wondering if it would be an idea to actually test for the img element in the check that you do? Seeing that the src attribute can only be applied to a limited amount of elements, it would be easy to test for those and add specific functionality for them, and otherwise for background images. This way we can give the background image a regular data-src as well, instead of the data-background-image we've got now.

Something like:

if (element.tagName === 'IMG') {
  if (element.dataset.src) {
    element.src = element.dataset.src;
  }
  if (element.dataset.srcset) {
    element.srcset = element.dataset.srcset;
  }
} else {
  element.style.backgroundImage = `url(${element.dataset.src})`;
}

maybe?

React Support?

I was wondering if Lozad works with react? I'm currently having trouble getting it work, I was trying to utilize lifecycle methods and have it not start observing until after the component is rendered. However, it seems like based on the nature of react and vdom, it doesn't actually work because my component is rendered before Lozad is initialized.

Any ideas? I was trying something along the lines of:

    observer = lozad('.lozad', {
        load: function() { console.log('loaded'); }
    });

    componentDidMount() {
        this.observer.observe();
    }

Thanks in advanced!

Support passing an `Element` or `NodeList`

It would be really useful to be able to pass either an Element or NodeList as well as a string selector.

For example:

const node = document.querySelector('img')
lozad(node)

or

const nodes = document.querySelectorAll('img')
lozad(nodes)

I'm using Lozad in a web component context, where I don't want to select my DOM node from the document, but rather some local tree. Being able to pass in the reference to the node(s) myself makes this trivial.

I have made the changes in a forked branch as a proof of concept, which I am happy to PR if there is agreement around the idea!

Forked branch: https://github.com/chrishutchinson/lozad.js/tree/feature/passElementOrNodeList

lozad.js with picture-element to use src from source

Hi there,

First of all great work, much appreciated!

I'm using lozad with the <picture> element like the following structure:

<picture>
    <!--[if IE 9]><video style="display: none;"><![endif]-->
      <source media="(min-width: 1024px)" data-srcset="...">
      <source media="(min-width: 768px)" data-srcset="...">
      <source data-srcset="...">
    <!--[if IE 9]></video><![endif]-->
    <img class="lozad" data-src="" alt="...">
</picture>

It happens that the final rendered image gets the data-src of the <img>-tag as its src rather than the desired source coming from the srcset of the matching <source>. Did I miss anything in the code above? I initialize it via simply calling observer.observe();

Thanks a lot for getting back to me,
Stefan

Why selectorClass?

It seems like selectorClass is too specific.

It would be better to use selector so one could do the following:

new Lozad({
  selector: 'img',
  threshold: 0.1
})

Or the following:

new Lozad({
  selector: '#jumbo',
  threshold: 0.1
})

Of course you could still select by class, just add a dot.

new Lozad({
  selector: '.lozad',
  threshold: 0.1
})

Is this project willing take pull request of typescript definitions?

It will be useful for typescript users and improve the experiences on some editors like vscode.

basicly a index.d.ts file with:

type Option = {
    rootMargin?: string;
    threshold?: number;
    load?(element: HTMLElement | HTMLCanvasElement): void;
}

type Observer = {
    observe(): void;
}

declare function lozad(selector?: string, options?: Option): Observer;

declare namespace lozad {
    const prototype: {
    };
}

export as namespace lozad;

export = lozad;

Make placeholder div

can we make a div placeholder that will be shown before image fully loads, so images will not jump around

Use travis

Add a simple build step on travis to show the people that the package has no errors.

Kebab-case classes are not fired

Following the documentation, to pick a typical CSS kebab-case class, does not make the plugin fire.

E.g.:

const observer = lozad('.is-lazy')

Preloader

Would like to make a preloader
Believe that users should have a indication of a loading element.
Is there an .is-loading class or something.

How can achieve this, thanks?

IE9 not working - loader Issue

When emulating IE9, images do not load because of the following error:

The "loaded" property of an undefined or null reference can not be retrieved.

Seems like it hase something to do with the loaded statement. I tried to fix it but I failed:

t.dataset.loaded=!0

Any help would be appreciated.

Thanks,

Sebastian

P.S. Adding the Polyfill does not work either. As far as I understand, Polyfill only helps for IE Versions Prior 9.

deprecating Bower support

Considering that:

  • Bower itself has been recommending use of Yarn for package installation
  • No way to automate publishing update to bower
  • most of the users are using jsDeliver CDN with ~1M downloads/month or npm package

thanks to @thiamsantos for suggesting this before as well, with data it's evident now that folks are using CDN directly or Yarn installation only.

srcset

Is it possible to add support for "srcset"?

Expose a function to load specific images before they appear

It would be useful to be able to preload certain images in advance when certain events are triggered (say, a menu is opened). Currently, though, the load function is not exported from the module. It would be useful to reuse it instead of having to write it by yourself.

The only issue I see is that the load function is configurable. Although I suppose, we could assign it to the lozad object.

Example:

import lozad from 'lozad'

const observer = lozad()
observer.observe()
document.addEventListener('menu:open', () => {
  observer.load('img.language-icon')
})

Though observer.load doesn't sound right.

iframes

Where is demo and documentation about lazyloading iframes?

Check if image is loaded?

It seems that in a gallery with a large numbers of items it can happen that data-loaded=true or any class you add in the callback, for that matters, can be applied to an image while the background image is not yet fully loaded. This results in a suddenly appearing image (especially when the images itself are fairly large) because the transition was already applied before the image was loaded in the browser.

I would propose to test if the image is actually loaded before adding the data-loaded=true attribute. Maybe like

const imgLoad = new Image();
imgLoad.onload = () => {
  element.dataset.loaded = true;
}
imgLoad.src = element.dataset.src;

There might be better ways to check if the images are loaded, but you catch my drift :)

edit: This does lead to the loading of two files when the srcset file which is loaded is different from the src file. This could be fixed by polling if element.currentSrc is set and use that image for the imgLoad.src.

add dev server

I think add a script just like npm run dev. It can see the example and it's convenient to debug and coding lozad.js

Threshold not working

Hi,

I was reading the official documentation to understand how Intersection observer work:

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options

But while making some tests to fine tune, I've notice that changing threshold to any value doesn't delay the callback at all.

For exemple, the callback should wait until all pixel are in view if the threshold is set to 1 but that's not the case.

Am I the only one with this problem?

Cheers

Change method signature

What do you think about changing the method signature from this:

const lozad = new Lozad({
    selectorClass: 'lozad', // for identification of images to lazy load
    rootMargin: '10px 0px', // syntax similar to that of CSS Margin
    threshold: 0.1 // ratio of image convergence
})
lozad.load = function(el) {
	console.log('loading element');
}

For something like this:

lozad('.some-selector', {
  rootMargin: '10px 0px',
  threshold: 0.1,
  onLoad() {
    console.log('loading element')
  }
})

In that way we would follow some good patterns followed by big libraries out there like moment. Additionally eslint has a rule that discourages the use of new for side effects. There a whole talk about that, I think that would be good if you check it out.

Best regards.

Use ES6

Would be great to use ES6 in the project and let Babel and rollup handle all the transpilation complexity.

Srcset

Does your plugin work with srcset? Or only with src?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.