Switch per Dark Mode con Javascript

4 minuti.

Inserito il

Dark Mode #

Tailwind CSS è un ottimo framework utility-first
che fornisce molti valori preimpostati (come ad es: colori, dimensioni, ecc...) e
velocizzano il design di una pagina WEB evitando di saltare da file html e css.

Il problema è che implementare in Tailwind CSS
una versione scura (dark Mode) o colorata non è semplice.
Nel classico modo, per aggiungere una variante di colore, si potrebbe creare e aggiungere
al codice html una classe 'dark-class" e personalizzare ogni elemento nel file css/scss
in un modo simile a questo:

h1 {
color: black;
}
.scheme-dark {
h1 {
color: white;
}
}

Tuttavia in Tailwind si definiscono i colori nella classe nel file
html, quindi avremmo una classe così composta:

<h1 class="text-blue-900 dark:text-white">Ciao Mondo!</h1>

La documentazione ufficiale raccomanda di aggiungere al file tailwind.config.js la seguente configurazione:

module.exports = {
theme: {
extend: {
screens: {
dark: { raw: "(prefers-color-scheme: dark)" },
// => @media (prefers-color-scheme: dark) { ... }
},
},
},
};

Questa modifica funziona come previsto perché viene regolato il colore della pagina attraverso prefers-color-scheme in base all'impostazione del browser ma, purtroppo, utilizzando questa regola, non sarà possibile aggiungere, ad esempio, un pulsante per fare uno switch del colore in manuale. L'utente dovrà modificare le impostazioni del browser per cambiare il colore della pagina (chiaro/scuro).

Modifica per lo switch #

Per dare all'utente la possibilità di passare alla modalità colore chiaro/scuro o qualsiasi altra colorazione, possiamo modificare le configurazioni nel file di tailwind.

Per prima cosa creiamo la nostra variante personalizzata aggiungendo un nuovo plugin nelle configurazioni tailwind:

...
plugins: [
plugin(function ({ addVariant, prefix }) {
addVariant('dark', ({ modifySelectors, separator}) => {
modifySelectors(({ selector }) => {
return selectorParser((selectors) => {
selectors.walkClasses((sel) => {
sel.value = `dark${separator}${sel.value}`
sel.parent.insertBefore(sel, selectorParser().astSync('.schema-dark '))
})
}).processSync(selector)
})
})
})
]
...

Il nome della variabile dark e la sua classe parente schema-dark saranno usate da tailwind quando verrà generato il file css.

Andranno aggiunte a variants le proprietà che vorremmo usare:

    ...
variants: {
textColor: ['dark', 'responsive', 'hover', 'focus'],
backgroundColor: ['dark', 'responsive', 'hover', 'focus']
},
...

Tailwind will now generate every text color class and background color class additionally with the .dark:\ prefix with the parent class .scheme-dark. So e.g. for the text color text-white it will create the following css:

Tailwind genererà ogni textColor e backgroundColor aggiungendo il prefisso .dark: nella classe parente .schema-dark. Quindi, per esempio, la proprietà text-black sarà creata con il seguente codice css:

.text-black {
color: #000;
}

.schema-dark.dark: \text-black {
color: #000;
}

Configurazione completa #

Questà è la modifica completa da aggiungere al file tailwind.config.js

const plugin = require("tailwindcss/plugin");
const selectorParser = require("postcss-selector-parser");

module.exports = {
theme: {
...
},
variants: {
textColor: ['dark', 'responsive', 'hover', 'focus'],
backgroundColor: ['dark', 'responsive', 'hover', 'focus']
},
plugins: [
plugin(function ({ addVariant, prefix }) {
addVariant('dark', ({ modifySelectors, separator}) => {
modifySelectors(({ selector }) => {
return selectorParser((selectors) => {
selectors.walkClasses((sel) => {
sel.value = `dark${separator}${sel.value}`
sel.parent.insertBefore(sel, selectorParser().astSync(prefix('.schema-dark ')))
})
}).processSync(selector)
})
})
})
]
}

Dark Mode e Hover del testo #

Può capitare di dover cambiare il colore del testo sul passaggio del puntatore del mouse. Come fare?
Semplice, basta aggiungere un ulteriore plugin:

plugin(function ({ addVariant, e }) {
addVariant("dark-hover", ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {
return `.schema-dark .${e(`dark\:hover${separator}${className}`)}:hover`;
});
});
});

e aggiungere la variante dark-hover:

variants: {
textColor: ['responsive', 'dark', 'dark-hover', 'hover', 'focus'],
},

.. e il risultato che si ottiene è il seguente:

<h1
class="text-gray-900 dark:text-gray-100 dark:hover:text-red-400 hover:text-blue-400"
>

Passaci Sopra
</h1>

PostCSS #

Se si utilizza PostCSS per rimuovere le classi da tailwind inutilizzate bisogna ricordarsi di escludere schema-dark da questa operazione aggiungendo al file postcss.config.js nella sezione safelist la classe da salvaguardare e da includere in ogni caso, come nel seguente codice:

    require("@fullhuman/postcss-purgecss")({
...
safelist: {
standard: [
".schema-dark",
],
deep: [],
greedy: [],
keyframes: [],
variables: [],
},
defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || [],
}),

altrimenti nella creazione del file .css la classe .schema-dark non verrà inserita.

🙏🙏🙏

Dato che sei arrivato fino a questo punto, se condividi questo articolo sul tuo social network preferito ti ringrazio in anticipo 💖! Per feedback, inviami un ping su Twitter.