diff --git a/.editorconfig b/.editorconfig index 4c4370f..b6ed257 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ root = true -[*.js] +[*] charset = utf-8 indent_size = 2 indent_style = space @@ -8,6 +8,5 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -[*.md] -trim_trailing_whitespace = true -end_of_line = crlf +[*.html] +indent_size = 4 diff --git a/LICENSE b/LICENSE index 667b799..78c426f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019-2023 Mai Nhut Tan +Copyright (c) 2019-2024 Mai Nhut Tan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 42eb67e..f8839f3 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,55 @@ -# Package @shinsenter/defer.js +# @shinsenter/defer.js -๐Ÿฅ‡ A JavaScript micro-library that helps you lazy load (almost) anything. Defer.js is zero-dependency, super-efficient, and Web Vitals friendly. +๐Ÿฅ‡ A lightweight JavaScript library that helps you lazy load (almost) anything. Defer.js is dependency-free, highly efficient, and optimized for Web Vitals. [![NPM](https://img.shields.io/npm/l/@shinsenter/defer.js)](https://code.shin.company/defer.js/blob/master/LICENSE) -[![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@shinsenter/defer.js)](https://snyk.io/advisor/npm-package/@shinsenter/defer.js) -[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/shinsenter/defer.js)](https://www.codefactor.io/repository/github/shinsenter/defer.js) [![GitHub Release Date](https://img.shields.io/github/release-date/shinsenter/defer.js)](https://code.shin.company/defer.js/releases) [![GitHub package.json version](https://img.shields.io/github/package-json/v/shinsenter/defer.js)](https://code.shin.company/defer.js/releases) [![npm bundle size (scoped)](https://img.shields.io/bundlephobia/minzip/@shinsenter/defer.js)](https://www.npmjs.com/package/@shinsenter/defer.js) [![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/@shinsenter/defer.js)](https://www.jsdelivr.com/package/npm/@shinsenter/defer.js) - -* * * - +> ๐Ÿ’ก [View document in other languages](#documentation-in-other-languages) ## Introduction -Lagging Big CSS files, slow JavaScript, or bulky media resources can cause issues with your website's Web Vitals, leading to a slow and frustrating user experience. But what if you could fully defer these resources and improve your website's load speed? - -By using Defer.js, you can say goodbye to these issues! With its lazy loading capabilities, dependency-free design, lightning-fast performance, and hard-won experience, Defer.js is the perfect solution for optimizing your website's Web Vitals. Whether you're using a modern or legacy browser, Defer.js makes it easy to enhance your website's user experience with lightning-fast loading times. - -[![NPM](https://nodei.co/npm/@shinsenter/defer.js.png?downloads=true)](https://www.npmjs.com/package/@shinsenter/defer.js) - -- **Package**: [@shinsenter/defer.js](https://www.npmjs.com/package/@shinsenter/defer.js) -- **Version**: 3.7.0 -- **Author**: Mai Nhut Tan -- **Copyright**: 2019-2023 SHIN Company -- **License**: [MIT](https://code.shin.company/defer.js/blob/master/LICENSE) - ---- - -## Document in other languages - -> [NEED HELP] Let's make the documentation and examples better together! - -### ๆ—ฅๆœฌ่ชž +Sluggish Big CSS files, slow JavaScript, or bulky media resources can negatively impact your website's Web Vitals, leading to a slow and frustrating user experience. But what if you could seamlessly defer these resources and boost your website's load speed? -ๆ—ฅๆœฌไบบใฎใฏใ“ใกใ‚‰ใฎ่จ˜ไบ‹ใ‚’ๅ‚่€ƒใซใ—ใฆใ„ใŸใ ใ‘ใ‚Œใฐๅนธใ„ใงใ™ใ€‚ - -- ใ‚ขใ‚ฟใƒซใ•ใ‚“ใฎ[Defer.js ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆ ๏ผˆๆ—ฅๆœฌ่ชž่จณ๏ผ‰](https://blog.gadgets-geek.net/2023/02/deferjs-doc-japanese.html) -- ใ‚ใƒˆใ‚“ใ•ใ‚“ใฎ[่จ˜ไบ‹](https://www.heavy-peat.com/2022/02/defer.html) -- ใƒชใƒขใ‚นใ‚ญใ•ใ‚“ใฎ[่จ˜ไบ‹](https://www.limosuki.com/2022/06/twitter-lazyload-deferjs.html) - -#### Credits - -I would like to express warm thanks to [@Ataruchi](https://twitter.com/Ataruchi), [@HeavyPeat](https://twitter.com/HeavyPeat) and [Limosuki](https://www.limosuki.com/) for their articles in Japanese. - -*** +By utilizing Defer.js, you can bid farewell to these issues! With its lazy loading capabilities, dependency-free design, lightning-fast performance, and hard-won experience, Defer.js is the ultimate solution for optimizing your website's Web Vitals. Whether you're using a modern or legacy browser, Defer.js makes it a breeze to enhance your website's user experience with blazing-fast loading times. ## Why Choose Defer.js -- ๐Ÿงฉ Lazy load almost anything with ease -- ๐Ÿš€ Lightweight and fast, with no dependencies -- ๐Ÿค Effortlessly integrates with your favorite frameworks +- ๐Ÿงฉ Effortlessly lazy load almost anything - ๐Ÿ”ฐ Easy to use, even for beginners +- ๐Ÿš€ Lightweight and blazingly fast, with no dependencies - โšก๏ธ Super tiny (minzipped size is around 1KB) +- ๐Ÿค Seamlessly integrates with your favorite frameworks - ๐Ÿฆพ Optimized for the latest Web Vitals standards - ๐Ÿ“ฑ Optimized for use on smartphones -- โœ… Supports legacy browsers like Internet Explorer 9 +- โœ… Supports legacy browsers like Internet Explorer 9 [(*)](#browser-support) -*Legacy browsers like Internet Explorer 9 require `IntersectionObserver` polyfill. +## Contributing -## Browser Support +[![NPM](https://nodei.co/npm/@shinsenter/defer.js.png?downloads=true)](https://www.npmjs.com/package/@shinsenter/defer.js) -Defer.js is compatible with all modern browsers, including: -- ๐Ÿ–ฅ IE9+ / Edge -- ๐Ÿ–ฅ Firefox 4+ -- ๐Ÿ–ฅ Safari 3+ -- ๐Ÿ–ฅ Chrome -- ๐Ÿ–ฅ Opera -- ๐Ÿ“ฑ Android 4+ -- ๐Ÿ“ฑ iOS 3.2+ +- **Package**: [@shinsenter/defer.js](https://www.npmjs.com/package/@shinsenter/defer.js) +- **Version**: 3.8.0 +- **Author**: Mai Nhut Tan +- **Copyright**: 2019-2024 SHIN Company +- **License**: [MIT](https://code.shin.company/defer.js/blob/master/LICENSE) ---- +If you find the project useful, please give it a star or consider donating via [PayPal](https://www.paypal.me/shinsenter). +You can also [open a discussion](https://github.com/shinsenter/defer.js/discussions/new/choose) on Github if you have any idea to improve the library. -## Known issues +[![Donate via PayPal](https://img.shields.io/badge/Donate-Paypal-blue)](https://www.paypal.me/shinsenter) [![Become a Stargazer](https://img.shields.io/badge/Become-Stargazer-yellow)](https://code.shin.company/defer.js/stargazers) [![Report an issue](https://img.shields.io/badge/New-Discussions-green)](https://code.shin.company/defer.js/discussions/new/choose) -- [Discussion #122](https://code.shin.company/defer.js/discussions/122): -In iOS Safari, the first `click` event may not work when using `Defer.all()` with the `waitForUserAction` argument set to `true` and one of deferred scripts make a DOM change. +Your support helps maintain and improve these project for the community. + +I appreciate you respecting my intellectual efforts in creating this library. +If you intend to copy or use ideas from this project, please give proper credit. --- -## Getting started +## Getting Started Defer.js is an easy-to-use library that will help boost your website's performance by reducing loading times. Here's how to get started: @@ -95,15 +63,15 @@ Add the Defer.js library to your page by including a ` + ``` -### Inlining the library +### Inlining the Library -To save an HTTP request, you can even inline the entire Defer.js library by copying its content from the [defer.min.js](https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@3.7.0/dist/defer.min.js) and replacing the comments in the script tag with its content. +To save an HTTP request, you can even inline the entire Defer.js library by copying its content from the [defer.min.js](https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@3.8.0/dist/defer.min.js) and replacing the comments in the script tag with its content. ```html @@ -117,9 +85,9 @@ To save an HTTP request, you can even inline the entire Defer.js library by copy ``` -### Compatibility with older versions +### Compatibility with Older Versions -If you're using an older version of Defer.js, you can use `defer_plus.min.js` instead of `defer.min.js`. +If you're using Defer.js v1.x, you can use `defer_plus.min.js` instead of `defer.min.js` without wondering about migrations. ```html @@ -127,13 +95,13 @@ If you're using an older version of Defer.js, you can use `defer_plus.min.js` in My Awesome Page - + ``` -### For OLD browsers (such as IE9) +### For OLD Browsers (such as IE9) To enhance performance for legacy browsers that don't support the `IntersectionObserver` feature, you can load the IntersectionObserver polyfill library after the `defer.min.js` script tag. @@ -141,17 +109,16 @@ To enhance performance for legacy browsers that don't support the `IntersectionO - + ``` *NOTE*: Modern browsers support the `IntersectionObserver` feature, so you don't have to worry about adding the polyfill if you don't have legacy browsers in mind. --- - ## Functions * [Defer(func, [delay], [waitForUserAction])](#Defer) โ‡’ void - * [.lazy](#Defer.lazy) : boolean + * [.lazy](#Defer.lazy) : boolean \| number * [.all([selector], [delay], [waitForUserAction])](#Defer.all) โ‡’ void * [.dom([selector], [delay], [unveiledClass], [resolver], [observeOptions])](#Defer.dom) โ‡’ void * [.css(fileUrl, [id_or_attributes], [delay], [onload], [waitForUserAction])](#Defer.css) โ‡’ void @@ -172,22 +139,22 @@ To enhance performance for legacy browsers that don't support the `IntersectionO ## Defer(func, [delay], [waitForUserAction]) โ‡’ void -Heavy DOM manipulations may cause render-blocking issues in real scenarios. -Wrapping your script with `Defer()` may help your website prevent render-blocking issues. +Heavy DOM manipulations can cause render-blocking issues in real-world scenarios. +Wrapping your script with `Defer()` may help prevent render-blocking issues on your website. **Kind**: global function **Since**: 2.0 | Param | Type | Default | Description | | --- | --- | --- | --- | -| func | function | | A function to be executed after page fully loaded. | -| [delay] | number | 0 | A timespan, in milliseconds, that the page should wait before the function is executed. | -| [waitForUserAction] | boolean | false | This argument tells `Defer()` to delay the execution and wait until there is a user interaction. | +| func | function | | A function to be executed after the page is fully loaded. | +| [delay] | number | 0 | A timespan, in milliseconds, that the page should wait before executing the function. | +| [waitForUserAction] | boolean \| number | false | This argument tells `Defer()` to delay execution and wait until there is a user interaction. | **Example** -jQuery is used in this example to perform some DOM manipulations. -This will attach `
` blocks to the document -as soon as the page finished loading. +This example uses jQuery to perform some DOM manipulations. +It will attach `
` blocks to the document +as soon as the page finishes loading. ```html ``` **Example** -Sometimes, you would like your code not to run unless there is user activity. +Sometimes, you may want your code to run only when there is user activity. -The third argument tells `Defer()` to delay the execution of the function +The third argument tells `Defer()` to delay executing the function and wait until the user starts interacting with your page. ```html @@ -232,7 +199,7 @@ and wait until the user starts interacting with your page. ``` * [Defer(func, [delay], [waitForUserAction])](#Defer) โ‡’ void - * [.lazy](#Defer.lazy) : boolean + * [.lazy](#Defer.lazy) : boolean \| number * [.all([selector], [delay], [waitForUserAction])](#Defer.all) โ‡’ void * [.dom([selector], [delay], [unveiledClass], [resolver], [observeOptions])](#Defer.dom) โ‡’ void * [.css(fileUrl, [id_or_attributes], [delay], [onload], [waitForUserAction])](#Defer.css) โ‡’ void @@ -244,32 +211,43 @@ and wait until the user starts interacting with your page. -### Defer.lazy : boolean +### Defer.lazy : boolean \| number The `Defer.lazy` variable was added since v3.0. -Setting `Defer.lazy=true` tells the library to delay the execution -of deferred scripts until the user starts interacting with the page +Setting `Defer.lazy=true` tells the library to delay executing +deferred scripts until the user starts interacting with the page, regardless of the page load event. -It will override the default behavior of `waitForUserAction` -argument of the `Defer()` method. - -Changing this variable will also affect the behavior of these functions: -- [Defer.all()](#Defer.all) -- [Defer.css()](#Defer.css) -- [Defer.js()](#Defer.js) +Changing this variable will also affect the default value +of the `waitForUserAction` argument in these functions: +- [`Defer()`](#Defer) +- [`Defer.all()`](#Defer.all) +- [`Defer.css()`](#Defer.css) +- [`Defer.js()`](#Defer.js) **Kind**: static property of [Defer](#Defer) **Default**: (not set) **Access**: public **Since**: 3.0 **Example** -To override the default behavior of the `Defer()` method. +To override the default behavior of the `Defer()` method: ```html ``` +**Example** +You can set a timeout period in milliseconds for the `Defer.lazy` +variable or any `waitForUserAction` argument. +If no user interaction occurs within this timeout period, the scripts will still execute. + +```html + + +``` + +This feature was added since v3.8.0. +View some use cases in [this discussion](https://github.com/shinsenter/defer.js/discussions/131#discussioncomment-8775870). * * * @@ -277,39 +255,43 @@ To override the default behavior of the `Defer()` method. ### Defer.all([selector], [delay], [waitForUserAction]) โ‡’ void Slow scripts (third-party libraries, add-ons, widgets, etc.) -may cause [Web Vitals](https://web.dev/vitals/) issues in real scenarios. +may cause [Web Vitals](https://web.dev/vitals/) issues in real-world scenarios. -Fully deferring ` ``` **Example** -Using the `Defer.all()` method for script tags with `src` attribute: +Using the `Defer.all()` method for script tags with the `src` attribute: Your scripts will work perfectly when you mix inline scripts -and script tags with an src attribute, like the below example. +and script tags with a `src` attribute, like the example below. The `waitForUserAction` argument (the fifth argument) is set to `true`, -the library will defer the load of the tippy.js library until the user starts -interacting, when the user moves his/her mouse on the button, a tooltip will show. +the library will defer loading the tippy.js library until the user starts +interacting. When the user moves their mouse over the button, a tooltip will show. Notice: To avoid unexpected behavior when using -the `Defer.all()` method to delay the execution of script tags, -you should call run the `Defer.all()` method with a regular script tag. - +the `Defer.all()` method to delay executing script tags, +you should call the `Defer.all()` method with a regular script tag. ```html @@ -388,30 +369,30 @@ you should call run the `Defer.all()` method with a regular script tag. ### Defer.dom([selector], [delay], [unveiledClass], [resolver], [observeOptions]) โ‡’ void -The `Defer.dom()` method is useful in the below use cases: +The `Defer.dom()` method is useful in the following use cases: - Lazy loading images, media, iframe tags, etc. on your website. -- Prevent downloading third-party libraries or add-ons unless they are needed. -- Scroll-reveal features, such as handling AJAX updating when a block is entering the viewport. -- An element that was deferred by Defer.dom() will be unveiled as soon as the page finished loading. +- Preventing the download of third-party libraries or add-ons unless they are needed. +- Scroll-reveal features, such as handling AJAX updates when a block enters the viewport. +- An element deferred by `Defer.dom()` will be unveiled as soon as the page finishes loading. -An element that was deferred by the `Defer.dom()` method will be unveiled -when it going to enters the browser viewport. +An element deferred by the `Defer.dom()` method will be unveiled +when it is about to enter the browser viewport. The `Defer.dom()` method also converts `data-*` attributes of the elements -into non-data attributes (e.g. from `data-src` to `src`). +into non-data attributes (e.g., from `data-src` to `src`). -Please check out the below examples for more details. +Please check out the examples below for more details. **Kind**: static method of [Defer](#Defer) **Since**: 2.0 | Param | Type | Default | Description | | --- | --- | --- | --- | -| [selector] | string | "[data-src]" | A CSS selector selects target HTML elements that will be unveiled later. | -| [delay] | number | 0 | A timespan, in milliseconds, that the page should wait before lazy loading is applied for target elements. | +| [selector] | string | "[data-src]" | A CSS selector that selects target HTML elements that will be unveiled later. | +| [delay] | number | 0 | A timespan, in milliseconds, that the page should wait before applying lazy loading to target elements. | | [unveiledClass] | string | | Class names that will be added to target elements when they are unveiled. | -| [resolver] | [NodeHandler](#NodeHandler) | | A [NodeHandler](#NodeHandler) will check a [Node](#Node) to determine if it will be unveiled or not. If the `resolver()` callback returns `false`, the node will not be unveiled. | +| [resolver] | [NodeHandler](#NodeHandler) | | A [NodeHandler](#NodeHandler) that will check a [Node](#Node) to determine if it will be unveiled or not. If the `resolver()` callback returns `false`, the node will not be unveiled. | | [observeOptions] | object | | [Intersection observer options](https://developer.mozilla.org/docs/Web/API/Intersection_Observer_API#Intersection_observer_options) | **Example** @@ -447,7 +428,7 @@ a very small placeholder image before the real image gets downloaded. ``` **Example** -Lazy load a responsive image with `data-srcset` and `data-sizes` attributes. +Lazy loading a responsive image with `data-srcset` and `data-sizes` attributes. Using the `srcset` attribute has made [responsive image](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images) @@ -456,9 +437,8 @@ It allows you to define a list of differently-sized versions of the same image, and provide information about the size of each one. Then, the client (browser) gets to make the decision. -We can also use the same trick as the above examples. -We specify an image URL set in -`data-srcset` and `data-sizes` attributes of the image tag. +We can also use the same trick as the above example. +We specify an image URL set in `data-srcset` and `data-sizes` attributes of the image tag. ```html
@@ -475,16 +455,12 @@ We specify an image URL set in ``` **Example** -Lazy load a responsive image with flexible format selection. +Lazy loading a responsive image with flexible format selection. Different browsers support different image formats. We might want to send a fancy new image format such as [WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types#webp_image) -to browsers that can render it, and fall back to trusty old JPEGs in browsers that donโ€™t. - -We can also use the same trick as the above examples for -[picture tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture), -and their children's HTML nodes. +to browsers that can render it, and fall back to trusty old JPEGs in browsers that can't. ```html
@@ -508,10 +484,10 @@ and their children's HTML nodes. ``` **Example** -Basic usage with adding CSS class. +Basic usage with adding CSS classes. The `Defer.dom()` method also allows you to add CSS class names when an element is unveiled. -In this example, we will add some CSS class names to make an `` tag animate. +In this example, we will add some CSS classes from Animate.css to make an `` tag animate. ```html
@@ -528,7 +504,7 @@ In this example, we will add some CSS class names to make an `` tag animate ``` **Example** -Lazy load inline CSS background images. +Lazy loading inline CSS background images. We can also defer background images for any HTML tag other than `` or ``. @@ -554,7 +530,7 @@ We can also defer background images for any HTML tag other than `` or ` ``` **Example** -Lazy load CSS background images. +Lazy loading CSS background images. Just another example of lazy loading background images for HTML tags, but we can also use CSS class names instead of inline `style` attributes. @@ -590,9 +566,9 @@ but we can also use CSS class names instead of inline `style` attributes. ``` **Example** -Lazy load a video. +Lazy loading a video. -With the `Defer.dom()` method, we can easily defer the load of various media tags, such as a `