mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
feat: add skeleton loader to prevent FOUC during CSS load
Replace unstyled content flash with pulsing gray placeholder shapes while the deferred Tailwind stylesheet loads. Uses a 'loading' class on <html> that critical CSS uses to show skeleton / hide content, removed by the stylesheet's onload handler. Includes noscript fallback to bypass skeleton when JS is disabled. Confab-Link: http://localhost:8080/sessions/edb1b7b0-da66-4486-bd9c-d1cfa7553b88
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ site.locale | default('en') }}">
|
||||
<html lang="{{ site.locale | default('en') }}" class="loading">
|
||||
<head>
|
||||
{# OG image resolution handled by og-fix transform in eleventy.config.js
|
||||
to bypass Eleventy 3.x parallel rendering race condition (#3183).
|
||||
@@ -57,7 +57,7 @@
|
||||
{# Critical CSS — inlined for fast first paint #}
|
||||
<style>{{ "css/critical.css" | inlineFile | safe }}</style>
|
||||
{# 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'">
|
||||
<link rel="stylesheet" href="/css/style.css?v={{ '/css/style.css' | hash }}" media="print" onload="this.media='all';document.documentElement.classList.remove('loading')">
|
||||
<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'">
|
||||
<noscript><link rel="stylesheet" href="/css/prism-theme.css?v={{ '/css/prism-theme.css' | hash }}"></noscript>
|
||||
@@ -89,6 +89,9 @@
|
||||
[x-data] > .flex.border-b { display: none !important; }
|
||||
/* Hide loading spinners and JS-only buttons */
|
||||
[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) */
|
||||
.page-skeleton { display: none !important; }
|
||||
html.loading main.container > .page-content { display: block !important; }
|
||||
</style>
|
||||
</noscript>
|
||||
<link rel="canonical" href="{{ site.url }}{{ page.url }}">
|
||||
@@ -277,6 +280,23 @@
|
||||
</header>
|
||||
|
||||
<main class="container py-8" 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 %}
|
||||
{# Homepage: builder controls its own layout and sidebar #}
|
||||
{{ content | safe }}
|
||||
@@ -301,6 +321,7 @@
|
||||
{% else %}
|
||||
{{ content | safe }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="border-t border-surface-200 dark:border-surface-700 mt-12 pt-8 pb-6">
|
||||
|
||||
@@ -59,3 +59,11 @@ a{color:#b45309}
|
||||
/* Prevent FOUC — constrain images and SVG icons before Tailwind loads */
|
||||
img{max-width:100%;height:auto}
|
||||
svg:not(:root):not([width]){width:1.25rem;height:1.25rem}
|
||||
|
||||
/* 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%}
|
||||
|
||||
Reference in New Issue
Block a user