JavaScript Curriculum
Intersection Observer
mediumThe coffee shop menu has 50 item images that all load at once, slowing the page to a crawl. The specials section should animate in as users scroll down. Intersection Observer handles both — efficiently, with zero scroll listener overhead.
Intersection Observer
scroll event listeners fire hundreds of times per second — expensive and janky. The IntersectionObserver API is asynchronous and browser-optimized: it tells you when elements enter or leave the viewport without blocking the main thread.
How IntersectionObserver Works
Watch elements scroll into view — adjust the threshold to see how it changes when callbacks fire:
// Scroll the cards below
const io = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
entry.isIntersecting
? el.classList.add('visible')
: el.classList.remove('visible')
})
},
{ threshold: 0.5 }
)
io.observe(el)Lazy Loading Images
Load images only when they approach the viewport — classic IntersectionObserver use case:
// Scroll to lazy-load images
// rootMargin: '50px' loads
// slightly before visible
const io = new IntersectionObserver(
(entries) => entries.forEach(e => {
if (!e.isIntersecting) return
loadImage(e.target)
io.unobserve(e.target) // once!
}),
{ rootMargin: '50px', threshold: 0 }
)
imgs.forEach(img => io.observe(img))Scroll-Triggered Animations
Animate elements in as they scroll into view — one observer handles all cards:
.card {
opacity:0;
transform:translateY(30px)
transition: all 500ms ease;
}
.card.visible {
opacity:1;
transform:translateY(0)
}const io = new IntersectionObserver(
entries => entries.forEach(e => {
if (e.isIntersecting)
e.target.classList.add('visible')
}),
{ threshold: 0.2 }
)
cards.forEach(c => io.observe(c))Your Challenge
Select all .card elements and observe each one. On intersection (threshold: 0.2), add .visible class and unobserve. Add CSS for the initial hidden state and the .visible animated state. Use rootMargin: '0px 0px -50px 0px' to trigger animations slightly before the card fully enters the viewport.
Challenge
Observe all .card elements. When a card enters the viewport (threshold: 0.2), add a 'visible' class and unobserve it. Add CSS: .card { opacity: 0; transform: translateY(20px); transition: all 400ms; } .card.visible { opacity: 1; transform: none; }
Intersection Observer
mediumThe coffee shop menu has 50 item images that all load at once, slowing the page to a crawl. The specials section should animate in as users scroll down. Intersection Observer handles both — efficiently, with zero scroll listener overhead.
Intersection Observer
scroll event listeners fire hundreds of times per second — expensive and janky. The IntersectionObserver API is asynchronous and browser-optimized: it tells you when elements enter or leave the viewport without blocking the main thread.
How IntersectionObserver Works
Watch elements scroll into view — adjust the threshold to see how it changes when callbacks fire:
// Scroll the cards below
const io = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
entry.isIntersecting
? el.classList.add('visible')
: el.classList.remove('visible')
})
},
{ threshold: 0.5 }
)
io.observe(el)Lazy Loading Images
Load images only when they approach the viewport — classic IntersectionObserver use case:
// Scroll to lazy-load images
// rootMargin: '50px' loads
// slightly before visible
const io = new IntersectionObserver(
(entries) => entries.forEach(e => {
if (!e.isIntersecting) return
loadImage(e.target)
io.unobserve(e.target) // once!
}),
{ rootMargin: '50px', threshold: 0 }
)
imgs.forEach(img => io.observe(img))Scroll-Triggered Animations
Animate elements in as they scroll into view — one observer handles all cards:
.card {
opacity:0;
transform:translateY(30px)
transition: all 500ms ease;
}
.card.visible {
opacity:1;
transform:translateY(0)
}const io = new IntersectionObserver(
entries => entries.forEach(e => {
if (e.isIntersecting)
e.target.classList.add('visible')
}),
{ threshold: 0.2 }
)
cards.forEach(c => io.observe(c))Your Challenge
Select all .card elements and observe each one. On intersection (threshold: 0.2), add .visible class and unobserve. Add CSS for the initial hidden state and the .visible animated state. Use rootMargin: '0px 0px -50px 0px' to trigger animations slightly before the card fully enters the viewport.
Challenge
Observe all .card elements. When a card enters the viewport (threshold: 0.2), add a 'visible' class and unobserve it. Add CSS: .card { opacity: 0; transform: translateY(20px); transition: all 400ms; } .card.visible { opacity: 1; transform: none; }