Modern browsers natively support lazy loading with <img loading=lazy>
attribute. But if the page has layout shifts or no flexibility to specify the width and height for all images within the page, the browser will determine that a misplaced images are visible to the user and load them all, that will hurt the page's total performance.
Alpinejs is a powerful and simple front-end library which can be extended with a intersect plugin that will wrap Intersection Observer, simplifying how to react when an element enters the viewport.
Install
import Alpine from 'alpinejs'
import intersect from '@alpinejs/intersect'
window.Alpine = Alpine
Alpine.plugin(intersect)
Alpine.start()
Alpine Component
Create a component by add x-data
directive to div#lazy-loading-page
, a lot of other useful directives can be used on it's children. Directive x-intersect
can be added to any element within an Alpine component, and when that element enters the viewport (is scrolled into view), the provided expression to load images will execute.
<div x-data id="lazy-loading-page" class="h-full">
<section x-intersect.threshold.50="$refs.img1.src = $refs.img1.dataset.img" class="border-b-4 border-black p-8 h-full flex items-center justify-center">
<img
x-ref="img1"
class="opacity-0 transition-opacity duration-300 ease-linear"
src=""
data-img="https://via.placeholder.com/650x450"
onload="this.classList.add('opacity-100')"
/>
</section>
<section x-intersect.threshold.50="$refs.img2.src = $refs.img2.dataset.img" class="border-b-4 border-black p-8 h-full flex items-center justify-center">
<img
x-ref="img2"
class="opacity-0 transition-opacity duration-300 ease-linear"
src=""
data-img="https://via.placeholder.com/650x451"
onload="this.classList.add('opacity-100')"
/>
</section>
<section x-intersect.threshold.50="$refs.img3.src = $refs.img3.dataset.img" class="border-b-4 border-black p-8 h-full flex items-center justify-center">
<img
x-ref="img3"
class="opacity-0 transition-opacity duration-300 ease-linear"
src=""
data-img="https://via.placeholder.com/650x452"
onload="this.classList.add('opacity-100')"
/>
</section>
<section x-intersect.threshold.50="$refs.img4.src = $refs.img4.dataset.img" class="border-b-4 border-black p-8 h-full flex items-center justify-center">
<img
x-ref="img4"
class="opacity-0 transition-opacity duration-300 ease-linear"
src=""
data-img="https://via.placeholder.com/650x453"
onload="this.classList.add('opacity-100')"
/>
</section>
</div>
Within the code above, x-intersect
directive used with .threshold
modifier to control the threshold property of the underlying Intersection Observer. For example to trigger an intersection after half of the element has entered the page, .threshold.50
can be used, and that will execute expression $refs.img1.src = $refs.img1.dataset.img
to load the image.
Full HTML Code
Full JS Code
Working Example
Your feedback is much appreciated, thank you for reading.
Top comments (0)