Librerie CSS-in-JS

Alla nascita dei nuovi framework Javascript ha fatto seguito un nuovo modo di sviluppare e integrare i fogli di stile

Per parlare di CSS-in-JS dobbiamo prima accennare ai Web Components, o meglio all’interpretazione che è stata fatta lato JS da alcune tecnologie come React, Vue o Angular.
Lo scopo dei Web Components è quello di avere, per l’appunto, dei componenti di interfaccia che siano autonomi e riutilizzabili non solo all’interno della singola interfaccia, ma condivisi tra progetti diversi; questo significa che ogni componente deve funzionare in maniera indipendente rispetto al contesto in cui viene inserito e deve reagire unicamente alle proprietà che riceve in input.
Questa logica va però in conflitto con quella delle proprietà CSS, che hanno come caratteristica principale di essere applicate a livello globale e non a livello di componente.
Ci sono alcune conseguenze di questo conflitto: se manteniamo l’idea di un CSS globale ogni volta che installiamo un componente dobbiamo gestire manualmente i suoi stili all’interno del file generale in maniera coerente, oltre a dover modificare il componente stesso per inserire le nostre classi.
Lo scopo fondamentale di CSS-in-JS è quello di poter includere lo stile del componente all’interno dello stesso, senza che vada in conflitto con gli altri.

Sia Angular che Vue sono dei framework che al loro interno integrano nativamente le tecnologie necessarie ad associare codice CSS ad ogni specifico componente; al contrario React, in quanto libreria, necessità di essere integrato per avere questo tipo di funzionalità.
Prendo spunto dall’ultimo report sul mondo CSS per analizzare alcune delle soluzioni più interessanti, non tanto per fare una valutazione quanto per confrontarne gli approcci a livello di metodologia, che in un mondo ai primi passi possono essere molto diverse.

Styled Components

Come dice il nome stesso della libreria, lo scopo è quello di generare dei componenti che abbiano lo stile integrato, sostituendo i tag standard HTML. Prendiamo ad esempio una situazione come questa:

index.html

<h1 class="title">This is Standard HTML</h1>

style.css

.title {
   font-size: 4rem;
   color: #FF3300;
}

Con Styled Components andremo a sostituire il tag H1 con un componente che include lo stile stesso

index.jsx

const StyledTitle = styled.h1`
   font-size: 4rem;
   color: #FF3300;
`

render(
<div>
	<StyledTitle>This is Styled Components</StyledTitle>
</div>
)

Il risultato finale sarà lo stesso dell’esempio iniziale, con la differenza che il nome della classe applicata al tag H1 sarà univoca e quindi legata unicamente a questo tag.

I componenti creati in questo modo possono essere importati e personalizzati in altri componenti, se ad esempio il nostro tag H1 deve comparire in modo diverso nella pagina di dettaglio di un post possiamo fare questo:

post.jsx

const PostTitle = styled(StyledTitle)`
   color: #000;
`

render(
<div>
      <PostTitle>This is a Post Title<PostTitle>
</div>
)

Oppure possiamo fare dei componenti configurabili

index.jsx

const StyledTitle = styled.h1`
   font-size: 4rem;
   color: ${props => props.color ? props.color : '#FF3300'};
`

post.jsx

render(
<div>
      <StyledTitle color="#000">This is a Post Title<StyledTitle>
</div>
)

L’insieme di queste due opzioni consente di creare delle component library di base da includere nel nostro progetto e personalizzare in base alle nostre esigenze

CSS Modules

Si tratta della metodologia che più di altre è riuscita ad inserirsi nel mondo degli sviluppatori CSS, poichè mantiene la separazione del codice tra CSS e JS pur implementando lo scope locale all’interno del componente. In termini pratici possiamo continuare a scrivere CSS come siamo abituati:

style.css

.title {
   font-size: 4rem;
   color: #FF3300;
}

cambia il modo in cui lo includiamo

index.jsx

import styles from "./style.css";

render(
<div>
	<h1 className={styles.title}>This is CSS Modules</h1>
</div>
)

Al tag H1 verrà applicata una classe univoca con le stesse caratteristiche di quella originale.
A livello di architettura possiamo gestire il codice css in moduli e tramite le composition estendere classi esistenti.

style.css

.title {
   font-size: 4rem;
   color: #FF3300;
}

post.css

.title {
  composes: title from "./style.css";
  color: #000;
}

post.jsx

import styles from "./post.css";

render(
<div>
    <h1 className={styles.title}>This is a Post Title</h1>
</div>
)

Emotion

L’implementazione di base di Emotion è quella che sviluppa più drasticamente il concetto di CSS-in-JS, inserendo il codice css direttamente nel codice JS tramite una apposita proprietà

index.jsx

render(
<div>
	<h1 css={css`
		font-size: 4rem;
        color: #FF3300;
        ` }
    >
        This is Emotion
	</h1>
</div>
)

Dato che il codice CSS viene passato tramite template literals è ovviamente possibile passare delle props al componente per gestirne lo stile in modo parametrico. Questo tipo di approccio è molto simile a quello definito da Styled Components, tanto che esiste una libreria variante di Emotion (@emotion/styled) che usa esattamente la stessa sintassi.

Styled JSX

Anche per questa libreria l’integrazione del CSS avviene direttamente in fase di render, la differenza è che viene applicato tramite il tag style a cui va aggiunto il parametro jsx.

index.jsx

render(
<div>
	<h1>This is Styled JSX</h1>
	<style jsx>{`
		h1 {
            font-size: 4rem;
            color: #FF3300;
        }
	`}</style>
</div>
)

Anche in questo caso l’utilizzo di template literals consente di scrivere del css configurabile tramite le props passate al componente.

Conclusioni

Per chiudere questo post faccio delle precisazioni che sono doverose:

  • Ho scelto di presentare le librerie che negli ultimi due anni hanno avuto un buon livello di soddisfazione tra gli utente, questo non significa che siano le migliori. Ogni mese nascono nuove implementazioni che meritano comunque di essera analizzate come, Fela o Stitches
  • Sono rimasto volutamente ad una visione superficiale delle funzionalità fornite da queste librerie, se dovete sceglierne una consiglio di approfondire la documentazione ufficiale di ognuna per avere uno spettro completo delle capacità
  • Negli esempi ho sempre fatto riferimento a codice React, ma molte di queste sono disponibili in modalità indipendente dalla libreria di rendering
  • La volontà era di presentare i vari approcci scelti dalle librerie, ma vanno valutate anche la facilità di implementazione, l’integrazione con SSR e SSG e le prestazioni sia in fase di build che in fase di rendering frontend

Qui trovate le documentazioni ufficiali