L'arte del precicamento: Eliminare il "Flash" del tema con JavaScript e CSS
Publié le 15 November 2025
Riassunto
In questo articolo tecnico approfondito, esploriamo come implementare un selettore di tema (light/dark) senza il fastidioso effetto di lampeggiamento che si verifica durante il caricamento della pagina. Analizziamo nel dettaglio il ciclo di rendering del browser, le cause profonde del FOUC (Flash of Unstyled Content), e proponiamo una soluzione robusta basata sul precaricamento sincrono nel`<head>`. Questa tecnica garantisce un’esperienza utente fluida e professionale.
Il Problema: Questo Maledetto Lampeggiamento del Tema
Un incubo per l’esperienza utente
Immagina la scena: hai trascorso ore a progettare un magnifico tema scuro per la tua applicazione web. I colori sono perfettamente bilanciati, il contrasto è ottimale e i tuoi utenti adorano questa opzione. Ma c’è un problema imbarazzante: ad ogni ricaricamento della pagina, per una frazione di secondo, il tema chiaro di default viene visualizzato prima che il tema scuro prenda il sopravvento.
Questo 'flash' visivo, sebbene breve (a volte meno di 100 ms), è immediatamente percepibile dall’occhio umano e crea un’esperienza sgradevole. Per gli utenti che hanno scelto il tema scuro per motivi di comfort visivo o di accessibilità, questo tremolio può persino risultare doloroso, specialmente in un ambiente poco illuminato.
Il FOUC : Un Vecchio Problema Web
Questo fenomeno è una variante di quello che viene chiamato il "Flash of Unstyled Content" (FOUC), un problema classico dello sviluppo web che risale ai primi giorni del CSS. Il FOUC si verifica quando il browser mostra temporaneamente contenuto HTML senza i suoi stili CSS applicati, creando un lampeggio di contenuto non stilizzato.
Nel nostro caso specifico, non stiamo parlando di un contenuto completamente non stilizzato, ma piuttosto di unLampo del tema sbagliato(FOWT) - il contenuto è stilizzato, ma con il tema sbagliato. Questo è particolarmente frustrante perché dimostra che la nostra applicazione "dimentica" la preferenza dell’utente ad ogni caricamento della pagina.
Impatto sulla Percezione di Qualità
Questo problema, sebbene tecnico, ha ripercussioni importanti sulla percezione della qualità della tua applicazione :
mancanza di rifinituraIl lampeggiamento dà l’impressione di un’applicazione incompleta o mal ottimizzata. Gli utenti associano spesso questi piccoli difetti visivi a una generale mancanza di professionalità.
Rottura di coerenzaL’applicazione sembra "dimenticare" le preferenze dell’utente, creando una sensazione di disallineamento tra l’interfaccia e le aspettative.
Affaticamento visivo: Per gli utenti sensibili alla luce o che soffrono di emicrania, questo flash luminoso può essere più di un semplice disagio estetico.
Performance percepita: Ironicamente, anche se il tuo sito si carica rapidamente, questo sfarfallio può dare l’impressione di un’applicazione lenta o poco reattiva.
Analisi Tecnica del Problema
Per capire come risolvere questo problema, è necessario prima capire perché si verifica. Lo sfarfallio si verifica a causa di uno sfasamento temporale tra tre eventi critici nel ciclo di vita di una pagina web :
-
Il parsing iniziale del HTML: Il browser legge e analizza la struttura della tua pagina
-
L’applicazione degli stili CSSIl navigatore applica le regole CSS e calcola il rendering visivo.
-
L’esecuzione del JavaScriptIl tuo codice che cambia il tema si esegue
Il problema si verifica quando l’evento n°3 (esecuzione del JavaScript) arriva dopo che il browser ha già iniziato o terminato l’evento n°2 (applicazione degli stili). A quel punto, il browser ha già preso una decisione su quale tema visualizzare, e il tuo codice arriva troppo tardi per influenzarlo prima del primo rendering.
Perché uno script classico non basta?
L’approccio intuitivo ma inefficace
L’approccio più naturale per uno sviluppatore sarebbe di posizionare uno script alla fine della nostra`<body>`che verifica il tema preferito dell’utente e lo applica. Questo approccio segue le migliori pratiche tradizionali del web che consigliano di caricare gli script alla fine della pagina per non bloccare il rendering.
// À la fin de <body> - L'APPROCHE INSUFFISANTE
document.addEventListener('DOMContentLoaded', () => {
const theme = localStorage.getItem('preferred-theme');
if (theme === 'dark') {
document.documentElement.setAttribute('data-bs-theme', 'dark');
}
});
Questa approccio sembra logico a prima vista. Attendiamo che il DOM sia pronto, poi applichiamo il tema. Semplice, no? Purtroppo, questa semplicità nasconde un difetto fondamentale legato al timing del ciclo di rendering del browser.
Comprendere l’evento DOMContentLoaded
L’evento`DOMContentLoaded`si attiva quando il documento HTML iniziale è stato completamente caricato e analizzato dal browser,senza attenderela fine del caricamento dei fogli di stile, delle immagini e dei sottocampi. È un punto importante da capire.
Ecco la sequenza tipica degli eventi :
-
Il browser inizia a scaricare l’HTML
-
Analizza l’HTML man mano che lo riceve
-
Lui scopre i tag`<link>`per i CSS e inizia a scaricarli
-
Scopre le etichette`<script>`e li esegue (secondo il loro tipo e attributi)
-
Costruisce il DOM (Document Object Model)
-
L’evento
DOMContentLoadedsi attiva -
Continua ad applicare gli stili e a fare il layout
-
Il primo paint (visualizzazione) si verifica
-
L’evento`load`si attiva quando tutte le risorse sono caricate
Il problema? Tra il passo 6 (DOMContentLoaded) e il passo 8 (primo paint), il browser ha già preso delle decisioni su come visualizzare la pagina. Se lo script di cambio tema viene eseguito al passo 6, è ormai troppo tardi per evitare una prima visualizzazione con gli stili predefiniti.
Il Problema del Render Blocking
In realtà, il timing è ancora più complesso. I browser moderni utilizzano tecniche di ottimizzazione sofisticate per migliorare le prestazioni percepite. Cercano di far avvenire il primo paint (First Contentful Paint) il più rapidamente possibile affinché l’utente veda qualcosa sullo schermo.
I CSS sono "render-blocking" per impostazione predefinita, il che significa che il browser attende di aver scaricato e analizzato i fogli di stile prima di effettuare il primo paint. È logico: non vogliamo mostrare contenuto non stilizzato.
Ma ecco la trappola : quando il browser applica questi stili CSS per la prima volta, lo fa basandosi sullo stato corrente del DOM. Se l’attributo`data-bs-theme`non è ancora definito sul tag`<html>`, il browser applicherà gli stili predefiniti (generalmente il tema chiaro).
Poi, quando il tuo script si esegue e cambia questo attributo, il browser deve :
-
Ricalcolare tutti gli stili interessati da questa modifica
-
Rifare il layout se necessario
-
Riverniciare gli elementi interessati
Questo processo di ricalcolo e di ridipingimento è ciò che causa lo sfarfallio visibile.
Visualizzazione del problema
Per comprendere meglio questa sequenza problematica, esaminiamo un diagramma di sequenza dettagliato:
Failed to generate image: PlantUML preprocessing failed: [From <input> (line 28) ]
@startuml
actor Utilisateur
participant Navigateur
participant "Analizzatore HTML" as Parser
participant "CSSOM" as CSS
participant "Script.js (fine del body)" as Script
participant "Motore di rendering" as Render
Utilisateur -> Navigateur: Demande la page
activate Navigateur
Navigateur -> Parser: Parse le HTML
activate Parser
Parser -> CSS: Découvre et charge les CSS
activate CSS
Parser -> Parser: Construit le DOM
Parser -> Navigateur: DOM Ready (DOMContentLoaded)
deactivate Parser
CSS -> CSS: Parse les feuilles de style
CSS -> Render: CSSOM Ready
deactivate CSS
activate Render
Render -> Render: Calcule les styles avec data-bs-theme=""note right: Tema predefinito (light)
Render -> Navigatore: Primo Paint (Tema Chiaro)
note right: L'utente vede il tema chiaro
disattiva Render
^^^^^
Syntax Error? (Assumed diagram type: sequence)
@startuml
actor Utilisateur
participant Navigateur
participant "Analizzatore HTML" as Parser
participant "CSSOM" as CSS
participant "Script.js (fine del body)" as Script
participant "Motore di rendering" as Render
Utilisateur -> Navigateur: Demande la page
activate Navigateur
Navigateur -> Parser: Parse le HTML
activate Parser
Parser -> CSS: Découvre et charge les CSS
activate CSS
Parser -> Parser: Construit le DOM
Parser -> Navigateur: DOM Ready (DOMContentLoaded)
deactivate Parser
CSS -> CSS: Parse les feuilles de style
CSS -> Render: CSSOM Ready
deactivate CSS
activate Render
Render -> Render: Calcule les styles avec data-bs-theme=""note right: Tema predefinito (light)
Render -> Navigatore: Primo Paint (Tema Chiaro)
note right: L'utente vede il tema chiaro
disattiva Render
Navigatore -> Script: Esegue lo script
attiva Script
Script -> Script: Legge localStorage
Script -> Navigatore: setAttribute('data-bs-theme', 'dark')
disattiva Script
attiva Render
Render -> Render: Recalcola gli stili con data-bs-theme="dark"
note right: Thème sombre
Render -> Navigateur: Repaint (Thème Sombre)
note right: Clignotement visible
deactivate Render
deactivate Navigateur
@enduml
Questo diagramma illustra chiaramente il problema: il primo paint avviene prima che il nostro script abbia avuto la possibilità di impostare il tema corretto. Il repaint successivo crea lo sfarfallio visibile.
Le Tentative di Soluzione Inefficaci
Sono stati provati diversi approcci per risolvere questo problema, ma la maggior parte ha i propri svantaggi :
Approccio 1: Nascondere il contenuto fino al caricamento
body {
opacity: 0;
transition: opacity 0.3s;
}
body.loaded {
opacity: 1;
}
Questa approccio nasconde tutto il contenuto finché JavaScript non imposta il tema corretto. Il problema? Ritarda artificialmente la visualizzazione del contenuto, dando l’impressione di un sito più lento. Inoltre, se JavaScript è disabilitato, l’utente non vede nulla!
Approccio 2 : Utilizzare un loader/spinner
Simile all’approccio 1, ma con uno spinner di caricamento. Questo maschera il problema ma non migliora le prestazioni reali e aggiunge un ritardo percepito inutile.
Approccio 3: Predefinito al tema scuro
Alcuni sviluppatori impostano il tema scuro come predefinito nel CSS. Questo evita lo sfarfallio per gli utenti del tema scuro, ma crea il problema opposto per gli utenti del tema chiaro!
Nessuno di questi approcci è soddisfacente perché tratta il sintomo anziché la causa radice del problema.
La Vera Soluzione: Agire prima
La chiave per risolvere questo problema è rendersi conto che dobbiamo definire l’attributo`data-bs-theme` primache il browser non inizi ad applicare gli stili CSS. Questo significa che il nostro script deve essere eseguito più presto nel ciclo di vita della pagina, ed è esattamente ciò che esploreremo nella sezione successiva.
La Soluzione : Il Caricamento Preventivo (Early Loading)
Il principio fondamentale
La soluzione elegante al nostro problema di sfarfallio si basa su un principio semplice ma potente :sincronizzare lo stato dell’applicazione con il processo di rendering del browser. Invece di aspettare che la pagina si carichi per impostare il tema, dobbiamo impostarloduranteil caricamento, prima ancora che gli stili CSS vengano applicati
Questa approccio si chiama "Early Loading" o "Synchronous Preloading" nel gergo dello sviluppo web. L’idea è di eseguire la nostra logica di rilevamento del tema il più presto possibile nel ciclo di vita della pagina, idealmente nel tag`<head>`, anche prima che il browser inizi a scaricare i file CSS.
Perché il <head> è il posto ideale
Le `<head>`di un documento HTML è elaborato sequenzialmente dal browser, dall’alto verso il basso. Ogni elemento è elaborato nell’ordine in cui appare. Questa caratteristica è fondamentale per la nostra soluzione.
Quando il browser incontra un tag`<script>`nel`<head>`senza gli attributi`async` ou defer, il :
-
Interrompe il parsing del HTML
-
Scarica lo script(se esterno) oppure il letto (se inline)
-
Esegui immediatamente lo script
-
Riprende il parsing dell’HTML
Questo comportamento, spesso considerato come un problema di prestazioni (da cui deriva la consueta raccomandazione di posizionare gli script alla fine della pagina), diventa nostro alleato in questo caso specifico. Posizionando il nostro script di rilevamento del tema all’inizio del`<head>`, garantiamo che venga eseguito prima che il browser incontri i tag`<link>`dei nostri fogli di stile.
Architettura della Soluzione a Tre Livelli
La nostra soluzione completa si compone di tre livelli interdipendenti, ognuno dei quali svolge un ruolo specifico:
Strato 1 : Persistenza (localStorage) Questo livello è responsabile del salvataggio e del recupero della scelta dell’utente tra le sessioni.
Livello 2 : sincronizzazione precoce (Script in linea in <head>) Questo livello sincronizza lo stato dell’applicazione con il DOM prima del rendering iniziale.
Livello 3: Stili reattivi (CSS con selettori di attributi) Questo livello definisce gli stili visivi basati sullo stato definito dal livello 2.
Esploriamo ora ogni strato nel dettaglio.
Passo 1 : Salvare la scelta dell’utente
Il localStorage: La tua memoria persistente
Le localStorage`è un’API Web Storage che permette di memorizzare coppie chiave-valore nel browser in modo persistente. A differenza dei cookie, i dati del`localStorage:
-
Non vengono mai inviate al server automaticamente
-
Hanno una capacità di storage più grande (di solito 5-10 MB)
-
Non hanno una data di scadenza (persistenti fino a cancellazione esplicita)
-
Sono limitate al protocollo e al dominio (Same-Origin Policy)
Per il nostro caso d’uso, il`localStorage`è perfetto perché :
-
Non abbiamo bisogno di condividere questa informazione con il server
-
Vogliamo che la preferenza persista indefinitamente
-
La dimensione di storage richiesta è minima (qualche byte)
Implementazione del salvataggio del tema
Ecco come salviamo la scelta dell’utente quando cambia tema:
// Fonction complète pour changer le thème
function setTheme(newTheme) {
// Validation de l'entrée
if (!['light', 'dark', 'auto'].includes(newTheme)) {
console.error('Thème invalide:', newTheme);
return;
}
try {
// Sauvegarde dans localStorage
localStorage.setItem('preferred-theme', newTheme);
// Application immédiate dans le DOM
document.documentElement.setAttribute('data-bs-theme', newTheme);
// Dispatch d'un événement personnalisé pour notifier d'autres composants
window.dispatchEvent(new CustomEvent('theme-changed', {
detail: { theme: newTheme }
}));
console.log('Thème changé:', newTheme);
} catch (error) {
console.error('Erreur lors de la sauvegarde du thème:', error);
// Fallback : on applique quand même le thème visuellement
document.documentElement.setAttribute('data-bs-theme', newTheme);
}
}
// Exemple d'utilisation avec un bouton
document.getElementById('theme-toggle').addEventListener('click', () => {
const currentTheme = document.documentElement.getAttribute('data-bs-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
});
Gestione dei casi di errore
È fondamentale gestire i casi in cui il`localStorage`non è disponibile o accessibile. Diversi scenari possono impedire l’accesso al`localStorage`:
Navigazione privata stricta: Safari in modalità navigazione privata solleva un’eccezione`QuotaExceededError`durante i tentativi di scrittura in`localStorage`.
Impostazioni sulla privacy: Alcuni browser o estensioni per la privacy possono bloccare l’accesso al`localStorage`.
Limitazioni di dominio : Le `localStorage`non è accessibile sul protocollo`file://`in alcuni browser.
Spazio di archiviazione saturatoSebbene raro, lo spazio di archiviazione può essere completamente pieno.
Per questo motivo il nostro codice utilizza un blocco`try…catch`per gestire questi casi con eleganza, continuando a offrire la funzionalità di cambio di tema anche se la persistenza non è disponibile.
Strategie avanzate di persistenza
Per applicazioni più sofisticate, puoi considerare strategie aggiuntive:
Sincronizzazione server (opzionale)
async function setTheme(newTheme) {
// Sauvegarde locale immédiate
localStorage.setItem('preferred-theme', newTheme);
document.documentElement.setAttribute('data-bs-theme', newTheme);
// Synchronisation serveur en arrière-plan (si l'utilisateur est connecté)
if (userIsAuthenticated()) {
try {
await fetch('/api/user/preferences', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme: newTheme })
});
} catch (error) {
console.warn('Échec de la synchronisation serveur:', error);
// L'échec n'est pas critique car la préférence est déjà sauvegardée localement
}
}
}
Questo approccio permette di sincronizzare le preferenze tra dispositivi per gli utenti connessi, mantenendo al contempo la reattività locale immediata.
Passo 2: Lo Script di Pre-caricamento nel `<head>
Il cuore della soluzione
Qui è dove la magia opera davvero. Posizioneremo un piccolo scriptin lineadirettamente nel nostro`<head>`, prima di tutte le nostre etichette`<link>`di fogli di stile. Questo script è intenzionalmente minimalista, autonomo e progettato per essere eseguito il più rapidamente possibile.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mon Site Incroyable</title>
<!-- ==========================================
NOTRE SCRIPT MAGIQUE DE PRÉ-CHARGEMENT
Ce script DOIT être le premier élément
dans le <head> après les meta tags
========================================== -->
<script>
// IIFE pour ne pas polluer le scope global
(function() {
'use strict';
try {
// Lecture de la préférence sauvegardée
const savedTheme = localStorage.getItem('preferred-theme');
// Si une préférence existe, on l'applique immédiatement
if (savedTheme) {
document.documentElement.setAttribute('data-bs-theme', savedTheme);
}
// Optionnel : Détecter la préférence système si aucune sauvegarde
else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark');
}
// Sinon, le thème par défaut du CSS sera utilisé (généralement 'light')
} catch (error) {
// En cas d'erreur (localStorage bloqué, etc.), on log discrètement
// et on laisse le thème par défaut s'appliquer
console.warn('Impossible de charger la préférence de thème:', error);
}
})();
</script>
<!-- FIN DU SCRIPT MAGIQUE -->
<!-- Les feuilles de style sont chargées APRÈS le script -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/styles.css">
<!-- Autres ressources du head -->
<link rel="icon" href="favicon.ico">
</head>
<body>
<!-- Contenu de la page -->
</body>
</html>
Anatomia dello script: Ogni linea conta
Analizziamo questo script riga per riga per comprendere ogni decisione di design:
L’IIFE (espressione di funzione richiamata immediatamente)
(function() {
// ...
})();
Questa struttura crea una funzione che viene eseguita immediatamente. Perché? Per isolare le nostre variabili in uno scope locale e evitare di inquinare lo scope globale. Anche se ne utilizziamo solo`const`(che ha uno scope di blocco), l’IIFE è una buona pratica che rende le nostre intenzioni chiare e protegge contro eventuali conflitti di nomi
La modalità rigorosa
'use strict';
Questa direttiva attiva la modalità strict di JavaScript, che : - Vietato l’uso di variabili non dichiarate - Genera errori per le operazioni pericolose Migliora le prestazioni in alcuni motori JavaScript
Per uno script critico come questo, vogliamo la massima sicurezza.
Il blocco try…catch
try {
// Code principal
} catch (error) {
console.warn('Impossible de charger la préférence de thème:', error);
}
Questo blocco è assolutamente cruciale. Garantisce che se qualcosa va storto (localStorage bloccato, errore di sintassi improbabile, ecc.), il nostro script non bloccherà il caricamento dell’intera pagina. L’utilizzo di`console.warn`piuttosto che`console.error`indica che è un problema non critico.
La lettura di localStorage
const savedTheme = localStorage.getItem('preferred-theme');
Questa linea può sollevare un’eccezione in alcuni contesti (navigazione privata stretta di Safari). Per questo motivo si trova in un blocco try…catch.
L’Applicazione Condizionale
if (savedTheme) {
document.documentElement.setAttribute('data-bs-theme', savedTheme);
}
Applichiamo il tema solo se ne abbiamo trovato uno salvato. Altrimenti, lasciamo che il CSS utilizzi il suo tema predefinito. Questo approccio è più robusto di un valore predefinito hard‑coded nel JavaScript.
Rilevamento della preferenza di sistema (Bonus)
Un miglioramento opzionale ma elegante consiste nel rilevare la preferenza di tema del sistema operativo dell’utente se non ha ancora fatto una scelta esplicita nella tua applicazione :
else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark');
}
Questa funzionalità utilizza la Media Query`prefers-color-scheme`per interrogare il sistema. Su macOS, Windows 10+, iOS e Android moderno, questa query restituisce la preferenza di sistema dell’utente.
Vantaggi : - Esperienza personalizzata dalla prima visita - Coerenza con l’ambiente di sistema dell’utente - Nessun spazio di archiviazione necessario per la prima visita
Considerazioni : - Tutti i browser non supportano questa funzionalità (ma il supporto è eccellente dal 2020) - La verifica`window.matchMedia`garantisce la compatibilità L’utente può sempre sovrascrivere questa scelta
Performance : Perché questo script è veloce
Il nostro script di precaricamento è progettato per essere estremamente veloce:
dimensione minima: Circa 300 byte non minificati, 200 byte minificati. È trascurabile rispetto a qualsiasi immagine o libreria JavaScript.
Inline: Nessuna richiesta HTTP aggiuntiva. Lo script è nell’HTML, quindi è immediatamente disponibile.
Operazioni sincrone semplici: Lettura di una chiave nel localStorage (operazione ultra-rapida) e modifica di un attributo DOM (operazione nativa del browser).
Nessuna dipendenzaNessun framework, nessuna libreria, solo JavaScript puro. Nessun tempo di avvio, nessun parsing delle dipendenze.
Esecuzione unicaQuesto script si esegue una sola volta al caricamento. Nessun listener di eventi, nessun ciclo, nessun calcolo complesso.
In pratica, su hardware moderno, questo script si esegue in meno di 1 millisecondo, un tempo impercettibile che non ha alcun impatto sulle prestazioni di caricamento della pagina.
Posizionamento Ottimale nel `<head>
L’ordine degli elementi nel`<head>`è importante. Ecco l’ordine consigliato:
<head>
<!-- 1. Métadonnées critiques -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 2. Notre script de pré-chargement (IMMÉDIATEMENT après les meta) -->
<script>
(function() { /* notre code */ })();
</script>
<!-- 3. Titre de la page -->
<title>Mon Site</title>
<!-- 4. Feuilles de style -->
<link rel="stylesheet" href="styles.css">
<!-- 5. Autres ressources (fonts, favicons, etc.) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="icon" href="favicon.ico">
<!-- 6. Autres scripts avec defer ou async -->
<script src="app.js" defer></script>
</head>
Questo ordine garantisce che :
-
Il charset è definito prima di qualsiasi elaborazione di testo
-
Il nostro script viene eseguito prima del caricamento dei CSS
-
I CSS vengono caricati successivamente e applicano direttamente il tema corretto
-
Le altre risorse non critiche sono caricate per ultime
Passo 3: la potenza dei selettori di attributi CSS
Il Sistema di Tema di Bootstrap 5
Bootstrap 5 ha introdotto un sistema elegante di gestione dei temi basato sulle custom properties CSS (variabili CSS) e sui selettori di attributo. Questo sistema utilizza l’attributo`data-bs-theme`sull’elemento`<html>`per determinare quale insieme di variabili di colore applicare.
La bellezza di questo sistema risiede nella sua semplicità: invece di caricare diversi fogli di stile o di attivare/disattivare le classi su migliaia di elementi, cambiamo semplicemente un attributo su un singolo elemento e il CSS si occupa del resto grazie alla cascata.
Struttura CSS per un sistema di tema
Ecco una struttura CSS completa per implementare un sistema di tema robusto:
/**
* SYSTÈME DE THÈME COMPLET
* Utilise les Custom Properties CSS pour une maintenance facile
*/
/* ============================================
THÈME PAR DÉFAUT (LIGHT)
Défini sur :root pour être le fallback
============================================ */
:root {
/* Couleurs de base */
--color-primary: #0d6efd;
--color-secondary: #6c757d;
--color-success: #198754;
--color-danger: #dc3545;
--color-warning: #ffc107;
--color-info: #0dcaf0;
/* Couleurs de fond */
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #e9ecef;
/* Couleurs de texte */
--text-primary: #212529;
--text-secondary: #6c757d;
--text-tertiary: #adb5bd;
/* Couleurs de bordure */
--border-color: #dee2e6;
--border-color-subtle: #e9ecef;
/* Couleurs d'ombre */
--shadow-sm: rgba(0, 0, 0, 0.075);
--shadow-md: rgba(0, 0, 0, 0.15);
--shadow-lg: rgba(0, 0, 0, 0.25
Articoli correlati
14 May 2026