Skip to content

Commit dfda61a

Browse files
committed
1.2.0 release with video lazy loading.
1 parent 71dcefc commit dfda61a

File tree

8 files changed

+55
-19
lines changed

8 files changed

+55
-19
lines changed

README.md

+41-8
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,108 @@
33

44
[![Build Status](https://travis-ci.org/malchata/yall.js.svg?branch=master)](https://travis-ci.org/malchata/yall.js)
55

6-
yall.js is a very small image lazy loader for reasonably modern browsers (back to IE11) that weighs in at 1.1 KB uglified (650 bytes with gzip/545 bytes with Brotli). It depends on `classList`, `querySelectorAll`, and supports the `<picture>` element and `srcset`. yall.js will also use `IntersectionObserver` if available, but will fall back to more traditional means if it's not. If you want to try out yall.js, grab a copy from the releases tab. Or you can clone the repo and check out the `test` folder. If you want to tinker, work with the copy in the `src` folder and build using `npm run build` (requires `npx`).
6+
yall.js is a very small image and video lazy loader for reasonably modern browsers (back to IE11) that weighs in at 1.18 KB uglified (688 bytes with gzip/568 bytes with Brotli). It uses on `classList`, `querySelector`. It supports lazy loading `<img>` and `<picture>` with `src`/`srcset`, as well as `<video>`. yall.js will also use `IntersectionObserver` if available, but will fall back to throttled `scroll`/`resize` event handlers if it's not. If you want to try out yall.js, grab a copy from the releases tab. Or you can clone the repo and check out the `test` folder. If you want to tinker, work with the copy in the `src` folder and build using `npm run build` (requires `npx`).
77

88
## Usage Pattern
99

1010
yall.js assumes a lot, but because it does, it's very straightforward. Here's the simplest `<img>` element use case: Just add a class of `lazy` to an `<img>` element you want to lazy load, and point the `data-src` attribute to the desired image source:
1111

1212
```html
13+
<!-- Simple <img> example -->
1314
<img class="lazy" data-src="/img/image-to-lazy-load.jpg" src="/img/placeholder.jpg" alt="Alternative text to describe image.">
1415
```
1516

16-
An optional (but recommended) placeholder can be specified in the `src` attribute. This will be replaced by the lazy loader when the element is scrolled into view.
17+
An optional (but recommended) placeholder can be specified in the `src` attribute, which will be replaced by yall.js when the image is lazily loaded. If you go this route, be sure to specify `width` and `height` attributes to minimize layout shifting.
1718

1819
You can also use yall.js on `srcset` attributes, too:
1920

2021
```html
22+
<!-- A somewhat more complex <img> + srcset example -->
2123
<img class="lazy" data-srcset="/img/image-to-lazy-load-2x.jpg 2x, /img/image-to-lazy-load-1x.jpg 1x" data-src="/img/image-to-lazy-load-1x.jpg" src="/img/placeholder.jpg" alt="Alternative text to describe image.">
2224
```
2325

2426
You can use it on `<picture>` elements, too!
2527

2628
```html
29+
<!-- A more complex <picture> + <img> + srcset example -->
2730
<picture>
2831
<source data-srcset="/img/image-to-lazy-load.webp" type="image/webp">
2932
<source data-srcset="/img/image-to-lazy-load.jpg" type="image/jpeg">
3033
<img data-src="/img/image-to-lazy-load.jpg" src="/img/placeholder.jpg" class="lazy" alt="Alternative text to describe image.">
3134
</picture>
3235
```
3336

37+
And now as of the 1.2.0 release, you can use it on `<video>` elements! This is useful if you are replacing animated GIFs with autoplaying videos (which are usually much smaller).
38+
39+
```html
40+
<!-- Lazy load that video! -->
41+
<video class="lazy" autoplay loop muted>
42+
<source data-src="video.webm" type="video/webm">
43+
<source data-src="video.ogv" type="video/ogg">
44+
<source data-src="video.mp4" type="video/mp4">
45+
</video>
46+
```
47+
48+
The pattern is largely the same as it is with the `<picture>` use case, only the `lazy` class is applied to the `<video>` element. **Pro tip:** If you're embedding videos that don't emulate animated GIF behavior (i.e., non autoplaying video), it's probably best to lean on the `preload` attribute to defer loading rather than using yall.js. Read more about `preload` [in the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video).
49+
3450
## What about users without JavaScript?
3551

3652
Easy! Slap on some `<noscript>` goodness:
3753

3854
```html
55+
<!-- For users without JavaScript -->
3956
<img class="lazy" data-src="/img/image-to-lazy-load.jpg" src="/img/placeholder.jpg" alt="Alternative text to describe image.">
4057
<noscript>
4158
<img src="/img/image-to-lazy-load.jpg" alt="Alternative text to describe image.">
4259
</noscript>
60+
61+
<!-- Here's a <video> example, too -->
62+
<video class="lazy" autoplay loop muted>
63+
<source data-src="video.webm" type="video/webm">
64+
<source data-src="video.ogv" type="video/ogg">
65+
<source data-src="video.mp4" type="video/mp4">
66+
</video>
67+
<noscript>
68+
<video autoplay loop muted>
69+
<source src="video.webm" type="video/webm">
70+
<source src="video.ogv" type="video/ogg">
71+
<source src="video.mp4" type="video/mp4">
72+
</video>
73+
</noscript>
4374
```
4475

4576
Then place a `no-js` class on the `<html>` element, and finally add this JavaScript one-liner in the `<head>` of the document:
4677

4778
```html
79+
<!-- Remove the no-js class on the <html> element if JavaScript is on -->
4880
<script>document.documentElement.classList.remove("no-js");</script>
4981
```
5082

5183
This snippet will remove the `no-js` class from the `<html>` element as the page loads, but if JavaScript is turned off, this will never happen. From there, you can add some CSS that hides elements with a class of `lazy` when the `no-js` class is present on the `<html>` element:
5284

5385
```css
86+
/* Hide .lazy elements if JavaScript is off */
5487
.no-js .lazy{
5588
display: none;
5689
}
5790
```
5891

59-
To see everything in action, check out the demos in the `test` folder.
92+
To see all use cases in action, check out the demos in the `test` folder and go from there.
6093

6194
## Limitations
6295

63-
yall.js will only attach listeners to markup that has been sent by the server. Lazy-loaded markup injected into the DOM using this pattern will not be recognized. This makes yall.js just fine for the vast majority of use cases, but if you have some really complex stuff going on, you should find a more feature-rich lazy loader.
96+
yall.js will only attach listeners to markup sent by the server. Lazy-loaded markup injected into the DOM using this pattern will not be recognized. This makes yall.js just fine for the vast majority of use cases, but if you have really complex stuff going on (such as SPA environments), you should find a more feature-rich lazy loader. Eventually, I will modify yall.js to expose methods to destroy/init.
6497

65-
yall.js also doesn't try to guess at placeholder sizes to minimize layout shifting. I would *highly recommend* you specify a placeholder `src` in your `<img>` tags, or develop a CSS placeholder solution. For example, you could serve an extremely low quality version of an image that has a heavy gaussian blur effect. This technique signals to the user that an image will appear in that space, but doesn't push many extra bytes down the wire.
98+
yall.js also doesn't try to guess at placeholder sizes to minimize layout shifting. I would _highly recommend_ you specify a placeholder `src` in your `<img>` tags, or develop a CSS placeholder solution. For example, you could serve an extremely low quality version of an image that has a heavy gaussian blur effect. This technique signals to the user that an image will appear in that space, but doesn't push many extra bytes down the wire.
6699

67100
## Contributing
68101

69-
I'm not interested in expanding the functionality by much unless a good case can be made for increasing its performance without making it huge. The goal of yall.js is to be as small as reasonably possible while maintaining functionality.
102+
If you have an idea, file an issue and let's talk about it. Unsolicited pull requests for new features will generally be rejected, unless those requests contain bug fixes. Generally speaking, I want to avoid adding new features in lieu of keeping this library very, very small.
70103

71104
## Special thanks
72105

73-
Props to [Kamran Ayub](https://github.com/kamranayub) for his tremendous help with performance tuning this script, and to [Anthony Gore](https://twitter.com/anthonygore) for fixing an elusive bug in my intersection observer code where sometimes the last image on a page would not lazy load.
106+
Props to [Kamran Ayub](https://github.com/kamranayub) for his tremendous help with performance tuning this script, and to [Anthony Gore](https://twitter.com/anthonygore) for fixing an elusive bug in my `IntersectionObserver` code where sometimes the last image on a page would not lazy load.
74107

75108
## Why another dumb lazy loader?
76109

77-
I explain how to write a lazy loader in Chapter 6 of my book [Web Performance in Action](https://www.manning.com/books/web-performance-in-action?a_aid=webopt&a_bid=63c31090) from Manning Publications. Otherwise, I wouldn't have bothered. The lazy loader in the book is much different (and more improved!) than what you'll find here.
110+
I explain how to write a lazy loader in Chapter 6 of my book [Web Performance in Action](https://www.manning.com/books/web-performance-in-action?a_aid=webopt&a_bid=63c31090) from Manning Publications. Otherwise, I wouldn't have bothered. The lazy loader in the book is much different (and less powerful) than what you'll find here.

dist/yall-1.2.0.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/yall.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
// The handler to load the media
4141
loadMedia = function(media){
4242
if(media.tagName == "VIDEO"){
43-
media[qsa]("source")[fe](function(source){
43+
Array[pr].slice.call(media[qsa]("source"))[fe](function(source){
4444
replaceAttr(source, ds, s);
4545
});
4646

@@ -58,6 +58,7 @@
5858
}
5959

6060
media.classList.remove("lazy");
61+
6162
elements = elements.filter(function(e){
6263
return e !== media;
6364
});

test/index.html

+11-9
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
font-family: sans-serif;
1919
}
2020

21-
img{
21+
img,
22+
video{
2223
width: 100%;
24+
max-width: 100%;
2325
display: block;
2426
}
2527

@@ -88,16 +90,16 @@ <h2>Lazy loading <code>&lt;picture&gt;</code></h2>
8890
</noscript>
8991
<h2>Lazy loading <code>&lt;video&gt;</code></h2>
9092
<a name="video"></a>
91-
<video class="lazy" width="500" height="213" poster="https://res.cloudinary.com/drp9iwjqz/image/upload/f_auto,q_auto/v1508295315/jeremywagner.me/using-webp-images/bateman-1-placeholder.jpg" autoplay loop muted>
92-
<source data-src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.webm" type="video/webm">
93-
<source data-src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.ogv" type="video/ogg">
94-
<source data-src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.mp4" type="video/mp4">
93+
<video class="lazy" width="500" height="213" poster="video-placeholder.jpg" autoplay loop muted>
94+
<source data-src="test.webm" type="video/webm">
95+
<source data-src="test.ogv" type="video/ogg">
96+
<source data-src="test.mp4" type="video/mp4">
9597
</video>
9698
<noscript>
97-
<video width="500" height="213" poster="https://res.cloudinary.com/drp9iwjqz/image/upload/f_auto,q_auto/v1508295315/jeremywagner.me/using-webp-images/bateman-1-placeholder.jpg" autoplay loop muted>
98-
<source src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.webm" type="video/webm">
99-
<source src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.ogv" type="video/ogg">
100-
<source src="https://res.cloudinary.com/drp9iwjqz/video/upload/v1509066934/bateman_xrk1jh.mp4" type="video/mp4">
99+
<video width="500" height="213" poster="video-placeholder.jpg" autoplay loop muted>
100+
<source src="test.webm" type="video/webm">
101+
<source src="test.ogv" type="video/ogg">
102+
<source src="test.mp4" type="video/mp4">
101103
</video>
102104
</noscript>
103105
<script src="../dist/yall-1.2.0.min.js" defer></script>

test/test.mp4

32.8 KB
Binary file not shown.

test/test.ogv

74.4 KB
Binary file not shown.

test/test.webm

85.4 KB
Binary file not shown.

test/video-placeholder.jpg

2.67 KB
Loading

0 commit comments

Comments
 (0)