Code this 💪, not that 💩. Learn how to use IntersectionObserver to lazy-load images efficiently in the browser without listening to the scroll event https://fireship.io/snippets/intersection-observer-lazy-load-images/


API https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
2024-02-04T07:01:24.448Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
2f5ad892-b0e8-4e73-a307-70dbe7a81623
144054062f96cf166c0c4c4f2ee065bd3aed417d01d60777ea045e4010459a49
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Welcome to another episode of Code This, Not That where we try to write the best code possible and avoid the bad stuff.
Today, we're going to look at Intersection Observer and how to determine the visibility of elements in the DOM.
This is a very useful tool because you can use it for things like infinite scroll, lazy loaded images, and animations.
In today's video we'll look at 2 different we can build out this lazy loaded image feature using nothing but vanilla JavaScript.
If you're new here, like and subscribe and grab the source code from Fireship IO.
I'll be giving away the first ever Fireship IO t shirt.
All you have to do is leave a comment below, and we'll pick a random winner next week.
Intersection Observer is a browser API that we can use to the visibility of an element in the viewport.
It's currently supported by most browsers, with the main exception being Safari.
But there is a polyfill that you can use as needed.
Actually use it on Fireship IO to lazy load the comments section.
The comments live in Firestore so this prevents unnecessary reads to the database.
Another thing you might notice on Fireship is that page transitions are super fast.
This is made possible in part by a library called Quick Link which uses Intersection Observer to preload all of the links that are visible on the page.
So there's all kinds of cool use cases, but let's go ahead and get started by writing some bad code.
What we have here is just a basic HTML page, and we have some high resolution images on it that we want to lazy load.
So when the user scrolls to an image, it will load it and then do this little CSS animation.
The CSS itself is pretty straightforward.
We start with an opacity of 0 and a transform and then we fade in by adding this fade class which sets the opacity to 1.
Then in the HTML, we'll go ahead and reference a script called app.js, and that'll be a deferred script.
And you'll notice with the images in this page that instead of having a source attribute, they have a data lazy attribute.
This is our own custom attribute that we can use to point to the image itself, and then we'll use our JavaScript to set it as the actual image Source when it becomes visible in the viewport.
The first thing we'll do is grab all of the images in the DOM by using query selector all.
Then we'll listen to the scroll event on the window.
And every time the user scrolls we'll be able to recalculate whether or not an element is visible.
After that, we can loop over each image and run the calculation.
The calculation is determined by the get bounding client rect value, so we'll be looking at the top of the element.
If the top of the element is less than or equal to the window inner height, Then we know that it's visible.
From there, we'll go ahead and read the data lazy attribute so we know the true source of the image.
And once we have that value, we'll just go ahead and call set attributes for the source.
And we'll also go ahead and add that fade class to run the animation.
So that code's actually very simple and it works, but it's also very inefficient and will very likely cause performance issues.
If we go back to the demo, you can see that I'm console pooping every time that calculation runs.
By the time we get to the bottom of the page, we've already taken over 3,000 console poops.
And not only that, but the event listener is still running even after all the images load.
So it's doing all the calculations for no reason in the background on the main thread.
Let's see how we can use Intersection Observer to clean up this mess.
We'll start with a function called lazy load that takes a DOM element as its argument.
Then we'll create an intersection observer for each image that we want to lazy load.
It has a callback function that has the entries which are the actual observations on the element and then observer is the interface that we can use to manage the actual instance of this observer.
Default, it will listen to the top level viewport on the document, but you can pass in an options object if you want to listen to a specific div or element.
This point, I want to make a note that you can use a single intersection observer to listen to multiple images.
But in this demo, I'm going to give each image its own observer and I'll show you why in just a minute.
The next step is to loop over the entries and see if any of them are intersecting with the viewport.
And fortunately, we don't have to do any of our own calculation.
We can just call EntryIsIntersecting which to return a boolean true or false.
However, there are situations where you probably wanna do some calculations here, so you have access to all of the bounding boxes for the elements.
From here, we need to get the actual image that has intersected with the window, which we can do by calling Entry Target.
And then we can run the same logic that we did in the previous example that adds attribute and the fade class.
Now, at this point, we know the image is visible, so we can dispose of the observer by calling observer disconnect.
Means we won't have any unnecessary work happening on the main thread like we did in the previous example.
And it's also why I set up an observer for each image.
The last thing we need to do in this function is call observe on the target element.
And then finally, we'll loop over all of the elements in the DOM and apply this observer to them.
When we reload the page, we get 7 console logs initially, which are for the 7 images on the page.
Then, as we scroll down, we'll start to intersect with the images and trigger additional console logs.
In total, our code only runs 13 times, which is much better than the 4,000 poops we took a few minutes ago.
I'm going to go ahead and wrap things up there.
If this video helped you, please like and subscribe, thanks for watching, and I will talk to you soon.

Speaker 0: Welcome to another episode of Code This, Not That where we try to write the best code possible and avoid the bad stuff. Today, we're going to look at Intersection Observer and how to determine the visibility of elements in the DOM. This is a very useful tool because you can use it for things like infinite scroll, lazy loaded images, and animations. In today's video we'll look at 2 different we can build out this lazy loaded image feature using nothing but vanilla JavaScript. If you're new here, like and subscribe and grab the source code from Fireship IO.

I'll be giving away the first ever Fireship IO t shirt. All you have to do is leave a comment below, and we'll pick a random winner next week. Intersection Observer is a browser API that we can use to the visibility of an element in the viewport. It's currently supported by most browsers, with the main exception being Safari. But there is a polyfill that you can use as needed.

Actually use it on Fireship IO to lazy load the comments section. The comments live in Firestore so this prevents unnecessary reads to the database. Another thing you might notice on Fireship is that page transitions are super fast. This is made possible in part by a library called Quick Link which uses Intersection Observer to preload all of the links that are visible on the page. So there's all kinds of cool use cases, but let's go ahead and get started by writing some bad code.

What we have here is just a basic HTML page, and we have some high resolution images on it that we want to lazy load. So when the user scrolls to an image, it will load it and then do this little CSS animation. The CSS itself is pretty straightforward. We start with an opacity of 0 and a transform and then we fade in by adding this fade class which sets the opacity to 1. Then in the HTML, we'll go ahead and reference a script called app.js, and that'll be a deferred script.

And you'll notice with the images in this page that instead of having a source attribute, they have a data lazy attribute. This is our own custom attribute that we can use to point to the image itself, and then we'll use our JavaScript to set it as the actual image Source when it becomes visible in the viewport. The first thing we'll do is grab all of the images in the DOM by using query selector all. Then we'll listen to the scroll event on the window. And every time the user scrolls we'll be able to recalculate whether or not an element is visible.

After that, we can loop over each image and run the calculation. The calculation is determined by the get bounding client rect value, so we'll be looking at the top of the element. If the top of the element is less than or equal to the window inner height, Then we know that it's visible. From there, we'll go ahead and read the data lazy attribute so we know the true source of the image. And once we have that value, we'll just go ahead and call set attributes for the source.

And we'll also go ahead and add that fade class to run the animation. So that code's actually very simple and it works, but it's also very inefficient and will very likely cause performance issues. If we go back to the demo, you can see that I'm console pooping every time that calculation runs. By the time we get to the bottom of the page, we've already taken over 3,000 console poops. And not only that, but the event listener is still running even after all the images load.

So it's doing all the calculations for no reason in the background on the main thread. Let's see how we can use Intersection Observer to clean up this mess. We'll start with a function called lazy load that takes a DOM element as its argument. Then we'll create an intersection observer for each image that we want to lazy load. It has a callback function that has the entries which are the actual observations on the element and then observer is the interface that we can use to manage the actual instance of this observer.

Default, it will listen to the top level viewport on the document, but you can pass in an options object if you want to listen to a specific div or element. This point, I want to make a note that you can use a single intersection observer to listen to multiple images. But in this demo, I'm going to give each image its own observer and I'll show you why in just a minute. The next step is to loop over the entries and see if any of them are intersecting with the viewport. And fortunately, we don't have to do any of our own calculation.

We can just call EntryIsIntersecting which to return a boolean true or false. However, there are situations where you probably wanna do some calculations here, so you have access to all of the bounding boxes for the elements. From here, we need to get the actual image that has intersected with the window, which we can do by calling Entry Target. And then we can run the same logic that we did in the previous example that adds attribute and the fade class. Now, at this point, we know the image is visible, so we can dispose of the observer by calling observer disconnect.

Means we won't have any unnecessary work happening on the main thread like we did in the previous example. And it's also why I set up an observer for each image. The last thing we need to do in this function is call observe on the target element. And then finally, we'll loop over all of the elements in the DOM and apply this observer to them. When we reload the page, we get 7 console logs initially, which are for the 7 images on the page.

Then, as we scroll down, we'll start to intersect with the images and trigger additional console logs. In total, our code only runs 13 times, which is much better than the 4,000 poops we took a few minutes ago. I'm going to go ahead and wrap things up there. If this video helped you, please like and subscribe, thanks for watching, and I will talk to you soon.
Welcome to another episode of Code This, Not That where we try to write the best code possible and avoid the bad stuff. Today, we're going to look at Intersection Observer and how to determine the visibility of elements in the DOM. This is a very useful tool because you can use it for things like infinite scroll, lazy loaded images, and animations. In today's video we'll look at 2 different we can build out this lazy loaded image feature using nothing but vanilla JavaScript. If you're new here, like and subscribe and grab the source code from Fireship IO.
visualization
animation
programming
I'll be giving away the first ever Fireship IO t shirt. All you have to do is leave a comment below, and we'll pick a random winner next week. Intersection Observer is a browser API that we can use to the visibility of an element in the viewport. It's currently supported by most browsers, with the main exception being Safari. But there is a polyfill that you can use as needed. Actually use it on Fireship IO to lazy load the comments section.
The comments live in Firestore so this prevents unnecessary reads to the database. Another thing you might notice on Fireship is that page transitions are super fast. This is made possible in part by a library called Quick Link which uses Intersection Observer to preload all of the links that are visible on the page.
websites
So there's all kinds of cool use cases, but let's go ahead and get started by writing some bad code. What we have here is just a basic HTML page, and we have some high resolution images on it that we want to lazy load. So when the user scrolls to an image, it will load it and then do this little CSS animation. The CSS itself is pretty straightforward. We start with an opacity of 0 and a transform and then we fade in by adding this fade class which sets the opacity to 1.
animation
graphic design
Then in the HTML, we'll go ahead and reference a script called app.js, and that'll be a deferred script. And you'll notice with the images in this page that instead of having a source attribute, they have a data lazy attribute.
This is our own custom attribute that we can use to point to the image itself, and then we'll use our JavaScript to set it as the actual image Source when it becomes visible in the viewport. The first thing we'll do is grab all of the images in the DOM by using query selector all.
photography
Then we'll listen to the scroll event on the window. And every time the user scrolls we'll be able to recalculate whether or not an element is visible. After that, we can loop over each image and run the calculation.
The calculation is determined by the get bounding client rect value, so we'll be looking at the top of the element. If the top of the element is less than or equal to the window inner height, Then we know that it's visible. From there, we'll go ahead and read the data lazy attribute so we know the true source of the image. And once we have that value, we'll just go ahead and call set attributes for the source. And we'll also go ahead and add that fade class to run the animation. So that code's actually very simple and it works, but it's also very inefficient and will very likely cause performance issues. If we go back to the demo, you can see that I'm console pooping every time that calculation runs.
animation
data
measurement
By the time we get to the bottom of the page, we've already taken over 3,000 console poops. And not only that, but the event listener is still running even after all the images load. So it's doing all the calculations for no reason in the background on the main thread. Let's see how we can use Intersection Observer to clean up this mess. We'll start with a function called lazy load that takes a DOM element as its argument.
Then we'll create an intersection observer for each image that we want to lazy load. It has a callback function that has the entries which are the actual observations on the element and then observer is the interface that we can use to manage the actual instance of this observer.
visualization
Default, it will listen to the top level viewport on the document, but you can pass in an options object if you want to listen to a specific div or element.
This point, I want to make a note that you can use a single intersection observer to listen to multiple images. But in this demo, I'm going to give each image its own observer and I'll show you why in just a minute. The next step is to loop over the entries and see if any of them are intersecting with the viewport.
visualization
And fortunately, we don't have to do any of our own calculation. We can just call EntryIsIntersecting which to return a boolean true or false. However, there are situations where you probably wanna do some calculations here, so you have access to all of the bounding boxes for the elements.
From here, we need to get the actual image that has intersected with the window, which we can do by calling Entry Target. And then we can run the same logic that we did in the previous example that adds attribute and the fade class. Now, at this point, we know the image is visible, so we can dispose of the observer by calling observer disconnect. Means we won't have any unnecessary work happening on the main thread like we did in the previous example. And it's also why I set up an observer for each image.
visualization
photography
The last thing we need to do in this function is call observe on the target element. And then finally, we'll loop over all of the elements in the DOM and apply this observer to them. When we reload the page, we get 7 console logs initially, which are for the 7 images on the page.
Then, as we scroll down, we'll start to intersect with the images and trigger additional console logs. In total, our code only runs 13 times, which is much better than the 4,000 poops we took a few minutes ago. I'm going to go ahead and wrap things up there. If this video helped you, please like and subscribe, thanks for watching, and I will talk to you soon.
youtube
video gaming
documentary
social media
television
media
Welcome to another episode of Code This, Not That where we try to write the best code possible and avoid the bad stuff. Today, we're going to look at Intersection Observer and how to determine the visibility of elements in the DOM. This is a very useful tool because you can use it for things like infinite scroll, lazy loaded images, and animations. In today's video we'll look at 2 different we can build out this lazy loaded image feature using nothing but vanilla JavaScript. If you're new here, like and subscribe and grab the source code from Fireship IO. I'll be giving away the first ever Fireship IO t shirt. All you have to do is leave a comment below, and we'll pick a random winner next week. Intersection Observer is a browser API that we can use to the visibility of an element in the viewport. It's currently supported by most browsers, with the main exception being Safari. But there is a polyfill that you can use as needed. Actually use it on Fireship IO to lazy load the comments section. The comments live in Firestore so this prevents unnecessary reads to the database. Another thing you might notice on Fireship is that page transitions are super fast. This is made possible in part by a library called Quick Link which uses Intersection Observer to preload all of the links that are visible on the page. So there's all kinds of cool use cases, but let's go ahead and get started by writing some bad code. What we have here is just a basic HTML page, and we have some high resolution images on it that we want to lazy load. So when the user scrolls to an image, it will load it and then do this little CSS animation. The CSS itself is pretty straightforward. We start with an opacity of 0 and a transform and then we fade in by adding this fade class which sets the opacity to 1. Then in the HTML, we'll go ahead and reference a script called app.js, and that'll be a deferred script. And you'll notice with the images in this page that instead of having a source attribute, they have a data lazy attribute. This is our own custom attribute that we can use to point to the image itself, and then we'll use our JavaScript to set it as the actual image Source when it becomes visible in the viewport. The first thing we'll do is grab all of the images in the DOM by using query selector all. Then we'll listen to the scroll event on the window. And every time the user scrolls we'll be able to recalculate whether or not an element is visible. After that, we can loop over each image and run the calculation. The calculation is determined by the get bounding client rect value, so we'll be looking at the top of the element. If the top of the element is less than or equal to the window inner height, Then we know that it's visible. From there, we'll go ahead and read the data lazy attribute so we know the true source of the image. And once we have that value, we'll just go ahead and call set attributes for the source. And we'll also go ahead and add that fade class to run the animation. So that code's actually very simple and it works, but it's also very inefficient and will very likely cause performance issues. If we go back to the demo, you can see that I'm console pooping every time that calculation runs. By the time we get to the bottom of the page, we've already taken over 3,000 console poops. And not only that, but the event listener is still running even after all the images load. So it's doing all the calculations for no reason in the background on the main thread. Let's see how we can use Intersection Observer to clean up this mess. We'll start with a function called lazy load that takes a DOM element as its argument. Then we'll create an intersection observer for each image that we want to lazy load. It has a callback function that has the entries which are the actual observations on the element and then observer is the interface that we can use to manage the actual instance of this observer. Default, it will listen to the top level viewport on the document, but you can pass in an options object if you want to listen to a specific div or element. This point, I want to make a note that you can use a single intersection observer to listen to multiple images. But in this demo, I'm going to give each image its own observer and I'll show you why in just a minute. The next step is to loop over the entries and see if any of them are intersecting with the viewport. And fortunately, we don't have to do any of our own calculation. We can just call EntryIsIntersecting which to return a boolean true or false. However, there are situations where you probably wanna do some calculations here, so you have access to all of the bounding boxes for the elements. From here, we need to get the actual image that has intersected with the window, which we can do by calling Entry Target. And then we can run the same logic that we did in the previous example that adds attribute and the fade class. Now, at this point, we know the image is visible, so we can dispose of the observer by calling observer disconnect. Means we won't have any unnecessary work happening on the main thread like we did in the previous example. And it's also why I set up an observer for each image. The last thing we need to do in this function is call observe on the target element. And then finally, we'll loop over all of the elements in the DOM and apply this observer to them. When we reload the page, we get 7 console logs initially, which are for the 7 images on the page. Then, as we scroll down, we'll start to intersect with the images and trigger additional console logs. In total, our code only runs 13 times, which is much better than the 4,000 poops we took a few minutes ago. I'm going to go ahead and wrap things up there. If this video helped you, please like and subscribe, thanks for watching, and I will talk to you soon.
Welcome
welcome
to
to
another
another
episode
episode
of
of
Code
code
This,
this
Not
not
That
that
where
where
we
we
try
try
to
to
write
write
the
the
best
best
code
code
possible
possible
and
and
avoid
avoid
the
the
bad
bad
stuff.
stuff
Today,
today
we're
we're
going
going
to
to
look
look
at
at
Intersection
intersection
Observer
observer
and
and
how
how
to
to
determine
determine
the
the
visibility
visibility
of
of
elements
elements
in
in
the
the
DOM.
dom
This
this
is
is
a
a
very
very
useful
useful
tool
tool
because
because
you
you
can
can
use
use
it
it
for
for
things
things
like
like
infinite
infinite
scroll,
scroll
lazy
lazy
loaded
loaded
images,
images
and
and
animations.
animations
In
in
today's
today's
video
video
we'll
we'll
look
look
at
at
2
2
different
different
we
we
can
can
build
build
out
out
this
this
lazy
lazy
loaded
loaded
image
image
feature
feature
using
using
nothing
nothing
but
but
vanilla
vanilla
JavaScript.
javascript
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe
subscribe
and
and
grab
grab
the
the
source
source
code
code
from
from
Fireship
fireship
IO.
io
I'll
i'll
be
be
giving
giving
away
away
the
the
first
first
ever
ever
Fireship
fireship
IO
io
t
t
shirt.
shirt
All
all
you
you
have
have
to
to
do
do
is
is
leave
leave
a
a
comment
comment
below,
below
and
and
we'll
we'll
pick
pick
a
a
random
random
winner
winner
next
next
week.
week
Intersection
intersection
Observer
observer
is
is
a
a
browser
browser
API
api
that
that
we
we
can
can
use
use
to
to
the
the
visibility
visibility
of
of
an
an
element
element
in
in
the
the
viewport.
viewport
It's
it's
currently
currently
supported
supported
by
by
most
most
browsers,
browsers
with
with
the
the
main
main
exception
exception
being
being
Safari.
safari
But
but
there
there
is
is
a
a
polyfill
polyfill
that
that
you
you
can
can
use
use
as
as
needed.
needed
Actually
actually
use
use
it
it
on
on
Fireship
fireship
IO
io
to
to
lazy
lazy
load
load
the
the
comments
comments
section.
section
The
the
comments
comments
live
live
in
in
Firestore
firestore
so
so
this
this
prevents
prevents
unnecessary
unnecessary
reads
reads
to
to
the
the
database.
database
Another
another
thing
thing
you
you
might
might
notice
notice
on
on
Fireship
fireship
is
is
that
that
page
page
transitions
transitions
are
are
super
super
fast.
fast
This
this
is
is
made
made
possible
possible
in
in
part
part
by
by
a
a
library
library
called
called
Quick
quick
Link
link
which
which
uses
uses
Intersection
intersection
Observer
observer
to
to
preload
preload
all
all
of
of
the
the
links
links
that
that
are
are
visible
visible
on
on
the
the
page.
page
So
so
there's
there's
all
all
kinds
kinds
of
of
cool
cool
use
use
cases,
cases
but
but
let's
let's
go
go
ahead
ahead
and
and
get
get
started
started
by
by
writing
writing
some
some
bad
bad
code.
code
What
what
we
we
have
have
here
here
is
is
just
just
a
a
basic
basic
HTML
html
page,
page
and
and
we
we
have
have
some
some
high
high
resolution
resolution
images
images
on
on
it
it
that
that
we
we
want
want
to
to
lazy
lazy
load.
load
So
so
when
when
the
the
user
user
scrolls
scrolls
to
to
an
an
image,
image
it
it
will
will
load
load
it
it
and
and
then
then
do
do
this
this
little
little
CSS
css
animation.
animation
The
the
CSS
css
itself
itself
is
is
pretty
pretty
straightforward.
straightforward
We
we
start
start
with
with
an
an
opacity
opacity
of
of
0
0
and
and
a
a
transform
transform
and
and
then
then
we
we
fade
fade
in
in
by
by
adding
adding
this
this
fade
fade
class
class
which
which
sets
sets
the
the
opacity
opacity
to
to
1.
1
Then
then
in
in
the
the
HTML,
html
we'll
we'll
go
go
ahead
ahead
and
and
reference
reference
a
a
script
script
called
called
app.js,
app.js
and
and
that'll
that'll
be
be
a
a
deferred
deferred
script.
script
And
and
you'll
you'll
notice
notice
with
with
the
the
images
images
in
in
this
this
page
page
that
that
instead
instead
of
of
having
having
a
a
source
source
attribute,
attribute
they
they
have
have
a
a
data
data
lazy
lazy
attribute.
attribute
This
this
is
is
our
our
own
own
custom
custom
attribute
attribute
that
that
we
we
can
can
use
use
to
to
point
point
to
to
the
the
image
image
itself,
itself
and
and
then
then
we'll
we'll
use
use
our
our
JavaScript
javascript
to
to
set
set
it
it
as
as
the
the
actual
actual
image
image
Source
source
when
when
it
it
becomes
becomes
visible
visible
in
in
the
the
viewport.
viewport
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
grab
grab
all
all
of
of
the
the
images
images
in
in
the
the
DOM
dom
by
by
using
using
query
query
selector
selector
all.
all
Then
then
we'll
we'll
listen
listen
to
to
the
the
scroll
scroll
event
event
on
on
the
the
window.
window
And
and
every
every
time
time
the
the
user
user
scrolls
scrolls
we'll
we'll
be
be
able
able
to
to
recalculate
recalculate
whether
whether
or
or
not
not
an
an
element
element
is
is
visible.
visible
After
after
that,
that
we
we
can
can
loop
loop
over
over
each
each
image
image
and
and
run
run
the
the
calculation.
calculation
The
the
calculation
calculation
is
is
determined
determined
by
by
the
the
get
get
bounding
bounding
client
client
rect
rect
value,
value
so
so
we'll
we'll
be
be
looking
looking
at
at
the
the
top
top
of
of
the
the
element.
element
If
if
the
the
top
top
of
of
the
the
element
element
is
is
less
less
than
than
or
or
equal
equal
to
to
the
the
window
window
inner
inner
height,
height
Then
then
we
we
know
know
that
that
it's
it's
visible.
visible
From
from
there,
there
we'll
we'll
go
go
ahead
ahead
and
and
read
read
the
the
data
data
lazy
lazy
attribute
attribute
so
so
we
we
know
know
the
the
true
true
source
source
of
of
the
the
image.
image
And
and
once
once
we
we
have
have
that
that
value,
value
we'll
we'll
just
just
go
go
ahead
ahead
and
and
call
call
set
set
attributes
attributes
for
for
the
the
source.
source
And
and
we'll
we'll
also
also
go
go
ahead
ahead
and
and
add
add
that
that
fade
fade
class
class
to
to
run
run
the
the
animation.
animation
So
so
that
that
code's
code's
actually
actually
very
very
simple
simple
and
and
it
it
works,
works
but
but
it's
it's
also
also
very
very
inefficient
inefficient
and
and
will
will
very
very
likely
likely
cause
cause
performance
performance
issues.
issues
If
if
we
we
go
go
back
back
to
to
the
the
demo,
demo
you
you
can
can
see
see
that
that
I'm
i'm
console
console
pooping
pooping
every
every
time
time
that
that
calculation
calculation
runs.
runs
By
by
the
the
time
time
we
we
get
get
to
to
the
the
bottom
bottom
of
of
the
the
page,
page
we've
we've
already
already
taken
taken
over
over
3,000
3,000
console
console
poops.
poops
And
and
not
not
only
only
that,
that
but
but
the
the
event
event
listener
listener
is
is
still
still
running
running
even
even
after
after
all
all
the
the
images
images
load.
load
So
so
it's
it's
doing
doing
all
all
the
the
calculations
calculations
for
for
no
no
reason
reason
in
in
the
the
background
background
on
on
the
the
main
main
thread.
thread
Let's
let's
see
see
how
how
we
we
can
can
use
use
Intersection
intersection
Observer
observer
to
to
clean
clean
up
up
this
this
mess.
mess
We'll
we'll
start
start
with
with
a
a
function
function
called
called
lazy
lazy
load
load
that
that
takes
takes
a
a
DOM
dom
element
element
as
as
its
its
argument.
argument
Then
then
we'll
we'll
create
create
an
an
intersection
intersection
observer
observer
for
for
each
each
image
image
that
that
we
we
want
want
to
to
lazy
lazy
load.
load
It
it
has
has
a
a
callback
callback
function
function
that
that
has
has
the
the
entries
entries
which
which
are
are
the
the
actual
actual
observations
observations
on
on
the
the
element
element
and
and
then
then
observer
observer
is
is
the
the
interface
interface
that
that
we
we
can
can
use
use
to
to
manage
manage
the
the
actual
actual
instance
instance
of
of
this
this
observer.
observer
Default,
default
it
it
will
will
listen
listen
to
to
the
the
top
top
level
level
viewport
viewport
on
on
the
the
document,
document
but
but
you
you
can
can
pass
pass
in
in
an
an
options
options
object
object
if
if
you
you
want
want
to
to
listen
listen
to
to
a
a
specific
specific
div
div
or
or
element.
element
This
this
point,
point
I
i
want
want
to
to
make
make
a
a
note
note
that
that
you
you
can
can
use
use
a
a
single
single
intersection
intersection
observer
observer
to
to
listen
listen
to
to
multiple
multiple
images.
images
But
but
in
in
this
this
demo,
demo
I'm
i'm
going
going
to
to
give
give
each
each
image
image
its
its
own
own
observer
observer
and
and
I'll
i'll
show
show
you
you
why
why
in
in
just
just
a
a
minute.
minute
The
the
next
next
step
step
is
is
to
to
loop
loop
over
over
the
the
entries
entries
and
and
see
see
if
if
any
any
of
of
them
them
are
are
intersecting
intersecting
with
with
the
the
viewport.
viewport
And
and
fortunately,
fortunately
we
we
don't
don't
have
have
to
to
do
do
any
any
of
of
our
our
own
own
calculation.
calculation
We
we
can
can
just
just
call
call
EntryIsIntersecting
entryisintersecting
which
which
to
to
return
return
a
a
boolean
boolean
true
true
or
or
false.
false
However,
however
there
there
are
are
situations
situations
where
where
you
you
probably
probably
wanna
wanna
do
do
some
some
calculations
calculations
here,
here
so
so
you
you
have
have
access
access
to
to
all
all
of
of
the
the
bounding
bounding
boxes
boxes
for
for
the
the
elements.
elements
From
from
here,
here
we
we
need
need
to
to
get
get
the
the
actual
actual
image
image
that
that
has
has
intersected
intersected
with
with
the
the
window,
window
which
which
we
we
can
can
do
do
by
by
calling
calling
Entry
entry
Target.
target
And
and
then
then
we
we
can
can
run
run
the
the
same
same
logic
logic
that
that
we
we
did
did
in
in
the
the
previous
previous
example
example
that
that
adds
adds
attribute
attribute
and
and
the
the
fade
fade
class.
class
Now,
now
at
at
this
this
point,
point
we
we
know
know
the
the
image
image
is
is
visible,
visible
so
so
we
we
can
can
dispose
dispose
of
of
the
the
observer
observer
by
by
calling
calling
observer
observer
disconnect.
disconnect
Means
means
we
we
won't
won't
have
have
any
any
unnecessary
unnecessary
work
work
happening
happening
on
on
the
the
main
main
thread
thread
like
like
we
we
did
did
in
in
the
the
previous
previous
example.
example
And
and
it's
it's
also
also
why
why
I
i
set
set
up
up
an
an
observer
observer
for
for
each
each
image.
image
The
the
last
last
thing
thing
we
we
need
need
to
to
do
do
in
in
this
this
function
function
is
is
call
call
observe
observe
on
on
the
the
target
target
element.
element
And
and
then
then
finally,
finally
we'll
we'll
loop
loop
over
over
all
all
of
of
the
the
elements
elements
in
in
the
the
DOM
dom
and
and
apply
apply
this
this
observer
observer
to
to
them.
them
When
when
we
we
reload
reload
the
the
page,
page
we
we
get
get
7
7
console
console
logs
logs
initially,
initially
which
which
are
are
for
for
the
the
7
7
images
images
on
on
the
the
page.
page
Then,
then
as
as
we
we
scroll
scroll
down,
down
we'll
we'll
start
start
to
to
intersect
intersect
with
with
the
the
images
images
and
and
trigger
trigger
additional
additional
console
console
logs.
logs
In
in
total,
total
our
our
code
code
only
only
runs
runs
13
13
times,
times
which
which
is
is
much
much
better
better
than
than
the
the
4,000
4,000
poops
poops
we
we
took
took
a
a
few
few
minutes
minutes
ago.
ago
I'm
i'm
going
going
to
to
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe,
subscribe
thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The host of a video on codes and websites explains how to use Intersection Qaeda to create a lazy loaded image feature in a page. The process involves writing code and using a browser API to access the image's visibility. The code is flexible and inefficient, but the results are promising.
Lazy-Loaded Images - Code This, Not That
Welcome to another episode of Code This, Not That where we try to write the best code possible and avoid the bad stuff. Today, we're going to look at Intersection Observer and how to determine the visibility of elements in the DOM. This is a very useful tool because you can use it for things like infinite scroll, lazy loaded images, and animations. In today's video we'll look at 2 different we can build out this lazy loaded image feature using nothing but vanilla JavaScript. If you're new here, like and subscribe and grab the source code from Fireship IO. I'll be giving away the first ever Fireship IO t shirt. All you have to do is leave a comment below, and we'll pick a random winner next week. Intersection Observer is a browser API that we can use to the visibility of an element in the viewport. It's currently supported by most browsers, with the main exception being Safari. But there is a polyfill that you can use as needed. Actually use it on Fireship IO to lazy load the comments section. The comments live in Firestore so this prevents unnecessary reads to the database. Another thing you might notice on Fireship is that page transitions are super fast. This is made possible in part by a library called Quick Link which uses Intersection Observer to preload all of the links that are visible on the page. So there's all kinds of cool use cases, but let's go ahead and get started by writing some bad code. What we have here is just a basic HTML page, and we have some high resolution images on it that we want to lazy load. So when the user scrolls to an image, it will load it and then do this little CSS animation. The CSS itself is pretty straightforward. We start with an opacity of 0 and a transform and then we fade in by adding this fade class which sets the opacity to 1. Then in the HTML, we'll go ahead and reference a script called app.js, and that'll be a deferred script. And you'll notice with the images in this page that instead of having a source attribute, they have a data lazy attribute. This is our own custom attribute that we can use to point to the image itself, and then we'll use our JavaScript to set it as the actual image Source when it becomes visible in the viewport. The first thing we'll do is grab all of the images in the DOM by using query selector all. Then we'll listen to the scroll event on the window. And every time the user scrolls we'll be able to recalculate whether or not an element is visible. After that, we can loop over each image and run the calculation. The calculation is determined by the get bounding client rect value, so we'll be looking at the top of the element. If the top of the element is less than or equal to the window inner height, Then we know that it's visible. From there, we'll go ahead and read the data lazy attribute so we know the true source of the image. And once we have that value, we'll just go ahead and call set attributes for the source. And we'll also go ahead and add that fade class to run the animation. So that code's actually very simple and it works, but it's also very inefficient and will very likely cause performance issues. If we go back to the demo, you can see that I'm console pooping every time that calculation runs. By the time we get to the bottom of the page, we've already taken over 3,000 console poops. And not only that, but the event listener is still running even after all the images load. So it's doing all the calculations for no reason in the background on the main thread. Let's see how we can use Intersection Observer to clean up this mess. We'll start with a function called lazy load that takes a DOM element as its argument. Then we'll create an intersection observer for each image that we want to lazy load. It has a callback function that has the entries which are the actual observations on the element and then observer is the interface that we can use to manage the actual instance of this observer. Default, it will listen to the top level viewport on the document, but you can pass in an options object if you want to listen to a specific div or element. This point, I want to make a note that you can use a single intersection observer to listen to multiple images. But in this demo, I'm going to give each image its own observer and I'll show you why in just a minute. The next step is to loop over the entries and see if any of them are intersecting with the viewport. And fortunately, we don't have to do any of our own calculation. We can just call EntryIsIntersecting which to return a boolean true or false. However, there are situations where you probably wanna do some calculations here, so you have access to all of the bounding boxes for the elements. From here, we need to get the actual image that has intersected with the window, which we can do by calling Entry Target. And then we can run the same logic that we did in the previous example that adds attribute and the fade class. Now, at this point, we know the image is visible, so we can dispose of the observer by calling observer disconnect. Means we won't have any unnecessary work happening on the main thread like we did in the previous example. And it's also why I set up an observer for each image. The last thing we need to do in this function is call observe on the target element. And then finally, we'll loop over all of the elements in the DOM and apply this observer to them. When we reload the page, we get 7 console logs initially, which are for the 7 images on the page. Then, as we scroll down, we'll start to intersect with the images and trigger additional console logs. In total, our code only runs 13 times, which is much better than the 4,000 poops we took a few minutes ago. I'm going to go ahead and wrap things up there. If this video helped you, please like and subscribe, thanks for watching, and I will talk to you soon.
The host of a video on codes and websites explains how to use Intersection Qaeda to create a lazy loaded image feature in a page. The process involves writing code and using a browser API to access the image's visibility. The code is flexible and inefficient, but the results are promising.