Dark Mode and Theming
as-folio ships with a polished dark mode implementation that matches al-folio’s visual identity. The toggle is in the navbar (☀/☽ icon). Preference is persisted to localStorage and restored before the page renders to avoid any flash of unstyled content.
How it works
1. FOUC prevention
An inline <script> in <head> — before any stylesheet — reads localStorage and sets data-theme="dark" on <html> before the browser paints:
// Runs synchronously before first paint
const theme = localStorage.getItem('theme') ?? 'light';
document.documentElement.setAttribute('data-theme', theme);
Because this script is is:inline in Astro, it is never deferred or bundled — it runs at the earliest possible moment.
2. CSS custom properties
All colours live in src/styles/_colors.css as CSS custom properties, mirroring al-folio’s variable names exactly:
:root {
--global-bg-color: #ffffff;
--global-text-color: #000000;
--global-theme-color: #b509ac;
/* ... */
}
[data-theme='dark'] {
--global-bg-color: #1c1c1c;
--global-text-color: #ffffff;
--global-theme-color: #b509ac; /* same accent in dark */
/* ... */
}
Every component references these variables rather than hard-coded colours, so toggling data-theme instantly re-paints the whole page without a single JavaScript re-render.
3. The toggle component
ThemeToggle.astro writes to localStorage and updates data-theme:
<script>
const toggle = document.getElementById('theme-toggle');
toggle?.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
});
</script>
4. Giscus comment theme sync
When comments are enabled, Giscus.astro observes data-theme changes with a MutationObserver and posts a message to the Giscus <iframe> to switch its own theme:
new MutationObserver(() => {
const theme = document.documentElement.getAttribute('data-theme');
giscusFrame.contentWindow.postMessage(
{ giscus: { setConfig: { theme: theme === 'dark' ? 'dark' : 'light' } } },
'https://giscus.app',
);
}).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
Customising the accent colour
The theme colour is set in src/config/site.ts as a comment/reference, but the actual CSS variables are in src/styles/_colors.css. To change the accent, update --global-theme-color (and optionally --global-hover-color) in both :root and [data-theme="dark"]:
:root {
--global-theme-color: #0070f3; /* Vercel blue */
--global-hover-color: #005cc5;
}
That’s all — every badge, link highlight, tag pill, and interactive element picks it up automatically.