Questa prima lezione è tosta, molto tosta. Lo dico perché per qualcuno che inizia con CSS potrebbe quasi scoraggiare dall’iniziare, ma giuro che sono concetti molto utili da conoscere per poter scrivere meglio il CSS di tutti i giorni.
Che cos’è CSS?
Cascading Style Sheets (CSS) è un linguaggio di stile usando per descrivere la presentazione di un documento HTML o XML (inclusi dialetti di XML come SVG).
CSS descrive come gli elementi devono essere renderizzati a schermo ed è proprio su questo processo che ci concentreremo nell’arco di questo approfondimento.
CSS fa parte dei linguaggi core del web ed è standardizzato tra i vari browser in accordo con la specifica W3C.
Per quanto CSS sia noto a molti come CSS3, il che indica che ci siano altre versioni (per la precisione la 1 e la 2.1) ad oggi il versionamento non esiste più e ciò significa che non ci sarà mai CSS4, ma solo CSS.
Questa scelta è dovuta alla dimensione della specifica e alla nascita di sempre più moduli di CSS, che tra loro differiscono parecchio, per cui è diventato più utile sviluppare i moduli separatamente. Al posto di avere una versione generale, la W3C, periodicamente fa un’istantanea della specifica e il progresso individuale dei moduli. A quest’ultimi viene applicato poi un livello (es. CSS Color Module Level 5).
Come fa il browser a comprendere CSS?
Questa domanda ce la siamo fatta anche con HTML ed è proprio da lì che dobbiamo partire, da quei processi visti nel corso di HTML. In particolar modo il pre-parsing della ben più complessa fase di parsing che il rendering engine esegue sul documento HTML.
Durante suddetta sottofase tutto il CSS (sia quello inserito via attributo style
, incluso con il tag <style>
o scritto in un documento separato e linkato con il tag <link />
) viene raccolto e mandato al parser di CSS.
Come per HTML anche per CSS c’è una fase di tokenization la quale trasforma ciò che è stato scritto nel documento in token, i quali si basano sulla specifica W3C menzionata in precedenza.
Al termine del processo otterremo una struttura dati con tutti i selettori, proprietà e i rispettivi valori di quest’ultime.
Facciamo un esempio
1.bottone {
2 background: green;
3 border: 3px solid red;
4 font-size: 1em;
5}
Ignorando per il momento cosa fanno esattamente queste righe di codice, concentriamoci sull’output del parser che sarà più o meno simile a quanto segue:
Selettore | Proprietà | Valore |
.bottone | background-color | rgb(0,255,0) |
.bottone | border-width | 3px |
.bottone | border-style | solid |
.bottone | border-color | rgb(255,0,0) |
.bottone | font-size | 1em |
Unica cosa da notare, ma che avrà più senso con qualche nozione generale in più sulle spalle è che il browser non considera le shorthand (es. border
e background
), ma solo le proprietà estese (o longhand).
Dopo la parsificazione il rendering engine continua la sua attività di costruzione del DOM.
Computazione
Ovviamente non è finita qui, siamo ben lontani dalla fine. A questo punto inizia un nuovo processo denominato computazione, dove tutti i valori vengono convertiti nel loro valore computazionale standard.
Al termine di questo processo tutti i valori avranno uno dei tre possibili output:
auto
- una percentuale
- valore in pixel
Chiaro che nel caso di colori o altri tipi di valori testuali questi output non si applicano.
Per fare qualche esempio:
Input | Valore computato |
font-size: 1rem | font-size: 16px |
width: 50% | width: 50% |
line-width: calc(10px + 2em) | line-width: 42px |
border-color: currentColor | border-color: rgb(0, 0, 0) |
height: 50vh | height: 540px |
display: grid | display: grid |
Le varie unità di misura, funzioni e diciture verranno affrontate più avanti nel corso. Per ora basta solo notare che valori come 1rem
o 50vh
cambiano in un valore in pixel.
Applicazione delle regole di specificità e cascata
Questa nuova fase è estremamente importante, questo perché il browser deve determinare quali stili applicare esattamente ad un determinato elemento.
La scelta si basa su una formula chiamata specificità, la quale conta il numero di tag, classi, id e attributi presenti nel selettore utilizzato e il numero di !important
che vengono usati.
Se gli stili sono applicati attraverso l’attributo style
, questo ha automaticamente la specificità più alta rispetto al CSS nel tag <style>
o in un documento esterno. Se usiamo !important
su un valore specifico questo vincerà su tutto il resto ignorando selettori o dove è stato scritto.
Il punteggio quindi può essere facilmente calcolato prendendo come riferimento questa semplice tabellina e aggiungendo un uno ogni volta che compare nel selettore un tipo specifico.
Qui nelle tabella che segue qualche semplice esempio:
Selettore | Specificità |
p | 0 0 0 0 1 |
p.intro | 0 0 0 1 1 |
#header nav ul li.active | 0 0 1 1 3 |
<p style=”color: #bada55”> | 0 1 0 0 0 |
color: #bada55 !important; | 1 0 0 0 0 |
Durante la lezione sui selettori ne vedremo tanti altri e analizzeremo la specificità di ognuno.
Cosa succede in caso di pareggio?
Nel caso due selettori di pari specificità applichino degli stili allo stesso elemento quello che prevale è quello che viene dopo. Questa è la seconda regola fondamentale di CSS.
Prendendo in considerazione il primo esempio:
1.bottone {
2 background: green;
3 border: 3px solid red;
4 font-size: 1em;
5}
6
7div .bottone {
8 background: yellow;
9}
La nostra tabella aggiornata e arricchita sarà la seguente:
Selettore | Proprietà | Valore | Specificità | Ordine |
.bottone | background-color | rgb(0,255,0) | 0 0 0 1 0 | 0 |
.bottone | border-width | 3px | 0 0 0 1 0 | 1 |
.bottone | border-style | solid | 0 0 0 1 0 | 2 |
.bottone | border-color | rgb(255,0,0) | 0 0 0 1 0 | 3 |
.bottone | font-size | 16px | 0 0 0 1 0 | 4 |
div .bottone | background-color | rgb(255, 255, 0) | 0 0 0 1 1 | 5 |
L’origine dello stile
In CSS gli stili hanno tre origini:
- utente: qualsiasi stile applicato globalmente tramite user agent dall’utente (es. dimensione del testo più grande)
- autore: gli stili scritti dal frontend developer
- user agent: gli stili di base del browser
L’ordine d’importanza è quello del listato: prima l’utente, poi l’autore e infine lo user agent.
Ipotizzando che l’utente abbia modificato la dimensione del testo a 32px con le nuove informazioni acquisite possiamo arricchire ulteriormente la nostra tabella:
Origine | Selettore | Proprietà | Valore | Specificità | Ordine |
Autore | .bottone | background-color | rgb(0,255,0) | 0 0 0 1 0 | 0 |
Autore | .bottone | border-width | 3px | 0 0 0 1 0 | 1 |
Autore | .bottone | border-style | solid | 0 0 0 1 0 | 2 |
Autore | .bottone | border-color | rgb(255,0,0) | 0 0 0 1 0 | 3 |
Autore | .bottone | font-size | 16px | 0 0 0 1 0 | 4 |
Autore | div .bottone | background-color | rgb(255, 255, 0) | 0 0 0 1 1 | 5 |
Utente | * | font-size | 32px | 0 0 0 0 1 | 0 |
Infine il browser ordinerà la struttura dati prima per origine, poi per specificità e infine per ordine.
Origine ⬆️ | Selettore | Proprietà | Valore | Specificità ⬆️ | Ordine ⬇️ |
Utente | * | font-size | 32px | 0 0 0 0 1 | 0 |
Autore | div .bottone | background-color | rgb(255, 255, 0) | 0 0 0 1 1 | 5 |
Autore | .bottone | background-color | rgb(0,255,0) | 0 0 0 1 0 | 0 |
Autore | .bottone | border-width | 3px | 0 0 0 1 0 | 1 |
Autore | .bottone | border-style | solid | 0 0 0 1 0 | 2 |
Autore | .bottone | border-color | rgb(255,0,0) | 0 0 0 1 0 | 3 |
Autore | .bottone | font-size | 16px | 0 0 0 1 0 | 4 |
A questo punto abbiamo le proprietà vincenti per il nostro elemento con classe .bottone
(più in alto meglio è). Gli stili applicati al browser saranno quindi:
Proprietà | Valore |
font-size | 32px |
background-color | rgb(255, 255, 0) |
border-width | 3px |
border-color | rgb(255, 0, 0) |
border-style | solid |
Se quanto hai letto non ti basta puoi sempre leggere la specifica ufficiale della W3C.
Giunti a questo punto è il momento di aggiornare il CSSOM (CSS Object Model), il quale risiede in document.stylesheets
alla quale si accede solitamente con il metodo getComputedStyle()
usando JavaScript.
Layout e rappresentazione visuale
Il browser a questo punto creerà il box tree. Per crearlo è necessario attraversare tutto il DOM e creare zero o più box CSS, dove ognuno ha margini, bordi, padding e contenuto.
Questo processo si chiama layout.
Questo processo in particolare è assai complesso e capisco che affrontarlo ora sarebbe veramente too much. Per cui il processo di layout verrà discusso di volta in volta che verranno introdotte le proprietà che vengono risolte in questa fase.
Painting
Facciamo un breve recap di quanto visto finora:
- Il browser recupera tutto il CSS
- Lo parsifica e ci applica cascata e specificità
- Aggiorna il CSSOM
- Creare il box tree e risolve le proprietà di layout come
float
, dimensioniauto
e frammentazioni
Cosa manca? Beh non abbiamo ancora applicato colori, bordi, ombre e altri elementi di design. Questo processo è chiamato painting.
L’ordine che si segue in questa fase è: background, bordi e contenuto, il che visivamente si traduce così:
Una volta terminato il tutto verrà convertito in bitmap. Eh sì, hai letto bene. Un’immagine.
Lo stacking context
Anche questa fase la vedremo meglio quando parlerò di position
, ma è solo a questo punto che vengono gestiti gli z-index
una proprietà che ci permette di mostrare un elemento sopra un altro. Un po’ come i livelli di Photoshop, solo che in questo punto specifico ancora non si parla di livelli (layer). Qui si chiama stacking context e con z-index
lo modifichiamo.
Composition
Ora iniziamo a parlare di layer perché quanto prodotto finora viene passato ad un software rasterizer che creerà vari livelli e li renderizzerà a video come bitmap.
Di layer e software rasterizer ne ho parlato ampiamente nel corso one shot sull’ottimizzazione delle animazioni in CSS.
Il motivo della creazione dei livelli e quindi lo spezzettamento della pagina web in tante piccole “piastrelle” è per questioni legate all’aggiornamento della pagina in caso di animazioni o cambiamenti in generale del layout.
Il senso di interattività
La pagina è pronta, l’utente può navigarla e interagirci e proprio su quest’ultimo aspetto voglio concentrarmi.
Cosa accade quando un utente passa il mouse su un bottone e questo cambia colore? Il processo è abbastanza semplice e coinvolge un algoritmo chiamato hit testing.
- L’utente muove il mouse sul bottone
- Il browser esegue un evento che comunica che il mouse si sta spostando ed esegue l’algoritmo di hit testing che in sostanza chiede “Quale box sta toccando il mouse?”
- L’algoritmo restituisce il box (il bottone)
- Il browser chiede “C’è qualcosa da fare quando il mouse passa sopra il bottone?”
- Viene eseguita al volo la parte di stile e cascata vista in precedenza solo per questo box e i suoi figli per determinare che c’è qualcosa e vengono passati solo gli stili da modificare
- Gli stili vengono appesi all’elemento DOM (il bottone)
- Viene bypassata la parte di layout e si passa immediatamente alla fase di painting creando un nuovo bitmap
- Il nuovo bitmap viene passato al compositor e quindi fatto vedere all’utente.
Per l’utente si tratta di interazione, ma per il browser si tratta semplicemente di scambiare un’immagine con un’altra.
Un viaggio bello lungo
Come già scritto il processo non è ancora completo, mancano delle nozioni interessanti, ma che possiamo affrontare di volta in volta che ci si presenta l’occasione. Per ora fai sedimentare questi concetti che sono già più che sufficienti.
Caricamento...
Diventiamo amici di penna? ✒️
Iscriviti alla newsletter per ricevere una mail ogni paio di settimane con le ultime novità, gli ultimi approfondimenti e gli ultimi corsi gratuiti puubblicati. Ogni tanto potrei scrivere qualcosa di commerciale, ma solo se mi autorizzi, altrimenti non ti disturberò oltre.
Se non ti piace la newsletter ti ricordo la community su Discord, dove puoi chiedere aiuto, fare domande e condividere le tue esperienze (ma soprattutto scambiare due meme con me). Ti aspetto!