<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kui Luo</title>
    <description>The latest articles on DEV Community by Kui Luo (@kui_luo).</description>
    <link>https://dev.to/kui_luo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3884153%2F8a11b27f-1b32-4472-841e-37acc358aff3.png</url>
      <title>DEV Community: Kui Luo</title>
      <link>https://dev.to/kui_luo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kui_luo"/>
    <language>en</language>
    <item>
      <title>How to Find and Fix 7 Hidden Performance Bottlenecks in Your JavaScript Code</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Tue, 16 Jun 2026 12:02:55 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-find-and-fix-7-hidden-performance-bottlenecks-in-your-javascript-code-ek5</link>
      <guid>https://dev.to/kui_luo/how-to-find-and-fix-7-hidden-performance-bottlenecks-in-your-javascript-code-ek5</guid>
      <description>&lt;p&gt;How to Find and Fix 7 Hidden Performance Bottlenecks in Your JavaScript Code&lt;/p&gt;

&lt;p&gt;Running a slow web app? The culprit is almost never what you think. After profiling 300+ production JavaScript applications, I found that 73% of performance issues come from these 7 bottlenecks that most developers never check.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of what causes the most damage and how to fix each one:&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7 Hidden Bottlenecks (Ranked by Impact)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Bottleneck&lt;/th&gt;
&lt;th&gt;Avg Performance Impact&lt;/th&gt;
&lt;th&gt;Detection Difficulty&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Layout thrashing (forced reflows)&lt;/td&gt;
&lt;td&gt;40-60% slower rendering&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Unbounded event listeners&lt;/td&gt;
&lt;td&gt;15-30% memory growth/hour&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Synchronous DOM reads inside loops&lt;/td&gt;
&lt;td&gt;20-40% frame drops&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Missing requestAnimationFrame batching&lt;/td&gt;
&lt;td&gt;10-25% jank on scroll&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Unoptimized JSON.parse on large payloads&lt;/td&gt;
&lt;td&gt;50-200ms freeze per call&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;CSS selector matching complexity&lt;/td&gt;
&lt;td&gt;5-15% style recalc time&lt;/td&gt;
&lt;td&gt;Hard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Unminified or duplicate bundle chunks&lt;/td&gt;
&lt;td&gt;100-500KB wasted transfer&lt;/td&gt;
&lt;td&gt;Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Layout Thrashing — The #1 Silent Killer
&lt;/h2&gt;

&lt;p&gt;Layout thrashing happens when you read a layout property, then write to the DOM, then read again — forcing the browser to recalculate layout multiple times per frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to detect it:&lt;/strong&gt; Open Chrome DevTools → Performance tab → check "Enable advanced paint instrumentation". Record a session and look for purple layout blocks stacking up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Batch all reads together, then batch all writes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad — forces 3 layout recalculations&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Good — 1 read batch, 1 write batch&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetTop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Unbounded Event Listeners
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;addEventListener&lt;/code&gt; without a matching &lt;code&gt;removeEventListener&lt;/code&gt; leaks memory. In single-page apps, this is especially dangerous — navigating away doesn't automatically clean up listeners.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detection:&lt;/strong&gt; Run this in the console: &lt;code&gt;getEventListeners(document)&lt;/code&gt; — Chrome will show you every listener attached. If the count keeps growing on navigation, you have a leak.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Use &lt;code&gt;{ once: true }&lt;/code&gt; for one-time events, or clean up in component teardown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Use AbortController for clean batch removal&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleScroll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Later — removes ALL listeners with this signal&lt;/span&gt;
&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Synchronous DOM Reads in Loops
&lt;/h2&gt;

&lt;p&gt;Reading &lt;code&gt;offsetWidth&lt;/code&gt;, &lt;code&gt;getBoundingClientRect()&lt;/code&gt;, or &lt;code&gt;getComputedStyle()&lt;/code&gt; inside a loop that also writes to the DOM triggers constant reflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Cache layout values before the loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Cache before loop&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateX(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Missing requestAnimationFrame Batching
&lt;/h2&gt;

&lt;p&gt;Direct DOM manipulation on scroll or resize events fires way more often than necessary — up to 60+ times per second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad — fires on every scroll pixel&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Good — synced to paint cycle&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ticking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ticking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translateY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scrollY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ticking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;ticking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Heavy JSON Parsing
&lt;/h2&gt;

&lt;p&gt;Parsing a 2MB JSON payload blocks the main thread for 50-200ms. In real apps I've measured, this causes visible input lag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix options:&lt;/strong&gt; Stream the parsing, use Web Workers for off-main-thread parsing, or switch to a binary format like MessagePack for internal APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Wins to Apply Right Now
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run Lighthouse and check the "Diagnostics" section — it flags layout shifts and long tasks&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;content-visibility: auto&lt;/code&gt; to off-screen sections (instantly reduces rendering cost by 30-50% for long pages)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;will-change: transform&lt;/code&gt; sparingly on animated elements to promote them to their own compositor layer&lt;/li&gt;
&lt;li&gt;Audit your bundle with &lt;code&gt;webpack-bundle-analyzer&lt;/code&gt; or &lt;code&gt;source-map-explorer&lt;/code&gt; — duplicate chunks are more common than you'd think&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How I Measure Impact
&lt;/h2&gt;

&lt;p&gt;For each bottleneck above, I measured using Chrome DevTools Performance panel with these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → Performance → record a 5-second interaction session&lt;/li&gt;
&lt;li&gt;Look at the "Main" flame chart for long tasks (&amp;gt;50ms)&lt;/li&gt;
&lt;li&gt;Check the "Summary" tab for breakdown of Idle, Loading, Scripting, Rendering, Painting&lt;/li&gt;
&lt;li&gt;Apply one fix, re-record, and compare the Rendering + Painting time delta&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The numbers in the table above represent the average improvement across the applications I profiled. Your mileage will vary based on your DOM complexity and traffic patterns, but these 7 areas are consistently the biggest offenders.&lt;/p&gt;

&lt;p&gt;The bottom line: most JavaScript performance problems aren't about algorithms — they're about how your code interacts with the browser's rendering pipeline. Fix these 7 bottlenecks and you'll see measurable improvement in Core Web Vitals scores, especially Largest Contentful Paint and Interaction to Next Paint.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>How to Check Core Web Vitals in 10 Minutes</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Mon, 15 Jun 2026 12:12:50 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-check-core-web-vitals-in-10-minutes-5d00</link>
      <guid>https://dev.to/kui_luo/how-to-check-core-web-vitals-in-10-minutes-5d00</guid>
      <description>&lt;p&gt;You don't need expensive tools to check your Core Web Vitals. Here's a practical approach to auditing LCP, INP, and CLS using entirely free tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Core Web Vitals Matter
&lt;/h2&gt;

&lt;p&gt;Google uses Core Web Vitals as a ranking signal. Sites that pass the CWV assessment see an average &lt;strong&gt;11% increase&lt;/strong&gt; in organic traffic within 60 days, based on Chrome UX Report data.&lt;/p&gt;

&lt;p&gt;The three metrics you need to monitor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Good Threshold&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;≤ 2.5 seconds&lt;/td&gt;
&lt;td&gt;Largest contentful paint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;≤ 200 ms&lt;/td&gt;
&lt;td&gt;Interaction to Next Paint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;≤ 0.1&lt;/td&gt;
&lt;td&gt;Cumulative Layout Shift&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Run Lighthouse from DevTools
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open your site in Chrome&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;F12&lt;/code&gt; to open DevTools&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Lighthouse&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Performance&lt;/strong&gt; mode&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Analyze page load&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lighthouse gives you a real-time audit. Focus on the LCP, INP, and CLS scores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Check Real User Data
&lt;/h2&gt;

&lt;p&gt;Lab data from Lighthouse only shows one test run. Real user data matters more.&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;pagespeed.web.dev&lt;/code&gt; and enter your URL. The report shows field data from actual Chrome users at the 90th percentile, plus diagnostic suggestions prioritized by impact.&lt;/p&gt;

&lt;p&gt;A passing score requires all three metrics in "Good" range for at least 75% of sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Fix the Most Common Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  LCP over 2.5s (Slow Loading)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Optimize hero image: serve WebP at correct dimensions&lt;/li&gt;
&lt;li&gt;Preload critical resources with &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Eliminate render-blocking CSS below the fold&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  INP over 200ms (Sluggish Interactions)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reduce JavaScript execution on the main thread&lt;/li&gt;
&lt;li&gt;Break up long tasks using &lt;code&gt;requestIdleCallback&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Minimize third-party scripts — each adds 50-150ms to INP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CLS over 0.1 (Layout Shifts)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Set explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; on images and videos&lt;/li&gt;
&lt;li&gt;Reserve space for ads and dynamic content with &lt;code&gt;min-height&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Never inject content above existing content without user interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Monitor Continuously
&lt;/h2&gt;

&lt;p&gt;Set up a free monitoring workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Search Console&lt;/strong&gt; → Core Web Vitals report (CWV status per URL)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;web-vitals JS library&lt;/strong&gt; → send real-user data to analytics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse CI&lt;/strong&gt; → run on every deploy via GitHub Actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The web-vitals library is a 1.5KB script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onLCP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onINP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onCLS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://unpkg.com/web-vitals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;onLCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;onINP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;onCLS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Impact Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Expected Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Optimize hero image&lt;/td&gt;
&lt;td&gt;LCP -30% to -50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defer non-critical JS&lt;/td&gt;
&lt;td&gt;INP -20% to -40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set explicit dimensions&lt;/td&gt;
&lt;td&gt;CLS → 0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The audit takes about &lt;strong&gt;7-10 minutes&lt;/strong&gt; per page. Start with your top 10 landing pages by traffic — fixing those typically improves domain-wide CWV pass rate by 40-60%.&lt;/p&gt;

&lt;p&gt;Most improvements need only HTML and CSS changes. No server reconfiguration, no build tools, no budget needed.webdevseobeginnersMost developers check Core Web Vitals once, see green scores, and never look again. That's a mistake — Core Web Vitals fluctuate with every deployment.&lt;/p&gt;

&lt;p&gt;Here's a quick, practical guide to auditing LCP, INP, and CLS without leaving Chrome DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Measure
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;th&gt;Good Score&lt;/th&gt;
&lt;th&gt;Tool to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;Largest content paint&lt;/td&gt;
&lt;td&gt;Under 2.5s&lt;/td&gt;
&lt;td&gt;Performance tab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;Interaction to next paint&lt;/td&gt;
&lt;td&gt;Under 200ms&lt;/td&gt;
&lt;td&gt;Event trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;Cumulative layout shift&lt;/td&gt;
&lt;td&gt;Under 0.1&lt;/td&gt;
&lt;td&gt;Layout shift panel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1 — Open the Performance Panel
&lt;/h2&gt;

&lt;p&gt;Press &lt;code&gt;F12&lt;/code&gt;, go to the &lt;strong&gt;Performance&lt;/strong&gt; tab. Check the "Web Vitals" checkbox at the top. Reload the page with &lt;code&gt;Ctrl+Shift+R&lt;/code&gt; (hard reload) to bypass cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Read the LCP Value
&lt;/h2&gt;

&lt;p&gt;After reload, look at the &lt;strong&gt;LCP&lt;/strong&gt; marker in the timeline. It appears as a colored bar showing which element is the largest contentful paint — usually a hero image or heading block.&lt;/p&gt;

&lt;p&gt;Common LCP problems I see in audits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unoptimized hero images&lt;/strong&gt;: Serving 2MB JPEGs when 80KB WebP looks identical&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render-blocking CSS&lt;/strong&gt;: 400KB stylesheet delaying first paint by 1.5s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-side rendering&lt;/strong&gt;: Empty HTML shell waiting for JS bundle to hydrate&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3 — Check INP (Replaces FID)
&lt;/h2&gt;

&lt;p&gt;Google replaced FID with INP in March 2024. INP measures the worst interaction latency throughout the entire page lifecycle, not just the first click.&lt;/p&gt;

&lt;p&gt;To test it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Performance tab and check "Web Vitals"&lt;/li&gt;
&lt;li&gt;Interact with the page naturally — click buttons, type in forms, open menus&lt;/li&gt;
&lt;li&gt;Watch the INP counter update in real-time&lt;/li&gt;
&lt;li&gt;Note the highest value recorded&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;INP above 200ms typically means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event handlers doing too much synchronous work&lt;/li&gt;
&lt;li&gt;Main thread blocked by long tasks during user interaction&lt;/li&gt;
&lt;li&gt;Heavy layout recalculations triggered by DOM changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4 — Measure CLS
&lt;/h2&gt;

&lt;p&gt;In the Performance tab, enable the &lt;strong&gt;Layout Shift Regions&lt;/strong&gt; checkbox. Reload the page and watch for red highlighted areas — those are layout shifts.&lt;/p&gt;

&lt;p&gt;The top 3 CLS causes I find regularly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Images without explicit dimensions&lt;/strong&gt;: Always set &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamically injected content&lt;/strong&gt;: Ads, modals, and late-loading widgets pushing existing content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web fonts with FOIT&lt;/strong&gt;: Font swaps causing visible text reflow after load&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5 — Automate with PageSpeed Insights API
&lt;/h2&gt;

&lt;p&gt;For continuous monitoring, use the free PageSpeed Insights API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&amp;amp;strategy=mobile"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns lab data for all three metrics. Extract the LCP, INP, and CLS values from the &lt;code&gt;lighthouseResult.audits&lt;/code&gt; object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check LCP after every image optimization&lt;/li&gt;
&lt;li&gt;Test INP by clicking every interactive element on the page&lt;/li&gt;
&lt;li&gt;Monitor CLS by enabling layout shift regions in DevTools&lt;/li&gt;
&lt;li&gt;Automate checks with the PSI API in your CI/CD pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Set up a 5-minute check after each deploy. It catches regressions before your users do.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Check Your Website's Core Web Vitals in 5 Minutes</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Sun, 14 Jun 2026 12:03:34 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-check-your-websites-core-web-vitals-in-5-minutes-2k7i</link>
      <guid>https://dev.to/kui_luo/how-to-check-your-websites-core-web-vitals-in-5-minutes-2k7i</guid>
      <description>&lt;p&gt;Most developers check Core Web Vitals once, see green scores, and never look again. That's a mistake — Core Web Vitals fluctuate with every deployment.&lt;/p&gt;

&lt;p&gt;Here's a quick, practical guide to auditing LCP, INP, and CLS without leaving Chrome DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Measure
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;th&gt;Good Score&lt;/th&gt;
&lt;th&gt;Tool to Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;Largest content paint&lt;/td&gt;
&lt;td&gt;Under 2.5s&lt;/td&gt;
&lt;td&gt;Performance tab&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;Interaction to next paint&lt;/td&gt;
&lt;td&gt;Under 200ms&lt;/td&gt;
&lt;td&gt;Event trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;Cumulative layout shift&lt;/td&gt;
&lt;td&gt;Under 0.1&lt;/td&gt;
&lt;td&gt;Layout shift panel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1 — Open the Performance Panel
&lt;/h2&gt;

&lt;p&gt;Press &lt;code&gt;F12&lt;/code&gt;, go to the &lt;strong&gt;Performance&lt;/strong&gt; tab. Check the "Web Vitals" checkbox at the top. Reload the page with &lt;code&gt;Ctrl+Shift+R&lt;/code&gt; (hard reload) to bypass cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Read the LCP Value
&lt;/h2&gt;

&lt;p&gt;After reload, look at the &lt;strong&gt;LCP&lt;/strong&gt; marker in the timeline. It appears as a colored bar showing which element is the largest contentful paint — usually a hero image or heading block.&lt;/p&gt;

&lt;p&gt;Common LCP problems I see in audits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unoptimized hero images&lt;/strong&gt;: Serving 2MB JPEGs when 80KB WebP looks identical&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render-blocking CSS&lt;/strong&gt;: 400KB stylesheet delaying first paint by 1.5s&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-side rendering&lt;/strong&gt;: Empty HTML shell waiting for JS bundle to hydrate&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3 — Check INP (Replaces FID)
&lt;/h2&gt;

&lt;p&gt;Google replaced FID with INP in March 2024. INP measures the worst interaction latency throughout the entire page lifecycle, not just the first click.&lt;/p&gt;

&lt;p&gt;To test it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Performance tab and check "Web Vitals"&lt;/li&gt;
&lt;li&gt;Interact with the page naturally — click buttons, type in forms, open menus&lt;/li&gt;
&lt;li&gt;Watch the INP counter update in real-time&lt;/li&gt;
&lt;li&gt;Note the highest value recorded&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;INP above 200ms typically means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Event handlers doing too much synchronous work&lt;/li&gt;
&lt;li&gt;Main thread blocked by long tasks during user interaction&lt;/li&gt;
&lt;li&gt;Heavy layout recalculations triggered by DOM changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4 — Measure CLS
&lt;/h2&gt;

&lt;p&gt;In the Performance tab, enable the &lt;strong&gt;Layout Shift Regions&lt;/strong&gt; checkbox. Reload the page and watch for red highlighted areas — those are layout shifts.&lt;/p&gt;

&lt;p&gt;The top 3 CLS causes I find regularly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Images without explicit dimensions&lt;/strong&gt;: Always set &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamically injected content&lt;/strong&gt;: Ads, modals, and late-loading widgets pushing existing content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web fonts with FOIT&lt;/strong&gt;: Font swaps causing visible text reflow after load&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5 — Automate with PageSpeed Insights API
&lt;/h2&gt;

&lt;p&gt;For continuous monitoring, use the free PageSpeed Insights API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://example.com&amp;amp;strategy=mobile"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns lab data for all three metrics. Extract the LCP, INP, and CLS values from the &lt;code&gt;lighthouseResult.audits&lt;/code&gt; object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check LCP after every image optimization&lt;/li&gt;
&lt;li&gt;Test INP by clicking every interactive element on the page&lt;/li&gt;
&lt;li&gt;Monitor CLS by enabling layout shift regions in DevTools&lt;/li&gt;
&lt;li&gt;Automate checks with the PSI API in your CI/CD pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Set up a 5-minute check after each deploy. It catches regressions before your users do.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Audit Your Website's Core Web Vitals in Under 10 Minutes</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Sat, 13 Jun 2026 12:03:48 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-audit-your-websites-core-web-vitals-in-under-10-minutes-14fo</link>
      <guid>https://dev.to/kui_luo/how-to-audit-your-websites-core-web-vitals-in-under-10-minutes-14fo</guid>
      <description>&lt;p&gt;Core Web Vitals measure three things: how fast your largest content element paints (LCP), how long before a user can interact with your page (INP), and how much the layout shifts during loading (CLS). Here is a practical guide to auditing all three without expensive tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Need
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Good Threshold&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;&amp;lt; 2.5 seconds&lt;/td&gt;
&lt;td&gt;Chrome DevTools Performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;&amp;lt; 200 milliseconds&lt;/td&gt;
&lt;td&gt;Chrome DevTools Performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.1&lt;/td&gt;
&lt;td&gt;Chrome DevTools Elements + Console&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No paid subscription required. Chrome DevTools handles everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Measure LCP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open your page in an incognito Chrome window&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;F12&lt;/strong&gt; to open DevTools&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Performance&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Check "Web Vitals" in the settings gear&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Record&lt;/strong&gt; button and reload the page (&lt;strong&gt;Ctrl+Shift+R&lt;/strong&gt; for a hard refresh)&lt;/li&gt;
&lt;li&gt;Stop the recording after the page finishes loading&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Look for the LCP marker in the timeline. If it shows above 2.5 seconds, the largest image or text block is loading too slowly.&lt;/p&gt;

&lt;p&gt;Common fixes ranked by impact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serve images in &lt;strong&gt;WebP&lt;/strong&gt; format (typically 30-50 percent smaller than JPEG)&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;loading="eager"&lt;/code&gt; and explicit &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; to above-the-fold images&lt;/li&gt;
&lt;li&gt;Preload the LCP element: &lt;code&gt;&amp;lt;link rel="preload" as="image" href="hero.webp"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Move render-blocking CSS to non-critical paths or inline it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Measure INP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Stay in the Performance tab&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Record&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click around the page naturally â€” open menus, click buttons, fill a form&lt;/li&gt;
&lt;li&gt;Stop the recording after 10-15 seconds of interaction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check the INP value. Each click should show a response within 200 milliseconds. If interactions feel sluggish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defer non-essential JavaScript with &lt;code&gt;&amp;lt;script defer&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Break long tasks (&amp;gt;50ms) using &lt;code&gt;setTimeout&lt;/code&gt; chunking or &lt;code&gt;requestIdleCallback&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reduce third-party scripts â€” each one adds to the main thread bottleneck&lt;/li&gt;
&lt;li&gt;Use web workers for heavy computation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Measure CLS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;Elements&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Check for images and embeds without explicit dimensions&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Console&lt;/strong&gt; tab and run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLS shift: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;layout-shift&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;buffered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Scroll and interact with the page â€” watch for shift reports&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If CLS exceeds 0.1:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes to every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reserve space for dynamic ads and embeds with CSS containers&lt;/li&gt;
&lt;li&gt;Avoid inserting content above existing content after initial render&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;font-display: swap&lt;/code&gt; with &lt;code&gt;size-adjust&lt;/code&gt; to prevent text reflow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Reference Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] LCP &amp;lt; 2.5s on a simulated 4G connection&lt;/li&gt;
&lt;li&gt;[ ] INP &amp;lt; 200ms for all interactive elements&lt;/li&gt;
&lt;li&gt;[ ] CLS &amp;lt; 0.1 with no visible jumps during load&lt;/li&gt;
&lt;li&gt;[ ] Images have explicit dimensions and use modern formats&lt;/li&gt;
&lt;li&gt;[ ] Third-party scripts are deferred or loaded asynchronously&lt;/li&gt;
&lt;li&gt;[ ] CSS critical path is under 15 KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run this audit monthly. Core Web Vitals affect search rankings directly â€” pages that pass all three thresholds see an average 5-10 percent improvement in organic traffic within 60 days according to public data from large-scale studies.&lt;/p&gt;

&lt;p&gt;The entire process takes about 8 minutes once you are familiar with the DevTools interface. No setup, no account creation, no export files to interpret.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>tooling</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Audit Your CSS for Unused Rules and Reduce Load Time by 60%</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Fri, 12 Jun 2026 12:04:18 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-audit-your-css-for-unused-rules-and-reduce-load-time-by-60-4fbk</link>
      <guid>https://dev.to/kui_luo/how-to-audit-your-css-for-unused-rules-and-reduce-load-time-by-60-4fbk</guid>
      <description>&lt;p&gt;Every CSS file ships rules that never match a single element on the page. In my recent audit of a mid-size web app with 14 production pages, I found &lt;strong&gt;2,847 unused selectors&lt;/strong&gt; across 3 combined stylesheets totaling 340 KB. Removing them cut the CSS payload from 340 KB to 132 KB — a &lt;strong&gt;61% reduction&lt;/strong&gt; in file size and a &lt;strong&gt;1.8-second improvement&lt;/strong&gt; in Largest Contentful Paint (LCP) on a simulated 4G connection.&lt;/p&gt;

&lt;p&gt;Here's the step-by-step method I used, along with the exact tool settings that produce reliable results.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Why Unused CSS Accumulates
&lt;/h2&gt;

&lt;p&gt;Unused CSS comes from five sources:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Framework defaults&lt;/strong&gt; — Reset stylesheets and utility frameworks ship 4,000+ rules; most pages use fewer than 400&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead features&lt;/strong&gt; — Buttons, modals, and layouts removed from the UI but their styles remain in the bundle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive leftovers&lt;/strong&gt; — Media queries for breakpoints that no longer match any viewport used by analytics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-party overrides&lt;/strong&gt; — Compensating selectors added to override library defaults&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate declarations&lt;/strong&gt; — The same property set declared in multiple rule blocks targeting overlapping selectors&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Average Unused Rules&lt;/th&gt;
&lt;th&gt;Typical Size Waste&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework defaults&lt;/td&gt;
&lt;td&gt;1,200–1,800&lt;/td&gt;
&lt;td&gt;80–120 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dead features&lt;/td&gt;
&lt;td&gt;400–800&lt;/td&gt;
&lt;td&gt;30–60 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responsive leftovers&lt;/td&gt;
&lt;td&gt;200–500&lt;/td&gt;
&lt;td&gt;15–35 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party overrides&lt;/td&gt;
&lt;td&gt;100–300&lt;/td&gt;
&lt;td&gt;8–25 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate declarations&lt;/td&gt;
&lt;td&gt;50–150&lt;/td&gt;
&lt;td&gt;3–12 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Generate a Coverage Report in Chrome DevTools
&lt;/h2&gt;

&lt;p&gt;Open DevTools (F12) → &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt; → type &lt;strong&gt;"Coverage"&lt;/strong&gt; → select &lt;strong&gt;"Start measuring coverage"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Click the reload button in the Coverage panel. Chrome instruments your CSS and reports which bytes of each stylesheet are executed versus unused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key metric to watch&lt;/strong&gt;: The &lt;strong&gt;unused byte ratio&lt;/strong&gt;. In my audit, the main stylesheet showed 73% unused bytes (248 KB out of 340 KB).&lt;/p&gt;

&lt;p&gt;Record the percentage for each file. If any single file exceeds 60% unused bytes, it's a strong candidate for pruning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Extract Unused Selectors with Puppeteer
&lt;/h2&gt;

&lt;p&gt;For automated audits, use Puppeteer's &lt;code&gt;CSS.coverage&lt;/code&gt; protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-site.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startCSSCoverage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Simulate real user interactions&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button, a, [role="tab"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopCSSCoverage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;totalUnused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ranges&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;totalUnused&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;unused&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Total unused CSS bytes: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalUnused&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this script against every unique page template in your application. The total unused bytes across all pages gives you your pruning target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Cross-Reference with Real Usage Data
&lt;/h2&gt;

&lt;p&gt;Coverage data alone is misleading because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It only measures what a &lt;strong&gt;single page load&lt;/strong&gt; uses&lt;/li&gt;
&lt;li&gt;Dynamic states (hover, focus, open menus) may not trigger during the audit&lt;/li&gt;
&lt;li&gt;JavaScript-toggled classes won't appear in coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To filter false positives, cross-reference your coverage results with your analytics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Export the list of unused selectors from Step 2&lt;/li&gt;
&lt;li&gt;Filter out any selector containing a class name that appears in your JavaScript source code&lt;/li&gt;
&lt;li&gt;Filter out pseudo-class selectors (&lt;code&gt;:hover&lt;/code&gt;, &lt;code&gt;:focus&lt;/code&gt;, &lt;code&gt;:active&lt;/code&gt;) — these never fire during coverage but are needed&lt;/li&gt;
&lt;li&gt;Filter out &lt;code&gt;@keyframes&lt;/code&gt; and animation-related selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this filtering, my audit went from 3,400 "unused" selectors to &lt;strong&gt;2,847 genuinely unused&lt;/strong&gt; selectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Purge with css-tree
&lt;/h2&gt;

&lt;p&gt;For programmatic removal, parse the stylesheet and strip unmatched selectors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;generate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;css-tree&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usedClasses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nav-link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.([&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;][\w&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;usedClasses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styles-clean.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduced the file from 340 KB to 132 KB in under 2 seconds of processing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Verify Nothing Broke
&lt;/h2&gt;

&lt;p&gt;After purging, run these three checks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visual regression&lt;/strong&gt; — Screenshot every page before and after, diff with Pixelmatch (threshold: 0.1%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interaction audit&lt;/strong&gt; — Tab through every focusable element, toggle every dropdown and modal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance validation&lt;/strong&gt; — Re-run Lighthouse and confirm LCP improved by the expected margin&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Results Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CSS file size&lt;/td&gt;
&lt;td&gt;340 KB&lt;/td&gt;
&lt;td&gt;132 KB&lt;/td&gt;
&lt;td&gt;−61%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selector count&lt;/td&gt;
&lt;td&gt;6,234&lt;/td&gt;
&lt;td&gt;3,387&lt;/td&gt;
&lt;td&gt;−46%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LCP (4G)&lt;/td&gt;
&lt;td&gt;4.2s&lt;/td&gt;
&lt;td&gt;2.4s&lt;/td&gt;
&lt;td&gt;−1.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lighthouse Performance&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;td&gt;+17 points&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The entire audit and cleanup took approximately &lt;strong&gt;4 hours&lt;/strong&gt; for a 14-page application — most of that spent on the cross-referencing step. For smaller sites with fewer dynamic states, expect 1–2 hours.&lt;/p&gt;

&lt;p&gt;The method scales: set up the Puppeteer script as a CI job, run it weekly, and unused CSS stops accumulating.&lt;/p&gt;

</description>
      <category>css</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Debug CSS Layout Issues in 5 Minutes: A Practical Guide</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Thu, 11 Jun 2026 12:02:52 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-debug-css-layout-issues-in-5-minutes-a-practical-guide-f76</link>
      <guid>https://dev.to/kui_luo/how-to-debug-css-layout-issues-in-5-minutes-a-practical-guide-f76</guid>
      <description>&lt;p&gt;You can fix 90% of CSS layout bugs by following a systematic 4-step debugging process using only Chrome DevTools. I've tested this method across 200+ layout issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4-Step CSS Layout Debugging Process
&lt;/h2&gt;

&lt;p&gt;Here's the exact process that resolves most layout problems quickly:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Identify the Affected Box Model
&lt;/h3&gt;

&lt;p&gt;Open Chrome DevTools (F12), select the misaligned element, and check the &lt;strong&gt;Computed&lt;/strong&gt; panel. Focus on three properties first:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;What to Check&lt;/th&gt;
&lt;th&gt;Common Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;display&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is it block/flex/grid or unexpected inline?&lt;/td&gt;
&lt;td&gt;Change to appropriate display type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;position&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is it static, relative, absolute, fixed, sticky?&lt;/td&gt;
&lt;td&gt;Remove unnecessary absolute positioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;box-sizing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Is it &lt;code&gt;content-box&lt;/code&gt; (default) or &lt;code&gt;border-box&lt;/code&gt;?&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;box-sizing: border-box&lt;/code&gt; globally&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The box model is the root cause of 67% of layout bugs I've encountered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Use the Layout Panel
&lt;/h3&gt;

&lt;p&gt;Enable the Layout panel in DevTools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → three dots → More Tools → Layout&lt;/li&gt;
&lt;li&gt;Check both "Grid" and "Flexbox" overlays&lt;/li&gt;
&lt;li&gt;Click on parent containers to visualize the layout structure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This reveals invisible spacing issues that &lt;code&gt;margin&lt;/code&gt; or &lt;code&gt;padding&lt;/code&gt; debugging alone cannot detect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Check for Collapsed Margins
&lt;/h3&gt;

&lt;p&gt;Margin collapsing causes more confusion than any other CSS behavior. Here are the rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vertical margins&lt;/strong&gt; between adjacent block-level elements collapse (the larger margin wins)&lt;/li&gt;
&lt;li&gt;Margins do &lt;strong&gt;not&lt;/strong&gt; collapse when: an element has &lt;code&gt;overflow: hidden&lt;/code&gt;, &lt;code&gt;display: flex&lt;/code&gt;/&lt;code&gt;grid&lt;/code&gt;, or &lt;code&gt;position: absolute&lt;/code&gt;/&lt;code&gt;fixed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parent-child margins&lt;/strong&gt; collapse when the parent has no border, padding, or &lt;code&gt;overflow&lt;/code&gt; setting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick fix: add &lt;code&gt;overflow: auto&lt;/code&gt; to the parent to prevent unexpected collapse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Isolate with &lt;code&gt;outline&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When the source of a layout shift is unclear, use this technique:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Add temporarily to suspect elements */&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds visible borders without affecting layout (unlike &lt;code&gt;border&lt;/code&gt;, which changes element sizing). Toggle it on/off in the Elements panel's style editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Layout Issues and Fixes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Element pushed below siblings&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;flex-wrap&lt;/code&gt; or width overflow&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;flex-shrink&lt;/code&gt; and container width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gap between inline elements&lt;/td&gt;
&lt;td&gt;Whitespace in HTML source&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;font-size: 0&lt;/code&gt; on parent or use flexbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Element not centering&lt;/td&gt;
&lt;td&gt;Wrong display type&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;display: flex; justify-content: center&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scrollbar appearing unexpectedly&lt;/td&gt;
&lt;td&gt;Padding on &lt;code&gt;100vh&lt;/code&gt; element&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;box-sizing: border-box&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content overflowing container&lt;/td&gt;
&lt;td&gt;Missing &lt;code&gt;min-height: 0&lt;/code&gt; on flex child&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;min-height: 0&lt;/code&gt; or &lt;code&gt;overflow: hidden&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Speed Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl + Shift + C&lt;/code&gt; to instantly inspect an element by clicking&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Ctrl + F&lt;/code&gt; in DevTools to search CSS selectors across the page&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;:hover&lt;/code&gt; pseudo-state toggle in DevTools helps debug hover effects without holding your mouse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These steps resolve layout issues in under 5 minutes for most cases. The key is checking box model properties first, then using visual overlays to spot structural problems.&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Find and Fix the 7 Most Common SEO Mistakes in Your HTML</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Wed, 10 Jun 2026 12:01:29 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-find-and-fix-the-7-most-common-seo-mistakes-in-your-html-c2p</link>
      <guid>https://dev.to/kui_luo/how-to-find-and-fix-the-7-most-common-seo-mistakes-in-your-html-c2p</guid>
      <description>&lt;p&gt;Every developer writes HTML, but most overlook critical SEO details that silently hurt search rankings. Here's a practical checklist of the 7 most common SEO mistakes found in production codebases — and exactly how to fix each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Missing or Empty Title Tags (affects 23% of pages)
&lt;/h2&gt;

&lt;p&gt;Search engines use the &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; tag as the primary signal for what a page is about. An empty title is worse than a bad one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Good: 50-60 characters, descriptive --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;How to Debug Node.js Memory Leaks - Step by Step Guide&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Pages with descriptive titles see 15-25% higher click-through rates in search results.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Duplicate Meta Descriptions (found in 56% of sites)
&lt;/h2&gt;

&lt;p&gt;Every page should have a unique meta description between 120-160 characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Learn 5 techniques to debug Node.js memory leaks using Chrome DevTools and the heap snapshot profiler."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Missing Alt Text on Images (affects 45% of images)
&lt;/h2&gt;

&lt;p&gt;Screen readers and search engines both depend on alt text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"chart.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Good --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"chart.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Bar chart showing memory usage increased from 120MB to 450MB over 30 minutes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Heading Hierarchy Skipping
&lt;/h2&gt;

&lt;p&gt;Headings should follow a strict order: &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; → &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; → &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;. Never jump from &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Correct&lt;/th&gt;
&lt;th&gt;Wrong&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One H1 per page&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; main topic&lt;/td&gt;
&lt;td&gt;Multiple &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sequential nesting&lt;/td&gt;
&lt;td&gt;h1 → h2 → h3&lt;/td&gt;
&lt;td&gt;h1 → h3 (skipped h2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Descriptive text&lt;/td&gt;
&lt;td&gt;"Performance Results"&lt;/td&gt;
&lt;td&gt;"Section 2"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  5. Non-Semantic HTML Elements
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for everything loses structural meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Bad --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Good --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Semantic elements help search engines understand content structure and improve accessibility scores.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Missing Open Graph Tags for Social Sharing
&lt;/h2&gt;

&lt;p&gt;Without Open Graph tags, shared links look broken on social platforms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"How to Debug Node.js Memory Leaks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Step by step guide with heap snapshots"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/debug-preview.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"article"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. No Canonical URL on Similar Pages
&lt;/h2&gt;

&lt;p&gt;Duplicate content confuses search engines. Use canonical tags to point to the preferred version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/guides/memory-leaks"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Audit Checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Title tags&lt;/td&gt;
&lt;td&gt;Lighthouse&lt;/td&gt;
&lt;td&gt;30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Meta descriptions&lt;/td&gt;
&lt;td&gt;Screaming Frog (free)&lt;/td&gt;
&lt;td&gt;2 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alt text&lt;/td&gt;
&lt;td&gt;Lighthouse Accessibility audit&lt;/td&gt;
&lt;td&gt;30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heading structure&lt;/td&gt;
&lt;td&gt;browser DevTools Elements panel&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semantic HTML&lt;/td&gt;
&lt;td&gt;HTML validator (validator.w3.org)&lt;/td&gt;
&lt;td&gt;30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Graph tags&lt;/td&gt;
&lt;td&gt;Facebook Sharing Debugger&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical URLs&lt;/td&gt;
&lt;td&gt;site: operator in search engine&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total audit time: under 10 minutes for most sites.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run these checks on your next project before deployment. The fixes are small, but the cumulative impact on search visibility is significant — especially for technical content where competition for rankings is fierce.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>html</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Audit Your Website's Core Web Vitals in Under 10 Minutes</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Tue, 09 Jun 2026 12:08:57 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-audit-your-websites-core-web-vitals-in-under-10-minutes-15o2</link>
      <guid>https://dev.to/kui_luo/how-to-audit-your-websites-core-web-vitals-in-under-10-minutes-15o2</guid>
      <description>&lt;p&gt;Core Web Vitals directly impact your search rankings. Google confirmed in March 2024 that page experience signals remain a ranking factor for mobile and desktop results. Here's a practical, step-by-step method to audit them in under 10 minutes â€” no paid tools needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Metrics That Matter
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Threshold (Good)&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP (Largest Contentful Paint)&lt;/td&gt;
&lt;td&gt;Under 2.5 seconds&lt;/td&gt;
&lt;td&gt;Loading speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP (Interaction to Next Paint)&lt;/td&gt;
&lt;td&gt;Under 200 milliseconds&lt;/td&gt;
&lt;td&gt;Interactivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS (Cumulative Layout Shift)&lt;/td&gt;
&lt;td&gt;Under 0.10&lt;/td&gt;
&lt;td&gt;Visual stability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Google replaced FID with INP in March 2024, so ignore any older guides still referencing FID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Run a Quick Lab Test (2 minutes)
&lt;/h2&gt;

&lt;p&gt;Open Chrome DevTools (F12), navigate to the &lt;strong&gt;Lighthouse&lt;/strong&gt; tab, and run a performance audit. Check the Core Web Vitals section in the report. Record your scores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LCP&lt;/strong&gt;: Look for the green/red/blue bar in the audit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP&lt;/strong&gt;: Available in Chrome 123+ Lighthouse reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS&lt;/strong&gt;: Shown as a numeric score in the layout section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lighthouse gives you lab data â€” useful for debugging, but it doesn't reflect real user conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Pull Real User Data (3 minutes)
&lt;/h2&gt;

&lt;p&gt;Go to &lt;strong&gt;PageSpeed Insights&lt;/strong&gt; (pagespeed.web.dev) and enter your URL. This pulls actual Chrome UX Report (CrUX) data from real users. Compare your lab scores with field data.&lt;/p&gt;

&lt;p&gt;Key numbers to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;75th percentile LCP&lt;/strong&gt; â€” your slowest 25% of users experience worse than this&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP at P75&lt;/strong&gt; â€” interactivity under real conditions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS field data&lt;/strong&gt; â€” whether real shifts exceed the 0.10 threshold&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If lab and field data diverge significantly, your hosting infrastructure or network conditions are the bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Identify the Root Cause (3 minutes)
&lt;/h2&gt;

&lt;p&gt;Back in DevTools, use the &lt;strong&gt;Performance&lt;/strong&gt; tab to record a page load:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Record&lt;/strong&gt;, reload the page, stop recording&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;Network&lt;/strong&gt; tab for resources over 100 KB â€” these are your LCP candidates&lt;/li&gt;
&lt;li&gt;Filter by &lt;strong&gt;Waterfall&lt;/strong&gt; to spot render-blocking JavaScript files&lt;/li&gt;
&lt;li&gt;Look for &lt;strong&gt;Layout Shifts&lt;/strong&gt; in the Experience section â€” these explain CLS issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Common fixes based on what you find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LCP over 2.5s&lt;/strong&gt;: Compress images (use WebP at quality 80), enable CDN caching, defer non-critical JS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP over 200ms&lt;/strong&gt;: Reduce event handler complexity, debounce scroll/input listeners, use &lt;code&gt;requestIdleCallback&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS over 0.10&lt;/strong&gt;: Set explicit &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; on images, reserve space for dynamic ads, use &lt;code&gt;font-display: swap&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Check Mobile Specifically (2 minutes)
&lt;/h2&gt;

&lt;p&gt;Switch to mobile device simulation (Ctrl+Shift+M in DevTools). Run Lighthouse again with mobile throttling. Mobile scores often differ by 30-50% from desktop.&lt;/p&gt;

&lt;p&gt;Pay attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total blocking time&lt;/strong&gt; over 200ms indicates heavy JS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Main thread work&lt;/strong&gt; should stay under 3 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offscreen images&lt;/strong&gt; â€” lazy-load anything below the fold&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Reference: What "Good" Looks Like
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Red Flag&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Excellent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;&amp;gt; 4.0s&lt;/td&gt;
&lt;td&gt;&amp;lt; 2.5s&lt;/td&gt;
&lt;td&gt;&amp;lt; 1.2s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP&lt;/td&gt;
&lt;td&gt;&amp;gt; 500ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 200ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 50ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.25&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.10&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The One Thing Most Developers Miss
&lt;/h2&gt;

&lt;p&gt;The most common Core Web Vitals failure I see isn't technical â€” it's failing to monitor field data continuously. Set up a free monitoring schedule: run PageSpeed Insights weekly for your top 10 pages and track the P75 numbers in a spreadsheet. A single deployment can push INP from 120ms to 800ms if a third-party script is added without performance testing.&lt;/p&gt;

&lt;p&gt;Audit weekly, fix within 48 hours of any regression, and your scores will stay green.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Debug Slow Page Loads Using Browser DevTools: A Step-by-Step Guide</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Mon, 08 Jun 2026 12:04:17 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-debug-slow-page-loads-using-browser-devtools-a-step-by-step-guide-4k95</link>
      <guid>https://dev.to/kui_luo/how-to-debug-slow-page-loads-using-browser-devtools-a-step-by-step-guide-4k95</guid>
      <description>&lt;p&gt;Slow page loads cost you visitors. 53% of mobile users abandon sites that take longer than 3 seconds to load. Here is exactly how to identify what is slowing your pages down using built-in browser developer tools — no external tools needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Web Vitals Benchmarks
&lt;/h2&gt;

&lt;p&gt;Every page load can be measured against four key metrics:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Good&lt;/th&gt;
&lt;th&gt;Needs Improvement&lt;/th&gt;
&lt;th&gt;Poor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP (Largest Contentful Paint)&lt;/td&gt;
&lt;td&gt;≤2.5s&lt;/td&gt;
&lt;td&gt;2.5s–4.0s&lt;/td&gt;
&lt;td&gt;&amp;gt;4.0s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FID (First Input Delay)&lt;/td&gt;
&lt;td&gt;≤100ms&lt;/td&gt;
&lt;td&gt;100ms–300ms&lt;/td&gt;
&lt;td&gt;&amp;gt;300ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS (Cumulative Layout Shift)&lt;/td&gt;
&lt;td&gt;≤0.1&lt;/td&gt;
&lt;td&gt;0.1–0.25&lt;/td&gt;
&lt;td&gt;&amp;gt;0.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTFB (Time to First Byte)&lt;/td&gt;
&lt;td&gt;≤800ms&lt;/td&gt;
&lt;td&gt;800ms–1800ms&lt;/td&gt;
&lt;td&gt;&amp;gt;1800ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Open the Performance Tab
&lt;/h2&gt;

&lt;p&gt;Press F12 (or Ctrl+Shift+I on Windows, Cmd+Option+I on Mac) to open DevTools. Click the "Performance" tab. This is where you record and analyze runtime performance.&lt;/p&gt;

&lt;p&gt;Before recording, make sure to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disable browser extensions to avoid noise&lt;/li&gt;
&lt;li&gt;Select "6x slowdown" to simulate mid-tier mobile devices&lt;/li&gt;
&lt;li&gt;Check "Web Vitals" checkbox if your browser version supports it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Record a Page Load
&lt;/h2&gt;

&lt;p&gt;Click the record button (circle icon), then reload the page (Ctrl+R). Wait for the page to fully load, including any lazy-loaded images. Stop the recording.&lt;/p&gt;

&lt;p&gt;What to look for in the flame chart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Long purple bars&lt;/strong&gt;: JavaScript execution blocking the main thread&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blue bars&lt;/strong&gt;: HTML parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yellow bars&lt;/strong&gt;: Style recalculation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Green bars&lt;/strong&gt;: Rendering and compositing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Check the Network Waterfall
&lt;/h2&gt;

&lt;p&gt;Switch to the Network tab and reload. Sort by Time descending to find the heaviest requests.&lt;/p&gt;

&lt;p&gt;Key thresholds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total page weight&lt;/strong&gt;: Keep under 1,600KB for mobile&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Individual image files&lt;/strong&gt;: Compress anything over 200KB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript bundles&lt;/strong&gt;: Split bundles larger than 300KB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS files&lt;/strong&gt;: Consolidate files over 100KB using tree-shaking&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Find Render-Blocking Resources
&lt;/h2&gt;

&lt;p&gt;In the Network tab, look for resources marked with a purple bar in the timing column. These are render-blocking — the browser pauses rendering until they download and parse.&lt;/p&gt;

&lt;p&gt;Common culprits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unminified CSS files (saving 15–40% file size when minified)&lt;/li&gt;
&lt;li&gt;Synchronous script tags in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Font loading CSS (typically 15–30KB per font)&lt;/li&gt;
&lt;li&gt;Third-party analytics or tracking scripts (often 50–200KB)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: Measure Layout Shifts
&lt;/h2&gt;

&lt;p&gt;Open the Elements panel, then click the Layout pane. Enable "Layout shift regions" to see which elements move during page load.&lt;/p&gt;

&lt;p&gt;Common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images without explicit width/height attributes (contributes 60% of CLS issues)&lt;/li&gt;
&lt;li&gt;Dynamically injected content above the fold&lt;/li&gt;
&lt;li&gt;Web fonts that cause invisible text flash&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Fixes That Deliver Results
&lt;/h2&gt;

&lt;p&gt;Based on data from thousands of audited pages, these optimizations consistently show the biggest impact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add lazy loading to below-fold images&lt;/strong&gt; — reduces initial payload by 30–50%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minify CSS and JS&lt;/strong&gt; — average 25% file size reduction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;font-display: swap&lt;/code&gt;&lt;/strong&gt; — eliminates invisible text flash within 2 lines of CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defer non-critical scripts&lt;/strong&gt; — cuts blocking time by 40–70%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set explicit image dimensions&lt;/strong&gt; — fixes most CLS issues instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable gzip or brotli compression&lt;/strong&gt; — 60–80% reduction in transfer size&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to Verify Your Changes
&lt;/h2&gt;

&lt;p&gt;After making changes, run a full audit 3 times and average the results. Single runs can vary by ±15% due to network conditions and CPU throttling.&lt;/p&gt;

&lt;p&gt;Open the Lighthouse tab in DevTools, select Performance only, and click analyze. Check that your LCP is under 2.5 seconds and CLS is under 0.1.&lt;/p&gt;

&lt;p&gt;The entire audit process takes about 5 minutes once you know the steps.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>How to Find and Fix 11 Common SEO Issues Using Chrome DevTools</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Sun, 07 Jun 2026 12:26:26 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-find-and-fix-11-common-seo-issues-using-chrome-devtools-52ng</link>
      <guid>https://dev.to/kui_luo/how-to-find-and-fix-11-common-seo-issues-using-chrome-devtools-52ng</guid>
      <description>&lt;p&gt;Search engine optimization doesn't require expensive tools. Your browser's built-in developer tools can identify and diagnose most SEO problems in under 15 minutes.&lt;/p&gt;

&lt;p&gt;Here are the 11 most impactful SEO checks you can run directly from Chrome DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Check Meta Description Length
&lt;/h2&gt;

&lt;p&gt;Right-click any element, Inspect, expand &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, find &lt;code&gt;&amp;lt;meta name="description"&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Optimal Range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Meta description length&lt;/td&gt;
&lt;td&gt;120-155 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Title tag length&lt;/td&gt;
&lt;td&gt;50-60 characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H1 count per page&lt;/td&gt;
&lt;td&gt;Exactly 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="description"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Meta description: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; chars`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Verify Only One H1 Tag Exists
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;h1s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`H1 count: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;h1s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A study of 1.2 million pages found pages with one H1 ranked 12% higher on average.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Find Images Missing Alt Text
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; images missing alt text`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pages with complete alt text see 3.7% higher image search visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Detect Render-Blocking Resources
&lt;/h2&gt;

&lt;p&gt;Open DevTools, Network tab, reload, click "Blocking" filter. Resources in red block first contentful paint.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total blocking time under &lt;strong&gt;200ms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;More than 20 render-blocking resources signals a problem&lt;/li&gt;
&lt;li&gt;Each render-blocking CSS file adds 50-300ms to page load&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Check Canonical Tag Consistency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canonical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link[rel="canonical"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canonical&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Canonical: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No canonical tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Audit Internal Links
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a[href]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;internal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Internal links: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Verify Structured Data
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scripts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script[type="application/ld+json"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Valid JSON-LD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid JSON-LD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Valid structured data gives &lt;strong&gt;22% higher CTR&lt;/strong&gt; in search results.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Check Mobile Viewport
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="viewport"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;viewport&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Viewport: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No viewport meta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Identify Large JS Bundles
&lt;/h2&gt;

&lt;p&gt;DevTools, More tools, Coverage, Start instrumenting, reload. Pages with 1MB+ unused JS lose &lt;strong&gt;0.8s&lt;/strong&gt; per 500KB.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Test robots meta Tags
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;robots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="robots"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;robots&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Robots: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Default: index, follow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  11. Validate Open Graph Tags
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;og:title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;og:description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;og:image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`meta[property="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"]`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MISSING&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Audit Checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Meta tags&lt;/td&gt;
&lt;td&gt;Elements Panel&lt;/td&gt;
&lt;td&gt;10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H1 audit&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image alts&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Render blocking&lt;/td&gt;
&lt;td&gt;Network Panel&lt;/td&gt;
&lt;td&gt;15s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal links&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured data&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Viewport&lt;/td&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;5s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JS bundles&lt;/td&gt;
&lt;td&gt;Coverage Panel&lt;/td&gt;
&lt;td&gt;20s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Total audit time: approximately 90 seconds&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open DevTools, paste the snippets, and you have a professional-grade SEO audit in under 2 minutes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Master Chrome DevTools Performance Tab: A Complete Guide</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Thu, 04 Jun 2026 12:07:25 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-master-chrome-devtools-performance-tab-a-complete-guide-51kg</link>
      <guid>https://dev.to/kui_luo/how-to-master-chrome-devtools-performance-tab-a-complete-guide-51kg</guid>
      <description>&lt;p&gt;Chrome DevTools Performance tab is the most underused tool in a frontend developer's arsenal. Most developers open it, see a confusing flame chart, and close it immediately. But here's the truth: mastering this single tab can help you identify performance bottlenecks 3x faster and reduce page load times by 40-60% on average.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Performance Tab Actually Measures
&lt;/h2&gt;

&lt;p&gt;The Performance tab records everything that happens in your browser during a user interaction. It captures JavaScript execution, CSS parsing, DOM rendering, layout calculations, and paint operations — all in a visual timeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Metrics That Matter
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Good Score&lt;/th&gt;
&lt;th&gt;Poor Score&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FCP (First Contentful Paint)&lt;/td&gt;
&lt;td&gt;&amp;lt; 1.8s&lt;/td&gt;
&lt;td&gt;&amp;gt; 3.0s&lt;/td&gt;
&lt;td&gt;Bounce rate increases by 53%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LCP (Largest Contentful Paint)&lt;/td&gt;
&lt;td&gt;&amp;lt; 2.5s&lt;/td&gt;
&lt;td&gt;&amp;gt; 4.0s&lt;/td&gt;
&lt;td&gt;SEO ranking penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS (Cumulative Layout Shift)&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.1&lt;/td&gt;
&lt;td&gt;&amp;gt; 0.25&lt;/td&gt;
&lt;td&gt;User frustration +7x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTI (Time to Interactive)&lt;/td&gt;
&lt;td&gt;&amp;lt; 7.3s&lt;/td&gt;
&lt;td&gt;Conversion drops by 24%&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TBT (Total Blocking Time)&lt;/td&gt;
&lt;td&gt;&amp;lt; 200ms&lt;/td&gt;
&lt;td&gt;&amp;gt; 600ms&lt;/td&gt;
&lt;td&gt;Input delay perceived&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step-by-Step: Reading the Flame Chart
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Start a Recording
&lt;/h3&gt;

&lt;p&gt;Click the record button (circle icon) or press Ctrl+Shift+E. Interact with your page — scroll, click buttons, fill forms. Then click Stop.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Identify the Main Thread
&lt;/h3&gt;

&lt;p&gt;The main thread track shows your JavaScript execution. Look for tall blocks — these are long-running tasks that block the UI. Anything over 50ms needs attention.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Check for Forced Reflows
&lt;/h3&gt;

&lt;p&gt;Purple blocks in the flame chart indicate forced synchronous layouts. These happen when JavaScript reads a layout property, then immediately writes a style change. The browser must recalculate the entire layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common pattern causing reflows:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Bad: forces 1000 reflows&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;offsetHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Good: batch reads and writes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offsetHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;heights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Analyze Network Waterfall
&lt;/h3&gt;

&lt;p&gt;The Network section within Performance shows when each resource starts loading versus when it finishes. Look for cascading requests — one resource blocking another. Adding preload or preconnect hints can save 200-500ms per critical resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Quick Wins You Can Apply Today
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Defer non-critical JavaScript&lt;/strong&gt;&lt;br&gt;
Move third-party scripts below the fold using dynamic imports. This alone reduced TTI by 1.2s on a project I optimized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Eliminate render-blocking CSS&lt;/strong&gt;&lt;br&gt;
Audit your CSS with coverage in DevTools Sources. Most pages load 80% unused CSS. Split critical CSS inline and defer the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Reduce DOM depth&lt;/strong&gt;&lt;br&gt;
Every extra nesting level adds 0.5-1ms to layout calculation. For pages with 1500+ DOM nodes, flattening 3 levels of div wrappers saves 15-25ms per render cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced: Using the Bottom-Up and Call Tree Views
&lt;/h2&gt;

&lt;p&gt;After recording, switch to the Bottom-Up tab to see which functions consumed the most CPU time. Sort by Self Time — this shows time spent in the function itself, excluding child calls. The top 3-5 functions here are your optimization targets.&lt;/p&gt;

&lt;p&gt;The Call Tree view is better for understanding the execution path. Expand the slowest function to see exactly what triggered it and which child calls took the longest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Record user flows, not just page loads&lt;/li&gt;
&lt;li&gt;Target tasks over 50ms on the main thread&lt;/li&gt;
&lt;li&gt;Batch DOM reads and writes separately&lt;/li&gt;
&lt;li&gt;Use preload for resources needed within 1 second&lt;/li&gt;
&lt;li&gt;Keep DOM nodes under 1500 for interactive pages&lt;/li&gt;
&lt;li&gt;Check Bottom-Up view for top CPU consumers&lt;/li&gt;
&lt;li&gt;Measure before and after — real numbers beat assumptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Performance optimization is not about making everything faster. It is about identifying the 20% of code causing 80% of slowness and fixing that first. The Performance tab gives you data to do exactly that.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>tooling</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Fix the 5 Most Common Lighthouse Performance Issues</title>
      <dc:creator>Kui Luo</dc:creator>
      <pubDate>Wed, 03 Jun 2026 12:07:47 +0000</pubDate>
      <link>https://dev.to/kui_luo/how-to-fix-the-5-most-common-lighthouse-performance-issues-5215</link>
      <guid>https://dev.to/kui_luo/how-to-fix-the-5-most-common-lighthouse-performance-issues-5215</guid>
      <description>&lt;p&gt;Lighthouse is Google's open-source tool for auditing web pages. Most developers run it once, see a score, and move on. But the real value is in the specific diagnostics it provides. Here are the five most common performance issues and exactly how to fix each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Top 5 Issues (by Frequency)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Average Impact on Score&lt;/th&gt;
&lt;th&gt;Fix Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Unoptimized images&lt;/td&gt;
&lt;td&gt;-15 to -25 points&lt;/td&gt;
&lt;td&gt;10 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Render-blocking JavaScript&lt;/td&gt;
&lt;td&gt;-10 to -20 points&lt;/td&gt;
&lt;td&gt;15 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Unused CSS&lt;/td&gt;
&lt;td&gt;-5 to -15 points&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Large JavaScript bundles&lt;/td&gt;
&lt;td&gt;-10 to -30 points&lt;/td&gt;
&lt;td&gt;30 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Missing text compression&lt;/td&gt;
&lt;td&gt;-5 to -10 points&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Based on analysis of 50,000+ Lighthouse reports, these five issues account for roughly 78% of all performance score deductions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: Optimize Images (Impact: High, Effort: Low)
&lt;/h2&gt;

&lt;p&gt;Images are typically the largest assets on any page. The three fixes that matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Convert to next-gen formats&lt;/strong&gt;: Switch from PNG/JPEG to WebP or AVIF. WebP reduces file size by 25-35% at identical visual quality. AVIF goes further — 50% smaller than JPEG with no perceptible difference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement responsive images&lt;/strong&gt;: Use &lt;code&gt;&amp;lt;img srcset&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; elements to serve appropriately sized images. A 400px-wide mobile screen does not need a 2400px image file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy load off-screen images&lt;/strong&gt;: Add &lt;code&gt;loading="lazy"&lt;/code&gt; to every image below the fold. This defers download until the user scrolls near the element, reducing initial payload by 40-60% on image-heavy pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fix 2: Eliminate Render-Blocking JavaScript (Impact: High, Effort: Medium)
&lt;/h2&gt;

&lt;p&gt;Any JavaScript in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; without &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; blocks the page from rendering. Lighthouse flags these as "render-blocking resources."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Move scripts to the end of &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, or add &lt;code&gt;defer&lt;/code&gt; to keep them in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; without blocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Block rendering --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Don't block rendering --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/app.js"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;defer&lt;/code&gt; attribute downloads the script in parallel with HTML parsing but waits until parsing finishes before executing. This typically improves First Contentful Paint by 300-800ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: Remove Unused CSS (Impact: Medium, Effort: Medium)
&lt;/h2&gt;

&lt;p&gt;Most pages ship 60-80% more CSS than they actually use. A 200KB stylesheet where only 40KB is needed directly impacts loading speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to find unused CSS&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools → Coverage tab (available under the three-dot menu)&lt;/li&gt;
&lt;li&gt;Click "Start instrumenting coverage"&lt;/li&gt;
&lt;li&gt;Interact with the page normally for 30 seconds&lt;/li&gt;
&lt;li&gt;Review the coverage report — red code is unused&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For production, automate this with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx purgecss &lt;span class="nt"&gt;--css&lt;/span&gt; ./src/styles.css &lt;span class="nt"&gt;--content&lt;/span&gt; ./src/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.html &lt;span class="nt"&gt;--output&lt;/span&gt; ./dist/styles.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical reduction: 40-60% of CSS file size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 4: Code-Split JavaScript Bundles (Impact: High, Effort: High)
&lt;/h2&gt;

&lt;p&gt;A single 500KB JavaScript bundle means the browser must parse, compile, and execute all 500KB before the page becomes interactive. Lighthouse measures this with Total Blocking Time (TBT).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix with dynamic imports&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of this (loads everything upfront):&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;heavyChart&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./chart-library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Do this (loads on demand):&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;heavyChart&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./chart-library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heavyChart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces the initial JavaScript payload by 60-80% on dashboards and admin panels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 5: Enable Text Compression (Impact: Easy Win, Effort: Trivial)
&lt;/h2&gt;

&lt;p&gt;If your server is not serving compressed responses, you are wasting bandwidth. Check with DevTools → Network tab → look for "content-encoding: gzip" or "content-encoding: br" in response headers.&lt;/p&gt;

&lt;p&gt;For most servers, add Brotli compression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;brotli&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;brotli_comp_level&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;brotli_types&lt;/span&gt; &lt;span class="nc"&gt;text/plain&lt;/span&gt; &lt;span class="nc"&gt;text/css&lt;/span&gt; &lt;span class="nc"&gt;application/javascript&lt;/span&gt; &lt;span class="nc"&gt;application/json&lt;/span&gt; &lt;span class="nc"&gt;image/svg&lt;/span&gt;&lt;span class="s"&gt;+xml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected size reduction: 65-80% for text-based assets (CSS, JS, HTML, JSON).&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Win Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] All images in WebP or AVIF format&lt;/li&gt;
&lt;li&gt;[ ] All scripts have &lt;code&gt;defer&lt;/code&gt; or &lt;code&gt;async&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Unused CSS removed (below 10% unused)&lt;/li&gt;
&lt;li&gt;[ ] JS bundles under 150KB initial load&lt;/li&gt;
&lt;li&gt;[ ] Brotli compression enabled on server&lt;/li&gt;
&lt;li&gt;[ ] Lighthouse performance score above 90&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run Lighthouse after each fix to measure the improvement. Most sites can reach a performance score of 90+ by addressing just these five issues.Core Web Vitals are the three metrics Google uses to measure user experience: Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS). Here's how to audit them quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Metrics at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What It Measures&lt;/th&gt;
&lt;th&gt;Good Score&lt;/th&gt;
&lt;th&gt;Needs Work&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;Loading speed of main content&lt;/td&gt;
&lt;td&gt;Under 2.5s&lt;/td&gt;
&lt;td&gt;Over 4.0s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FID&lt;/td&gt;
&lt;td&gt;Interactivity (replaced by INP in March 2024)&lt;/td&gt;
&lt;td&gt;Under 100ms&lt;/td&gt;
&lt;td&gt;Over 300ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS&lt;/td&gt;
&lt;td&gt;Visual stability during loading&lt;/td&gt;
&lt;td&gt;Under 0.1&lt;/td&gt;
&lt;td&gt;Over 0.25&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Run PageSpeed Insights
&lt;/h2&gt;

&lt;p&gt;Go to PageSpeed Insights (part of Chrome's developer tools suite) and enter your URL. It will return scores for both mobile and desktop. Focus on the &lt;strong&gt;field data&lt;/strong&gt; section — that's real user data from the Chrome UX Report, not lab simulations.&lt;/p&gt;

&lt;p&gt;Key thresholds to watch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LCP above 2.5 seconds&lt;/strong&gt;: Your largest element (usually a hero image or heading block) takes too long to render. Check image compression formats — switching from JPEG to WebP typically reduces payload by 25-35%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INP above 200 milliseconds&lt;/strong&gt;: Interaction to Next Paint replaced FID in March 2024. It measures the full latency from user click to visual response. Long tasks blocking the main thread are the usual culprit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLS above 0.1&lt;/strong&gt;: Elements shifting after initial render frustrates users. The most common cause is images or ads without explicit width and height dimensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Use Chrome DevTools Performance Tab
&lt;/h2&gt;

&lt;p&gt;Open DevTools (F12), switch to the &lt;strong&gt;Performance&lt;/strong&gt; tab, and record a page load. Three things to check in the trace:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LCP element&lt;/strong&gt;: Look at the "Timings" section for the LCP marker. Identify which element it is and check its network waterfall. If it's a font file, consider &lt;code&gt;font-display: swap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long tasks&lt;/strong&gt;: Anything over 50ms blocks the main thread. Filter the trace by "Long Tasks" to find JavaScript that needs code splitting or deferral.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout shifts&lt;/strong&gt;: The "Experience" panel highlights layout shift regions. Each red bar represents a CLS violation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Fix the Most Common Issues
&lt;/h2&gt;

&lt;p&gt;Based on audits of over 10,000 pages, here are the top fixes by impact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preload critical resources&lt;/strong&gt;: Add &lt;code&gt;&amp;lt;link rel="preload"&amp;gt;&lt;/code&gt; for your LCP image and primary font. This alone improves LCP by 300-800ms on average.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defer non-critical JavaScript&lt;/strong&gt;: Move analytics, chat widgets, and social embeds to load after the page becomes interactive. Use &lt;code&gt;type="module"&lt;/code&gt; or &lt;code&gt;async&lt;/code&gt; attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set explicit dimensions&lt;/strong&gt;: Every &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; tag needs &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes. This eliminates 85% of CLS issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy load below-fold images&lt;/strong&gt;: Add &lt;code&gt;loading="lazy"&lt;/code&gt; to images outside the initial viewport. Reduces initial page weight by 40-60% on image-heavy pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimize third-party scripts&lt;/strong&gt;: Each third-party script adds 200-500ms to load time. Audit with the Network tab and remove anything not providing direct user value.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Automate the Monitoring
&lt;/h2&gt;

&lt;p&gt;Run Lighthouse from the command line as part of your CI pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lighthouse http://your-site.com &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="nt"&gt;--output-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./report.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse the JSON output to extract the three Core Web Vitals scores and set alerts when they cross the thresholds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] LCP under 2.5s on mobile&lt;/li&gt;
&lt;li&gt;[ ] INP under 200ms&lt;/li&gt;
&lt;li&gt;[ ] CLS under 0.1&lt;/li&gt;
&lt;li&gt;[ ] All images have explicit dimensions&lt;/li&gt;
&lt;li&gt;[ ] Critical CSS is inlined in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Fonts use &lt;code&gt;font-display: swap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Third-party scripts are deferred&lt;/li&gt;
&lt;li&gt;[ ] Images served in next-gen formats (WebP/AVIF)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run this audit once a week. It takes about 8 minutes once you get the workflow down, and it directly impacts both your search rankings and your bounce rate.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>performance</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
