📌 Cambio tema automatico con JSON (light/dark)

Dynamic theme switching senza duplicare CSS: i temi diventano dati (JSON), il CSS resta stabile (token), JavaScript applica i valori e gestisce system/user. Include demo e debug essenziale.

Due monitor mostrano codice in tema scuro e una finestra di configurazione chiara per cambiare l’aspetto dell’interfaccia.

Autore: Redazione · Creato: 11/02/2026 09:10

🧩 Dynamic Theme Switching with JSON in Web Development: guida operativa completa (con 3 file)

Il cambio tema dinamico è un problema di ingegneria del front-end: separare le regole (CSS stabile) dai valori (tema variabile), applicare questi valori in modo deterministico e garantire che la pagina resti leggibile anche se JavaScript o storage falliscono. La soluzione più pulita prevede quattro elementi (HTML, CSS, JS, JSON). In questa guida, però, applichiamo un vincolo pratico: tre file soltanto, come spesso richiesto in contesti reali dove si vuole un esempio copiabile e immediatamente funzionante. Per mantenere il requisito “JSON”, il file JSON dei temi viene incorporato come oggetto JSON dentro theme.js: concettualmente è lo stesso dato, ma non richiede un quarto file o un endpoint. Il sistema supporta: preferenza di sistema (light/dark), scelta esplicita dell’utente, persistenza della scelta e degrado corretto quando una componente non è disponibile.

Nota terminologica: in questo articolo “token” indica design token (variabili CSS come --bg, --text), non token di sicurezza (es. CSRF).

🧠 Fatti, modelli e limiti: cosa è certo e cosa no

Fatti accertati (A): le CSS Custom Properties permettono di definire token riusabili e aggiornabili a runtime; la preferenza di sistema può essere rilevata; JavaScript può impostare token su :root e quindi modificare l’aspetto globale senza duplicare regole.

Modello operativo (B): la scelta utente deve prevalere sulla preferenza di sistema; in assenza di scelta utente si segue l’OS; se qualcosa fallisce si deve tornare a un fallback CSS coerente.

Limiti e incertezze (C): la persistenza può essere limitata (privacy, modalità privata); la “perfezione” anti-flash dipende dal timing di caricamento e dalla cache. In questo esempio si riduce il problema con fallback CSS e applicazione immediata al load.

🧱 Architettura in 3 file: catena causale verificabile

La catena deve essere leggibile e controllabile:

  • theme.css definisce token e usa token nelle regole (niente valori hardcoded sparsi).
  • theme.js contiene il JSON dei temi (embedded) e applica i token su :root.
  • index.php include CSS e JS e fornisce (opzionale) un controllo di switch.

Pietra miliare: in un sistema ben progettato, il CSS non conosce i temi. Conosce solo i token. I temi sono dati. Il JavaScript applica dati ai token. Se per cambiare tema devi riscrivere regole CSS, il sistema è duplicato e fragile.

📄 index.php (file 1/3)

Questo file serve solo a caricare CSS e JS e a mostrare un contenuto test. Il pulsante è volutamente minimale: in un progetto reale potresti integrarlo nel tuo layout o sostituirlo con una voce di menu.

<?php declare(strict_types=1); ?>
<!doctype html>
<html lang="it">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dynamic Theme Switching with JSON</title>
  <link rel="stylesheet" href="theme.css">
  <script src="theme.js" defer></script>
</head>
<body>

  <h1>Dynamic Theme Switching (JSON + CSS Tokens)</h1>

  <p>
    Se la soluzione funziona, i colori di sfondo/testo e i pulsanti cambiano tema.
    La scelta viene memorizzata e riapplicata al refresh.
  </p>

  <ul>
    <li><button type="button" data-theme-set="light">Light</button></li>
    <li><button type="button" data-theme-set="dark">Dark</button></li>
    <li><button type="button" data-theme-set="system">System</button></li>
  </ul>

  <p>
    Testo di prova per contrasto e leggibilità. Controlla anche input e bordi.
  </p>

  <input type="text" placeholder="Type something...">

</body>
</html>

🎨 theme.css (file 2/3)

Il CSS è scritto per dipendere esclusivamente da token. Inoltre include un fallback coerente con la preferenza di sistema, così la pagina resta usabile anche se JS non gira o se storage è bloccato.

:root{
  color-scheme: light dark;

  --bg: #ffffff;
  --text: #111111;
  --muted: #444444;
  --border: #d0d0d0;
  --surface: #f5f5f5;
  --accent: #1a73e8;

  --btn-bg: #111111;
  --btn-text: #ffffff;
  --input-bg: #ffffff;
  --input-text: #111111;
}

/* fallback automatico su preferenza OS */
@media (prefers-color-scheme: dark){
  :root{
    --bg: #121212;
    --text: #f0f0f0;
    --muted: #c8c8c8;
    --border: #2a2a2a;
    --surface: #1b1b1b;
    --accent: #8ab4f8;

    --btn-bg: #f0f0f0;
    --btn-text: #121212;
    --input-bg: #1b1b1b;
    --input-text: #f0f0f0;
  }
}

html, body{
  margin: 0;
  padding: 24px;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  line-height: 1.6;
}

h1{
  margin: 0 0 14px 0;
}

p{
  margin: 0 0 14px 0;
  color: var(--text);
}

ul{
  margin: 0 0 16px 0;
  padding-left: 18px;
}

button{
  border: 1px solid var(--border);
  background: var(--btn-bg);
  color: var(--btn-text);
  padding: 10px 12px;
  cursor: pointer;
}

input{
  border: 1px solid var(--border);
  background: var(--input-bg);
  color: var(--input-text);
  padding: 10px 12px;
  width: 320px;
}

🧬 theme.js (file 3/3) con JSON incorporato

Qui sta la parte “JSON”: i temi sono descritti come oggetto JSON (equivalente a un file themes.json). Il codice fa tre cose: recupera la scelta salvata, risolve il tema effettivo (utente/system), applica token su :root. Inoltre limita i token applicabili per evitare che il tema diventi un canale arbitrario.

(() => {
  "use strict";

  const STORAGE_KEY = "ap_theme_choice";

  /* JSON dei temi (equivalente a themes.json) */
  const THEMES = {
    light: {
      "--bg": "#ffffff",
      "--text": "#111111",
      "--muted": "#444444",
      "--border": "#d0d0d0",
      "--surface": "#f5f5f5",
      "--accent": "#1a73e8",
      "--btn-bg": "#111111",
      "--btn-text": "#ffffff",
      "--input-bg": "#ffffff",
      "--input-text": "#111111"
    },
    dark: {
      "--bg": "#121212",
      "--text": "#f0f0f0",
      "--muted": "#c8c8c8",
      "--border": "#2a2a2a",
      "--surface": "#1b1b1b",
      "--accent": "#8ab4f8",
      "--btn-bg": "#f0f0f0",
      "--btn-text": "#121212",
      "--input-bg": "#1b1b1b",
      "--input-text": "#f0f0f0"
    }
  };

  const ALLOWED_TOKENS = new Set(Object.keys(THEMES.light));

  function systemTheme() {
    return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  }

  function safeGet() {
    try { return localStorage.getItem(STORAGE_KEY); } catch { return null; }
  }

  function safeSet(v) {
    try { localStorage.setItem(STORAGE_KEY, v); } catch {}
  }

  function applyTheme(choice) {
    const themeName = (!choice || choice === "system") ? systemTheme() : choice;
    const tokens = THEMES[themeName];
    if (!tokens) return;

    const root = document.documentElement;
    for (const [k, v] of Object.entries(tokens)) {
      if (!ALLOWED_TOKENS.has(k)) continue;
      if (typeof v !== "string") continue;
      root.style.setProperty(k, v);
    }
  }

  function bindUI() {
    document.addEventListener("click", (e) => {
      const t = e.target;
      if (!(t instanceof HTMLElement)) return;
      const choice = t.getAttribute("data-theme-set");
      if (!choice) return;

      safeSet(choice);
      applyTheme(choice);
    });
  }

  /* boot deterministico */
  applyTheme(safeGet() || "system");
  bindUI();
})();

🧪 Debug essenziale: se “non cambia niente”, dove guardare subito

  • 1) CSS caricato? Se theme.css non è caricato, non vedi nessun effetto: controlla Network o sorgente pagina.
  • 2) JS caricato? Se theme.js non gira, resta solo il fallback. Apri Console: errori di path o sintassi si vedono subito.
  • 3) Token coerenti? Se nel CSS usi --bg ma nel JS scrivi --bg-color, non cambia nulla.
  • 4) Cache? Se aggiorni theme.js ma il browser usa la versione vecchia, sembra “rotto”. Forza refresh o disabilita cache in DevTools.

🔍 Tesi falsificabile e criterio di falsificazione

Tesi: se tutte le regole CSS dipendono da token e i temi sono definiti come JSON di token→valore applicati a :root, allora aggiungere un tema o correggere un colore richiede modificare solo il JSON (non il CSS) e il sito resta leggibile anche senza JavaScript grazie al fallback su preferenza di sistema.

Criterio di falsificazione: se per aggiungere/correggere un tema sei costretto a modificare più punti del CSS (valori hardcoded o regole duplicate), oppure se senza JS la pagina diventa illeggibile, allora il modello è incompleto o implementato male: non hai tokenizzato davvero o hai eliminato il fallback.

🌐 Implicazioni e connessioni interdisciplinari

Ingegneria del software: separare dati (temi) da logica (regole CSS) riduce duplicazione e drift. È un principio verificabile: meno punti di modifica per un cambio, meno divergenze.

HCI e accessibilità: tema significa leggibilità e contrasto. La preferenza OS è un segnale, ma non garantisce che il tuo contrasto sia adeguato: i token devono includere stati (hover/focus) e superfici, non solo sfondo/testo.

Operatività editoriale: un sito di contenuti cresce. Token e temi come dati permettono evoluzione del design senza “rompere” l’archivio: è manutenzione sistemica, non estetica.

❓ Limiti, incertezze, domande aperte

Limite: l’assenza totale di flash non si dichiara senza misure sul progetto reale; qui si riduce il problema con fallback CSS e boot immediato.

Incertezza: storage e caching possono comportarsi diversamente per browser e impostazioni privacy; il sistema deve degradare al fallback.

Domanda aperta: quanti token servono davvero? La risposta dipende dal numero di componenti e dalla complessità del sito: è un equilibrio empirico tra granularità e manutenibilità.

🧾 Sintesi finale (non prescrittiva)

Il dynamic theme switching con JSON non è una “feature da demo”: è una disciplina architetturale. Funziona quando il CSS usa token ovunque, il tema è un set di valori coerenti (JSON), e il JavaScript applica questi valori in modo deterministico con fallback sensato. La qualità della soluzione non sta nel numero di temi, ma nel fatto che il sistema resti governabile: un cambio di tema deve essere un cambio di dati, non una riscrittura di regole.


🧪 Demo interattivo (sandbox di test)

Questa demo è un sandbox controllato: testa token e logica di switch senza dipendere dal CSS globale del sito.

Messaggio sponsorizzato
Pubblicità

🔗 Condividi l'articolo:

Autore: Redazione · Creato: 11/02/2026 09:10 · Ultima modifica: 03/09/2026 12:20