Skip to content
Created: November 19, 2022
  • Goal:
  • See with my own eyes a page rendering experience: JS → Layout → Paint → Composite

1. Prepare a demo that “must produce results” ​

First create the simplest HTML (just open it locally):

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>Render Demo</title>
  <style>
    .box {
      width: 100px;
      height: 100px;
      background: red;
      margin: 20px;
      transition: transform 0.5s;
    }
  </style>
</head>
<body>
  <button id="btn">Move</button>
  <div class="box" id="box"></div>

  <script>
    const box = document.getElementById('box')
    document.getElementById('btn').onclick = () => {
      // Dirty layout before reading geometry to demonstrate a forced flush.
      box.style.width = '120px';
      console.log(box.offsetWidth)
      // Subsequent transform animation can reuse layers.
      box.style.transform = 'translateX(200px)'
    }
  </script>
</body>
</html>

This example intentionally contains:

  • One time forced reflow
  • Once Only the animation of the composite layer

2. Open the Performance panel (core tool) ​

  1. open page

  2. F12 / Cmd + Option + I

  3. Cut to Performance

  4. Check:

    • ✅ Screenshots
    • ✅ Web vitals (optional)

3. Record a rendering process ​

1️⃣ Click Record (●) ​

2️⃣ Click Move on the page ​

3️⃣ Wait for the animation to end ​

4️⃣ Click Stop (■) ​

What you are seeing now is the browser The most realistic internal execution trace

4. Understand the Performance Timeline (Key Points) ​

1️⃣ Overview area (top) ​

You will see several color bars:

ColorMeaning
🟨 YellowJS execution
🟪 PurpleStyle / Layout
🟩 GreenPaint
🟦 BlueComposite

📌 Target State: The animation phase is almost only 🟦

2️⃣ Main thread (the most important) ​

Expand Main:

Task
 ├── Event: click
 │    ├── Function Call
 │    │    ├── offsetWidth   ← 强制回流
 │    │    ├── set style
 │    ├── Layout
 │    ├── Paint
 └── Composite Layers

You will clearly see:

👉 read offsetWidth → The browser is forced to execute Layout → Subsequent transforms no longer trigger layout

🔥Key knowledge points (very important) ​

Why does offsetWidth trigger Layout? ​

Because inside the browser is Lazy calculation of layout :

  • Change the style: Account first
  • Reading layout information: must be counted once

This is the root of Layout Thrashing

5. Verification: Does the transform really have no reflow? ​

Open the Rendering panel ​

  1. DevTools → More tools → Rendering

  2. Check:

    • ✅ Paint flashing
    • ✅ Layer borders

Click the button again ​

You will see:

  • Box Flash Blue Border (composition layer)
  • NO GREEN FLASH (NO REDRAW)

✔️ Proof only happens with Composite

6. Comparative experiment (very critical) ​

Change JS to:

js
box.style.left = '200px'

And add:

css
.box {
  position: relative;
}

Re-record the Performance.

You will see: ​

  • Each frame has:

    • Layout
    • Paint
  • Significant drop in FPS

👉 This is why animations use transform

7. Use FPS Meter to check fluency ​

  1. Rendering panel
  2. Check FPS meter

Comparison:

  • left Animation: FPS fluctuates greatly
  • transform: measure actual frame rate; a stable 60 FPS is not guaranteed on every device.

8. Summary ​

  • A complete browser rendering process is:
  • After the DOM and CSSOM are built, the Render Tree is generated.
  • Then perform Layout to calculate geometric information,
  • Then Paint draws the pixels,
  • Finally, the GPU performs Composite synthesis.
  • In the Performance panel of DevTools, you can see
  • Execution time of JS, Layout, Paint, and Composite,
  • Transforms and opacity can reduce Layout/Paint for reusable layers with unchanged content; confirm with a trace.