DOM Reflow, Repaint & Browser Rendering Pipeline

    What You'll Learn in This Lesson

    • The browser's rendering pipeline steps
    • What causes reflow vs repaint
    • Layout thrashing and how to avoid it
    • GPU-accelerated animations with transform/opacity
    • DocumentFragment for batch DOM updates
    • Profiling with Chrome DevTools

    💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:

    • Download Node.js to run JavaScript on your computer
    • Use your browser's Developer Console (Press F12) to test code snippets
    • Create a .html file with <script> tags and open it in your browser

    Modern web performance starts with understanding how the browser actually turns your HTML, CSS, and JavaScript into pixels on the screen. This lesson reveals the rendering pipeline, reflow/repaint costs, and professional optimization techniques used by Meta, Google, Netflix, and Airbnb.

    🚀 Master Performance

    A single line of code—changing width, reading offsetHeight, or triggering layout—can destroy 60 FPS performance. Learn to write code that keeps your UI smooth even on low-power devices.

    🚀 The Browser Rendering Pipeline

    The browser doesn't magically draw pixels. It follows a detailed sequence every frame:

    1. HTML → DOM Tree

    Browser parses HTML and creates nodes representing every tag.

    2. CSS → CSSOM Tree

    Browser parses stylesheets, computes rules, builds CSS Object Model.

    3. Render Tree

    DOM + CSSOM merge into structure defining what's visible.

    4. Layout (Reflow) 🟥 EXPENSIVE

    Every visible element receives size, position, geometry, box model values.

    5. Paint (Repaint) 🟨 COSTLY

    Colors, borders, shadows, backgrounds, text are drawn.

    6. Compositing 🟩 FAST

    Layers are merged into final image on your screen (GPU-accelerated).

    ⚠️ Critical Understanding

    This entire cycle repeats every time something changes visually. A smooth 60 FPS requires all tasks to fit inside a 16.6ms frame budget!

    🟥 What Causes Reflow (Most Expensive)

    Reflow recalculates layout—the most expensive operation. Common triggers:

    • Changing element size: width, height
    • Changing margin, padding, border
    • Changing font-size
    • Adding/removing elements
    • Changing position, display, flex, grid
    • Setting scroll position
    • Querying layout properties (forced reflow)

    🔥 Forced Reflow Properties (Dangerous in Loops)

    element.offsetHeight
    element.offsetWidth
    element.scrollTop
    element.getBoundingClientRect()
    window.getComputedStyle(element)

    These force the browser to apply pending layout changes before returning a value!

    🟨 What Causes Repaint (Cheaper but Not Free)

    Repaint happens when appearance changes but geometry does not:

    • Changing color
    • Changing background-color
    • Changing visibility
    • Changing box-shadow
    • Changing outline
    div.style.backgroundColor = "red"; // repaint only, no layout

    🟩 Best Case: Compositor-Only Changes

    Using transform or opacity avoids both reflow and repaint. These changes happen on the GPU compositor thread—extremely fast!

    box.style.transform = "translateX(30px)";  
    box.style.opacity = "0.7";
    // No layout, no paint — just compositing

    ✅ Pro Tip

    This is why all modern animation libraries use transform and opacity. Always prefer these for smooth 60 FPS animations.

    🧨 Layout Thrashing: The Performance Killer

    Layout thrashing happens when you repeatedly mix layout reads and writes in the same execution cycle. This causes hundreds of reflows!

    Layout Thrashing Example

    See how to avoid the performance killer

    Try it Yourself »
    JavaScript
    // ❌ BAD: Layout thrashing
    function badResize(items) {
      for (let i = 0; i < items.length; i++) {
        // Forces layout read
        const width = items[i].offsetWidth;
        // Triggers layout write
        items[i].style.width = width + 5 + "px";
        // Repeat hundreds of times = disaster
      }
    }
    
    // ✅ GOOD: Batch reads, then batch writes
    function goodResize(items) {
      // Read all at once
      const widths = items.map(item => item.offsetWidth);
      
      // Write all at once
      items.forEach((item, i) => {
        item
    ...

    🎯 Golden Rule

    Batch all reads together, then batch all writes together. This avoids thrashing and reduces reflows massively.

    🎯 Efficient vs Inefficient Animations

    The difference between laggy and smooth animations often comes down to which properties you animate:

    Efficient Animations

    Compare laggy vs smooth animation techniques

    Try it Yourself »
    JavaScript
    // ❌ BAD: Triggers reflow every frame
    function animateBad(element) {
      setInterval(() => {
        element.style.left = element.offsetLeft + 2 + "px";
      }, 16);
    }
    
    // ✅ GOOD: Uses compositor (GPU)
    function animateGood(element) {
      let x = 0;
      
      function animate() {
        x += 2;
        element.style.transform = `translateX(${x}px)`;
        requestAnimationFrame(animate);
      }
      
      animate();
    }
    
    // Even better: with will-change
    const box = document.querySelector('.animate-box');
    box.style.willChange = 'tran
    ...

    Why transform is faster:

    • No recalculating of layout
    • No reflow triggered
    • Runs on GPU compositor thread
    • Main thread stays free for JavaScript

    🕹️ Real-World: Smooth Scroll Performance

    Scroll events fire hundreds of times per second. Without optimization, they destroy performance:

    Smooth Scroll Performance

    Optimize scroll handlers for 60 FPS

    Try it Yourself »
    JavaScript
    // ❌ BAD: Triggers layout on every scroll
    window.addEventListener('scroll', () => {
      const sidebar = document.querySelector('.sidebar');
      sidebar.style.top = window.scrollY + "px";
    });
    
    // ✅ GOOD: GPU-accelerated with throttle
    function throttle(fn, limit) {
      let inThrottle = false;
      return function(...args) {
        if (!inThrottle) {
          fn.apply(this, args);
          inThrottle = true;
          setTimeout(() => (inThrottle = false), limit);
        }
      };
    }
    
    const sidebar = document.querySelector('.s
    ...

    🔥 DocumentFragment: Batch DOM Changes

    When adding multiple elements, use DocumentFragment to avoid multiple reflows:

    DocumentFragment Batch Changes

    Batch DOM changes for better performance

    Try it Yourself »
    JavaScript
    // ❌ BAD: Multiple reflows
    function addItemsSlow(container, count) {
      for (let i = 0; i < count; i++) {
        const div = document.createElement('div');
        div.textContent = `Item ${i}`;
        container.appendChild(div); // reflow each time
      }
    }
    
    // ✅ GOOD: Single reflow with fragment
    function addItemsFast(container, count) {
      const fragment = document.createDocumentFragment();
      
      for (let i = 0; i < count; i++) {
        const div = document.createElement('div');
        div.textContent = `Item ${i}`
    ...

    🧬 Compositor Layers & GPU Acceleration

    Modern browsers split the page into layers. Certain properties automatically create a new layer:

    • CSS transform
    • CSS opacity
    • CSS will-change
    • Canvas, video, iframes
    • position: fixed in some scenarios

    Force GPU layer for animation:

    .box {
      will-change: transform;
    }
    
    // Now this runs on GPU:
    box.style.transform = "translateY(120px)";

    ⚠️ Warning

    Don't overuse will-change. Too many layers consume GPU memory. Only use on elements that actually animate frequently.

    🧠 Chrome DevTools Performance Debugging

    Professional engineers use these techniques to find performance bottlenecks:

    1. Performance Panel

    • Press F12 → Performance → Start Recording
    • Interact with your page
    • Stop recording
    • Look for large purple blocks (Layout) or green blocks (Paint)

    2. Enable Paint Flashing

    • Open DevTools
    • Press Ctrl+Shift+P
    • Search "Show paint flashing"
    • Your screen flashes green every time browser repaints

    3. Rendering → Layout Shift Regions

    Highlights areas causing layout shifts—essential for Core Web Vitals optimization.

    🏁 Professional Performance Checklist

    Follow this checklist to achieve near-professional performance:

    ✅ Always Do

    • Use transform and opacity for animations
    • Batch DOM reads before writes
    • Use requestAnimationFrame for visual updates
    • Throttle/debounce high-frequency events
    • Use IntersectionObserver for lazy loading
    • Promote animating elements with will-change

    ❌ Never Do

    • Animate top, left, width, height
    • Query layout inside loops
    • Mix reads and writes in same cycle
    • Use complex CSS selectors
    • Poll layout with setInterval
    • Add elements one-by-one in loops

    🎓 Practice Challenges

    Challenge 1: Fix the Laggy Slider

    Optimize this mousemove slider to use transforms and throttling for 60 FPS performance.

    slider.addEventListener("mousemove", () => {
      handle.style.left = event.clientX + "px";
    });

    Challenge 2: Optimize Infinite Scroll

    Refactor an infinite scroll implementation to use DocumentFragment and IntersectionObserver instead of scroll events and individual DOM appends.

    Challenge 3: Parallax Without Jank

    Create a smooth parallax scrolling effect using transforms and requestAnimationFrame that maintains 60 FPS even on mobile devices.

    🎯 Key Takeaways

    • The browser rendering pipeline has 6 stages: DOM → CSSOM → Render Tree → Layout → Paint → Compositing
    • Reflow (layout) is the most expensive operation—avoid changing layout properties in animations
    • Layout thrashing occurs when mixing reads and writes—always batch reads before writes
    • Use transform and opacity for animations—they run on GPU compositor thread
    • Throttle/debounce high-frequency events like scroll, resize, and mousemove
    • Use Chrome DevTools Performance panel and Paint Flashing to identify bottlenecks
    • DocumentFragment batches DOM changes to avoid multiple reflows
    • Professional performance = understanding what your code does to the rendering pipeline

    📋 Quick Reference

    ConceptImpact
    ReflowExpensive — recalculates layout geometry
    RepaintCheaper — redraws pixels without layout
    transform/opacityGPU-accelerated, no reflow
    offsetWidthForces layout — use sparingly
    DocumentFragmentBatch DOM changes into one reflow

    Lesson Complete!

    You now understand the full browser rendering pipeline and how to write code that keeps UIs smooth at 60 FPS.

    Up next: Virtual DOM Concepts — learn how React and modern frameworks avoid unnecessary DOM updates.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service