Skip to content
intermediatePhase 34 · DOM

Repaint

Understand repaint cycles and optimize for smooth visual updates.

30m
0 problems
Topic Progress0%

What is Repaint

Repaint (also called redraw) happens when visual changes occur that don't affect layout. The browser redraws affected pixels.

Layout vs Repaint

// Layout (Reflow): Geometry changes
// - Triggers reflow + repaint
element.style.width = '100px';
element.style.position = 'absolute';
element.style.margin = '10px';

// Repaint only: Visual changes
// - Triggers repaint only (no layout)
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.boxShadow = '0 0 5px black';
element.style.opacity = '0.5';
element.style.visibility = 'hidden';

What Triggers Repaint

// Color changes
element.style.color = 'red';
element.style.backgroundColor = '#fff';
element.style.borderColor = 'blue';

// Visibility
element.style.visibility = 'hidden';
element.style.opacity = '0.5';
element.style.display = 'none'; // Also triggers reflow!

// Shadows
element.style.boxShadow = '0 0 5px black';
element.style.textShadow = '1px 1px 2px black';

// Backgrounds
element.style.backgroundImage = 'url(...)';
element.style.backgroundGradient = 'linear-gradient(...)';
element.style.backgroundSize = 'cover';

// Borders
element.style.borderWidth = '2px';
element.style.borderStyle = 'solid';
element.style.borderRadius = '5px';

// Text
element.style.fontSize = '16px'; // May trigger reflow
element.style.fontWeight = 'bold';
element.textContent = 'New text'; // May trigger reflow

What Doesn't Trigger Repaint

// transform: composite only
element.style.transform = 'translateX(100px)';
element.style.transform = 'rotate(45deg)';
element.style.transform = 'scale(1.5)';

// opacity: may composite
element.style.opacity = '0.5'; // Can be composited

// will-change: promotes to layer
.element { will-change: transform; }

Repaint Triggers

Different types of changes trigger different levels of work.

Change Categories

┌─────────────────────────────────────────────────┐
│                  Change Type                    │
├─────────────────────────────────────────────────┤
│ Layout + Paint + Composite                      │
│ - width, height, position, margin, padding     │
│ - display, font-size, float                    │
│ - border, box-sizing                           │
├─────────────────────────────────────────────────┤
│ Paint + Composite (no layout)                   │
│ - color, background-color                      │
│ - visibility, opacity                          │
│ - box-shadow, text-shadow                      │
│ - border-color, border-style                   │
│ - background-image                             │
├─────────────────────────────────────────────────┤
│ Composite only (no layout, no paint)            │
│ - transform                                    │
│ - opacity (GPU-composited)                     │
│ - will-change                                  │
└─────────────────────────────────────────────────┘

Performance Impact

// Layout: Most expensive
// - Recalculates geometry
// - Invalidates paint
// - May trigger repaint

element.style.width = '100px'; // Layout + Paint

// Paint: Medium expensive
// - Fills in pixels
// - Can be expensive for large areas
element.style.color = 'red'; // Paint only

// Composite: Cheapest
// - Combines layers
// - GPU-accelerated

element.style.transform = 'translateX(100px)'; // Composite only

Identifying Repaints

// Chrome DevTools: Rendering tab
// - Enable 'Paint flashing' (green overlay)
// - Shows areas being repainted

// Chrome DevTools: Performance tab
// - Record performance
// - Look for 'Paint' events
// - Check duration

// Performance.now() for timing
const start = performance.now();
// ... changes ...
const end = performance.now();
console.log(`Took ${end - start}ms`);

Example: Hover Effect

// BAD: Triggers layout + paint
element.addEventListener('mouseenter', () => {
  element.style.width = '120px';   // Layout
  element.style.padding = '20px';  // Layout
  element.style.color = 'red';     // Paint
});

// BETTER: Paint only
element.addEventListener('mouseenter', () => {
  element.style.color = 'red';     // Paint
  element.style.boxShadow = '0 0 10px red'; // Paint
});

// BEST: Composite only
element.addEventListener('mouseenter', () => {
  element.style.transform = 'scale(1.1)'; // Composite
  element.style.opacity = '0.9'; // Composite
});

Performance Tips

Tips to minimize repaints and improve rendering performance.

1. Use transform Instead of top/left

// BAD: Triggers layout + paint
element.style.top = '100px';
element.style.left = '100px';

// BEST: Composite only
element.style.transform = 'translate(100px, 100px)';

2. Use opacity Instead of visibility

// BAD: Triggers repaint
element.style.visibility = 'hidden';

// BETTER: Can be composited
element.style.opacity = '0';

3. Promote to Compositor Layer

/* Use will-change for animated elements */
.animated {
  will-change: transform, opacity;
}

/* But don't overuse! */
.animated:hover {
  will-change: transform; /* Bad! */
}

4. Batch Style Changes

// BAD: Multiple repaints
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.boxShadow = '0 0 5px black';

// BETTER: Single repaint
element.style.cssText = 'color: red; background: blue; box-shadow: 0 0 5px black;';

// OR: Use CSS class
.element.modified {
  color: red;
  background: blue;
  box-shadow: 0 0 5px black;
}
element.classList.add('modified');

5. Use CSS Containment

/* Tell browser to isolate changes */
.container {
  contain: layout style paint;
}

/* Types of containment:
 * layout: internal layout changes don't affect outside
 * style: counters and quotes are scoped
 * paint: element clips descendants
 * size: element size is independent of children
 * content: shorthand for layout style paint
 */

6. Reduce Paint Area

/* Bad: Large painted area */
.hero {
  background: linear-gradient(...);
}

/* Better: Smaller area */
.hero::before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(...);
}

7. Use Content-Visibility

/* Skip rendering off-screen content */
.offscreen {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

8. Debounce Frequent Updates

// BAD: Many repaints
element.addEventListener('mousemove', (e) => {
  element.style.left = `${e.clientX}px`;
});

// GOOD: Throttled
element.addEventListener('mousemove', throttle((e) => {
  element.style.transform = `translateX(${e.clientX}px)`;
}, 16)); // ~60fps

Practice Problems

0/3solved
Build Repaint Component

Create a reusable React component implementing Repaint. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Repaint Testing

Write unit and integration tests for Repaint using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Repaint Performance

Optimize Repaint for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What triggers repaint but NOT layout?

Question 1 options

2. What is the cheapest way to animate?

Question 2 options

3. What does will-change do?

Question 3 options

4. How do you identify repaints in Chrome DevTools?

Question 4 options

Flashcards

Question

What is repaint?

Answer

Browser redraws affected pixels when visual changes occur (color, visibility, shadows) without affecting layout.

Question

What triggers repaint but not layout?

Answer

color, background-color, visibility, opacity, box-shadow, text-shadow, border-color.

Question

What is the cheapest way to animate?

Answer

Using transform (composite only). Also opacity. Both are GPU-accelerated.

Question

What does will-change do?

Answer

Promotes element to its own compositor layer, improving animation performance.

Question

What is Repaint?

Answer

Repaint is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Repaint redraws pixels without affecting layout
  • 2.Color, visibility, shadows trigger repaint only
  • 3.transform and opacity are cheapest (composite only)
  • 4.Use will-change to promote to compositor layer
  • 5.Batch style changes to minimize repaints

Interview Tips

  • Explain the difference between layout and repaint
  • Show how to identify repaints in DevTools
  • Discuss when to use transform vs top/left
  • Explain CSS containment and its benefits

Cheat Sheet

Repaint Cheat Sheet

What is it?

Redrawing pixels when visual changes occur (no layout change).

Triggers

  • color, background-color
  • visibility, opacity
  • box-shadow, text-shadow
  • border-color, border-style
  • background-image

No Layout, No Paint

  • transform (composite only)
  • opacity (can be composited)
  • will-change

Performance Tips

  1. Use transform instead of top/left
  2. Use opacity instead of visibility
  3. Use CSS classes for style changes
  4. Promote animated elements with will-change
  5. Use contain for isolation
  6. Debounce frequent updates

Tools

  • Chrome: Paint flashing
  • Chrome: Performance timeline
  • performance.now()