perf: remove skeleton loader to fix CLS (0.916 mobile / 1.004 desktop)

The skeleton-to-content swap was the root cause of extreme CLS scores.
Critical CSS already provides correct first-paint layout, making the
skeleton unnecessary. Removes html.loading class, skeleton div,
page-content wrapper, and all skeleton CSS rules.

Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
This commit is contained in:
Ricardo
2026-03-08 15:23:27 +01:00
parent 229f770cbb
commit 9e8f0f139a
2 changed files with 4 additions and 31 deletions
+3 -23
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ site.locale | default('en') }}" class="loading"> <html lang="{{ site.locale | default('en') }}">
<head> <head>
{# OG image resolution handled by og-fix transform in eleventy.config.js {# OG image resolution handled by og-fix transform in eleventy.config.js
to bypass Eleventy 3.x parallel rendering race condition (#3183). to bypass Eleventy 3.x parallel rendering race condition (#3183).
@@ -57,7 +57,7 @@
{# Critical CSS — inlined for fast first paint #} {# Critical CSS — inlined for fast first paint #}
<style>{{ "css/critical.css" | inlineFile | safe }}</style> <style>{{ "css/critical.css" | inlineFile | safe }}</style>
{# Defer full stylesheet — loads after first paint #} {# Defer full stylesheet — loads after first paint #}
<link rel="stylesheet" href="/css/style.css?v={{ '/css/style.css' | hash }}" media="print" onload="this.media='all';document.documentElement.classList.remove('loading')"> <link rel="stylesheet" href="/css/style.css?v={{ '/css/style.css' | hash }}" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/style.css?v={{ '/css/style.css' | hash }}"></noscript> <noscript><link rel="stylesheet" href="/css/style.css?v={{ '/css/style.css' | hash }}"></noscript>
<link rel="stylesheet" href="/css/prism-theme.css?v={{ '/css/prism-theme.css' | hash }}" media="print" onload="this.media='all'"> <link rel="stylesheet" href="/css/prism-theme.css?v={{ '/css/prism-theme.css' | hash }}" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/css/prism-theme.css?v={{ '/css/prism-theme.css' | hash }}"></noscript> <noscript><link rel="stylesheet" href="/css/prism-theme.css?v={{ '/css/prism-theme.css' | hash }}"></noscript>
@@ -90,9 +90,7 @@
[x-data] > .flex.border-b { display: none !important; } [x-data] > .flex.border-b { display: none !important; }
/* Hide loading spinners and JS-only buttons */ /* Hide loading spinners and JS-only buttons */
[x-show*="loading"], button[\\@click*="fetch"], button[\\@click*="loadMore"] { display: none !important; } [x-show*="loading"], button[\\@click*="fetch"], button[\\@click*="loadMore"] { display: none !important; }
/* Show content and hide skeleton for no-JS (stylesheet loads synchronously via noscript link) */ /* Content is always visible — no skeleton loader */
.page-skeleton { display: none !important; }
html.loading main.container > .page-content { display: block !important; }
</style> </style>
</noscript> </noscript>
<link rel="canonical" href="{{ site.url }}{{ page.url }}"> <link rel="canonical" href="{{ site.url }}{{ page.url }}">
@@ -282,23 +280,6 @@
</header> </header>
<main class="container py-8" id="main-content" data-pagefind-body> <main class="container py-8" id="main-content" data-pagefind-body>
{# Skeleton loader — shown until Tailwind stylesheet loads #}
<div class="page-skeleton" aria-hidden="true">
<div style="display:flex;gap:1.5rem;align-items:flex-start;margin-bottom:2rem">
<div class="skel-bone skel-circle" style="width:96px;height:96px;flex-shrink:0"></div>
<div style="flex:1">
<div class="skel-bone" style="height:1.75rem;width:50%;margin-bottom:.75rem"></div>
<div class="skel-bone" style="height:1rem;width:35%;margin-bottom:.75rem"></div>
<div class="skel-bone" style="height:3rem;width:90%"></div>
</div>
</div>
<div class="skel-bone" style="height:5rem;margin-bottom:.75rem"></div>
<div class="skel-bone" style="height:5rem;margin-bottom:.75rem"></div>
<div class="skel-bone" style="height:5rem;margin-bottom:.75rem"></div>
<div class="skel-bone" style="height:5rem"></div>
</div>
<div class="page-content">
{% if withSidebar and page.url == "/" and homepageConfig and homepageConfig.sections %} {% if withSidebar and page.url == "/" and homepageConfig and homepageConfig.sections %}
{# Homepage: builder controls its own layout and sidebar #} {# Homepage: builder controls its own layout and sidebar #}
{{ content | safe }} {{ content | safe }}
@@ -323,7 +304,6 @@
{% else %} {% else %}
{{ content | safe }} {{ content | safe }}
{% endif %} {% endif %}
</div>
</main> </main>
<footer class="border-t border-surface-200 dark:border-surface-700 mt-12 pt-8 pb-6"> <footer class="border-t border-surface-200 dark:border-surface-700 mt-12 pt-8 pb-6">
+1 -8
View File
@@ -72,13 +72,6 @@ button:focus-visible,[type="button"]:focus-visible{outline:2px solid #b45309;out
.skip-link{position:absolute;top:-100%;left:0;z-index:100;background:#b45309;color:#fff;padding:0.5rem 1rem;font-weight:600;text-decoration:none} .skip-link{position:absolute;top:-100%;left:0;z-index:100;background:#b45309;color:#fff;padding:0.5rem 1rem;font-weight:600;text-decoration:none}
.skip-link:focus{top:0;outline:none} .skip-link:focus{top:0;outline:none}
/* Skeleton loader — visible until Tailwind stylesheet loads */
html.loading main.container>.page-content{display:none}
html:not(.loading) .page-skeleton{display:none}
@keyframes skel-pulse{0%,100%{opacity:1}50%{opacity:.4}}
.skel-bone{background:#e8e5df;border-radius:.5rem;animation:skel-pulse 1.5s ease-in-out infinite}
.dark .skel-bone{background:#3f3b35}
.skel-circle{border-radius:50%}
/* Reduced motion — disable animations for users who prefer it */ /* Reduced motion — disable animations for users who prefer it */
@media(prefers-reduced-motion:reduce){.skel-bone{animation:none}*{transition-duration:0.01ms!important;animation-duration:0.01ms!important}} @media(prefers-reduced-motion:reduce){*{transition-duration:0.01ms!important;animation-duration:0.01ms!important}}