SalakCode SalakCode
Performance

Lazy Loading

Load resources only when needed

Beginner
performance images code-splitting

Definition

Lazy loading is a design pattern that delays the loading of non-critical resources at page load time. Instead, these resources are loaded when they’re needed, such as when a user scrolls to them or interacts with a specific part of the page.

Native Lazy Loading

Images

<!-- Native lazy loading (modern browsers) -->
<img src="image.jpg" loading="lazy" alt="Description" width="800" height="600">

<!-- Eager loading for above-the-fold images -->
<img src="hero.jpg" loading="eager" alt="Hero" width="1200" height="600">

<!-- Lazy loading with responsive images -->
<picture>
  <source media="(min-width: 800px)" srcset="large.jpg">
  <source media="(min-width: 400px)" srcset="medium.jpg">
  <img src="small.jpg" loading="lazy" alt="Description" width="400" height="300">
</picture>

iframes

<!-- Lazy load YouTube videos, maps, etc. -->
<iframe 
  src="https://www.youtube.com/embed/VIDEO_ID" 
  loading="lazy"
  width="560" 
  height="315"
  title="YouTube video"
></iframe>

JavaScript Implementation

Intersection Observer Pattern

// Lazy load images with fallback
if ('loading' in HTMLImageElement.prototype) {
  // Browser supports native lazy loading
  const images = document.querySelectorAll('img[data-src]');
  images.forEach(img => {
    img.src = img.dataset.src;
    img.loading = 'lazy';
  });
} else {
  // Use Intersection Observer
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.removeAttribute('data-src');
        observer.unobserve(img);
      }
    });
  }, {
    rootMargin: '50px 0px', // Start loading 50px before visible
    threshold: 0.01
  });
  
  document.querySelectorAll('img[data-src]').forEach(img => {
    imageObserver.observe(img);
  });
}

Lazy Loading Components

// React lazy loading
import { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

// Vue lazy loading
const HeavyComponent = () => import('./HeavyComponent.vue');

Advanced Patterns

Progressive Image Loading

// Low-quality image placeholder (LQIP)
function ProgressiveImage({ src, placeholder, alt }) {
  const [imageSrc, setImageSrc] = useState(placeholder);
  const [isLoaded, setIsLoaded] = useState(false);
  
  useEffect(() => {
    const img = new Image();
    img.src = src;
    img.onload = () => {
      setImageSrc(src);
      setIsLoaded(true);
    };
  }, [src]);
  
  return (
    <img
      src={imageSrc}
      alt={alt}
      style={{
        filter: isLoaded ? 'none' : 'blur(10px)',
        transition: 'filter 0.3s'
      }}
    />
  );
}

Lazy Load on Interaction

// Load content on click/hover
function LazyLoadOnInteraction() {
  const [shouldLoad, setShouldLoad] = useState(false);
  
  return (
    <div>
      <button 
        onMouseEnter={() => setShouldLoad(true)}
        onClick={() => setShouldLoad(true)}
      >
        Show Content
      </button>
      
      {shouldLoad && (
        <Suspense fallback={<div>Loading...</div>}>
          <LazyContent />
        </Suspense>
      )}
    </div>
  );
}

Best Practices

Always Include Dimensions

<!-- Good: Prevents layout shift -->
<img 
  src="image.jpg" 
  loading="lazy" 
  width="800" 
  height="600"
  alt="Description"
>

<!-- Bad: Causes layout shift -->
<img src="image.jpg" loading="lazy" alt="Description">

Prioritize Critical Content

<!-- Load above-the-fold images immediately -->
<img src="hero.jpg" loading="eager" alt="Hero">

<!-- Lazy load below-the-fold content -->
<img src="gallery-1.jpg" loading="lazy" alt="Gallery 1">
<img src="gallery-2.jpg" loading="lazy" alt="Gallery 2">

Error Handling

function LazyImage({ src, alt, ...props }) {
  const [error, setError] = useState(false);
  
  if (error) {
    return <div className="image-error">Failed to load image</div>;
  }
  
  return (
    <img
      src={src}
      alt={alt}
      loading="lazy"
      onError={() => setError(true)}
      {...props}
    />
  );
}
Key Takeaway

Lazy loading improves initial page load by deferring non-critical resources. Use native lazy loading with the loading attribute, implement Intersection Observer for broader browser support, and always include image dimensions to prevent layout shifts. Lazy load images, iframes, and code for optimal performance.

Resources

Related Topics