From 17c21b2b8f962d2b9325dadf8122019e64b929f0 Mon Sep 17 00:00:00 2001 From: Ricardo Date: Mon, 9 Mar 2026 00:19:20 +0100 Subject: [PATCH] =?UTF-8?q?perf:=20fix=20desktop=20CLS=20(0.57)=20?= =?UTF-8?q?=E2=80=94=20grid=20match,=20font-display=20optional,=20avatar?= =?UTF-8?q?=20sizing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three root causes identified via PageSpeed layout shift culprits: 1. Grid mismatch (CLS 0.495): Critical CSS used `2fr 1fr` but Tailwind compiles to `repeat(3, minmax(0, 1fr))` with `grid-column: span 2`. Updated critical CSS to match Tailwind's exact output. 2. Font swap FOUT (CLS 0.074): @font-face declarations were only in the deferred stylesheet. Moved to critical CSS with font-display:optional and added for weights 400/600/700. Changed all font-display from swap to optional in tailwind.css source. 3. Avatar resize: HTML width/height was 96x96 but CSS sets sm:w-32/h-32 (128px) on desktop. Updated attributes to 128x128. Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88 --- _includes/layouts/base.njk | 5 +++++ _includes/layouts/home.njk | 4 ++-- css/critical.css | 14 +++++++++++--- css/tailwind.css | 16 ++++++++-------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/_includes/layouts/base.njk b/_includes/layouts/base.njk index 49bab81..492a41f 100644 --- a/_includes/layouts/base.njk +++ b/_includes/layouts/base.njk @@ -54,6 +54,11 @@ + {# Preload critical fonts — starts download before CSS is parsed #} + + + + {# Critical CSS — inlined for fast first paint #} {# Defer full stylesheet — loads after first paint #} diff --git a/_includes/layouts/home.njk b/_includes/layouts/home.njk index 1a90b60..f626251 100644 --- a/_includes/layouts/home.njk +++ b/_includes/layouts/home.njk @@ -15,8 +15,8 @@ withSidebar: true {{ site.author.name }} diff --git a/css/critical.css b/css/critical.css index f6261f9..c099de9 100644 --- a/css/critical.css +++ b/css/critical.css @@ -41,13 +41,21 @@ body{background-color:#faf8f5;color:#1c1b19} main.container{padding-top:1.5rem;padding-bottom:1.5rem} @media(min-width:768px){main.container{padding-top:2rem;padding-bottom:2rem}} -/* Layout with sidebar */ -.layout-with-sidebar{display:grid;grid-template-columns:1fr;gap:1.5rem} -@media(min-width:1024px){.layout-with-sidebar{grid-template-columns:2fr 1fr;gap:2rem}} +/* Layout with sidebar — must match Tailwind's compiled output exactly to prevent CLS */ +.layout-with-sidebar{display:grid;grid-template-columns:repeat(1,minmax(0,1fr));gap:1.5rem} +@media(min-width:768px){.layout-with-sidebar{gap:2rem}} +@media(min-width:1024px){.layout-with-sidebar{grid-template-columns:repeat(3,minmax(0,1fr))}} .main-content{min-width:0;overflow-x:hidden} +@media(min-width:1024px){.main-content{grid-column:span 2/span 2}} /* Reserve sidebar space on desktop to prevent CLS when Alpine.js hydrates collapsible widgets */ @media(min-width:1024px){.sidebar{min-height:600px}} +/* Font faces — in critical CSS so fonts begin downloading immediately. + font-display:optional prevents FOUT/CLS: font either loads in time or fallback is kept. */ +@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:400;src:url(/fonts/inter-latin-400-normal.woff2) format('woff2')} +@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:600;src:url(/fonts/inter-latin-600-normal.woff2) format('woff2')} +@font-face{font-family:'Inter';font-style:normal;font-display:optional;font-weight:700;src:url(/fonts/inter-latin-700-normal.woff2) format('woff2')} + /* Basic typography — prevent FOUT */ h1,h2,h3,h4{margin:0;line-height:1.25} a{color:#b45309} diff --git a/css/tailwind.css b/css/tailwind.css index 5607dcc..e4895cb 100644 --- a/css/tailwind.css +++ b/css/tailwind.css @@ -2,7 +2,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 400; src: url(/fonts/inter-latin-ext-400-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; @@ -10,7 +10,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 400; src: url(/fonts/inter-latin-400-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; @@ -18,7 +18,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 500; src: url(/fonts/inter-latin-ext-500-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; @@ -26,7 +26,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 500; src: url(/fonts/inter-latin-500-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; @@ -34,7 +34,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 600; src: url(/fonts/inter-latin-ext-600-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; @@ -42,7 +42,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 600; src: url(/fonts/inter-latin-600-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; @@ -50,7 +50,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 700; src: url(/fonts/inter-latin-ext-700-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; @@ -58,7 +58,7 @@ @font-face { font-family: 'Inter'; font-style: normal; - font-display: swap; + font-display: optional; font-weight: 700; src: url(/fonts/inter-latin-700-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;