CSS3 - selettori, cascata, box model e layout
In questa pagina 12
CSS (Cascading Style Sheets, specifiche del W3C) descrive come si presenta un documento HTML: colori, caratteri, dimensioni, posizione. Separa la presentazione dal contenuto (HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →): lo stesso HTML cambia aspetto cambiando foglio di stile. "CSS3" indica l'insieme dei moduli successivi a CSS2.1 (selettori, flexbox, grid, media query...), che oggi evolvono ognuno per conto proprio. Il browser applica gli stili dopo aver costruito il CSSOM (Architettura delle applicazioni web - browser, server web e livelliUn'applicazione web è distribuita su più livelli (tier): presentazione (browser: HTML, CSS, JavaScript), logica applicativa (server web e application server) e dati (DBMS). Il client invia richieste HTTP, il server risponde; HTTP è senza stato, quindi lo stato dell'utente viaggia in cookie e sessioni. Il web server serve file statici, l'application server (container, per esempio Tomcat per le servlet Java) esegue codice che genera risposte dinamiche; spesso il web server fa da reverse proxy davanti all'application server. Il browser trasforma i byte della risposta in una pagina: decodifica, tokenizzazione e costruzione del DOM, CSS che diventa CSSOM, render tree, layout (reflow), paint e composizione; un script senza defer o async blocca il parsing, il CSS blocca il rendering. Origine = schema + host + porta; la same-origin policy limita ciò che uno script può leggere da altre origini. Web 1.0: pagine generate dal server, ogni azione ricarica la pagina; Web 2.0: AJAX, contenuti degli utenti, servizi REST; Web 3.0: dati con significato esplicito (RDF, linked data).Architettura delle applicazioni web - browser, server web e livelli →), e JavaScript li può modificare (JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →).
Come si collega e com'è fatta una regola
<link rel="stylesheet" href="stile.css"> <!-- foglio esterno: il metodo normale -->
<style> td { color: gray; } </style> <!-- nel documento -->
<td style="color: gray">...</td> <!-- inline: solo su quell'elemento -->Una regola (rule) ha un selettore (a quali elementi si applica) e un blocco di dichiarazioni proprietà: valore;:
th, td { /* selettore: th oppure td */
padding: 0.4rem 0.6rem; /* dichiarazione */
border-bottom: 1px solid #c7d0da;
}I commenti sono /* ... */. Valori frequenti: colori (red, #1b5e9b, rgb(27 94 155), hsl(208 70% 35%)), lunghezze (px; em relativa alla dimensione del carattere dell'elemento (per font-size: del padre); rem relativa a quella dell'elemento radice; %; vw/vh percentuale della larghezza e altezza della finestra; fr frazione di spazio nella griglia), parole chiave (bold, none, auto).
Le proprietà personalizzate (variabili) si dichiarano con --nome e si usano con var(): un colore cambiato in un punto cambia in tutto il foglio.
:root { --colore-principale: #1b5e9b; } /* :root = elemento html */
header { background: var(--colore-principale); }Selettori
| selettore | seleziona | esempio |
|---|---|---|
| tipo | tutti gli elementi di quel tag | td |
| classe | elementi con class="..." |
.libera |
| id | l'elemento con quell'id (unico) |
#lab |
| universale | tutto | * |
| attributo | elementi con quell'attributo | [required], [type="date"], [href^="https"] (comincia per) |
| gruppo | l'unione | th, td |
| discendente | a qualsiasi profondità dentro | nav a |
| figlio | solo figli diretti | ul > li |
| fratello adiacente | il fratello subito dopo | h2 + p |
| fratelli seguenti | tutti i fratelli dopo | h2 ~ p |
| pseudo-classe | elemento in un certo stato o posizione | a:hover, li:first-child, tr:nth-child(even), input:checked, button:not([disabled]) |
| pseudo-elemento | una parte o un elemento generato | p::first-line, a::after, input::placeholder |
I selettori si combinano senza spazi: li.aula.libera è un li con entrambe le classi; li .libera (con spazio) è un elemento .libera dentro un li.
Pseudo-classi utili: :hover (mouse sopra), :focus e :focus-visible (focus da tastiera), :checked, :disabled, :required, :invalid e :user-invalid (campo non valido, la seconda solo dopo l'interazione dell'utente: HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →), :nth-child(n) con formule (odd, even, 3, 2n+1), :first-child, :last-child, :not(selettore), :is(a, b) e :where(a, b) (raggruppano, con una differenza di specificità, vedi sotto). ::before e ::after inseriscono contenuto generato (content: "...").
Specificità e cascata
Più regole possono assegnare valori diversi alla stessa proprietà dello stesso elemento. La cascata (cascade) decide quale vince. Gli ingredienti, in ordine di peso (CSS Cascading and Inheritance):
- Origine e importanza. Gli stili del browser (user agent), dell'utente e dell'autore (il nostro foglio). Le dichiarazioni con
!importantvincono sulle altre di pari origine; lo stile inline (style="...") vince su quelli normali dei fogli. (Un!importantbatte anche lo stile inline normale.) - Specificità del selettore.
- Ordine di comparsa: a parità di tutto, vince l'ultima dichiarazione nel documento.
(Con le cascade layers, @layer, c'è un livello in più, prima della specificità: argomento avanzato, fuori dal programma.)
Calcolo della specificità
La specificità è una terna di numeri (a, b, c):
- a = numero di selettori id (
#lab); - b = numero di selettori di classe (
.libera), di attributo ([type="date"]) e pseudo-classi (:hover,:nth-child); - c = numero di selettori di tipo (
li) e pseudo-elementi (::before).
Il selettore universale * e i combinatori (spazio, >, +, ~) valgono 0. :not(x) e :is(x) valgono come l'argomento più specifico al loro interno; :where(x) vale sempre 0. Lo stile inline sta sopra a tutto (si può pensare come una quarta cifra più a sinistra).
Le terne si confrontano come numeri a posizione, da sinistra: prima a, poi (a parità) b, poi c. Non è un numero in base 10: dieci classi non battono un id, perché (0,10,0) < (1,0,0).
| selettore | (a,b,c) | motivo |
|---|---|---|
li |
(0,0,1) | un tipo |
.aula |
(0,1,0) | una classe |
ul li.aula |
(0,1,2) | due tipi, una classe |
li.aula.libera |
(0,2,1) | due classi, un tipo |
.contenitore .elenco .libera |
(0,3,0) | tre classi (gli spazi non contano) |
#lab |
(1,0,0) | un id |
#app li.occupata |
(1,1,1) | id, classe, tipo |
a:hover |
(0,1,1) | pseudo-classe e tipo |
p::first-line |
(0,0,2) | tipo e pseudo-elemento |
input[type="date"]:not(.x) |
(0,2,1) | attributo, :not vale .x, tipo |
Confronti istruttivi: .contenitore .elenco .libera (0,3,0) batte ul li.aula (0,1,2): a parità di a (0) conta b, 3 contro 1, e il c non si guarda neanche. #lab (1,0,0) batte .aula e li.aula.libera perché ha a = 1.
Esempio con risultati
<div id="app" class="contenitore">
<ul class="elenco">
<li class="aula libera">Aula A1</li>
<li class="aula">Aula B2</li>
<li class="aula occupata" id="lab">Lab Info</li>
</ul>
</div>li { color: black; } /* R1 (0,0,1) */
.aula { color: green; } /* R2 (0,1,0) */
ul li.aula { color: blue; } /* R3 (0,1,2) */
.contenitore .elenco .libera { color: orange; } /* R4 (0,3,0) */
#lab { color: purple; } /* R5 (1,0,0) */
#app li.occupata { color: red; } /* R6 (1,1,1) */
.occupata { color: gray !important; } /* R7 (0,1,0) ma !important */- Aula A1 (classi
aula,libera): le regole che la toccano sono R1, R2, R3 e R4; la più specifica è.contenitore .elenco .libera(0,3,0): arancione. - Aula B2: regole R1, R2, R3; la più specifica è
ul li.aula(0,1,2): blu. - Lab Info: tocca tutte tranne R4; R6,
#app li.occupata(1,1,1), batte R5,#lab(1,0,0); ma la regola R7,.occupatacon!importantbatte tutte le dichiarazioni normali, anche quelle con specificità maggiore: grigio. Senza!importantil colore sarebbe rosso.
(Risultati verificati leggendo gli stili calcolati in un browser.) Per questo !important va evitato: spezza la cascata e può essere battuto solo da un altro !important più specifico.
Parità e ordine. .aula { font-weight: bold } e .libera { font-weight: normal } hanno la stessa specificità (0,1,0): vince la seconda perché scritta dopo. Lo stesso vale fra fogli: l'ultimo <link> batte i precedenti.
Ereditarietà
Alcune proprietà, se non sono specificate per un elemento, si ereditano dal padre; altre no.
- Ereditate:
color,font-family,font-size,font-weight,line-height,text-align,visibility,cursor,list-style. Se si impostacolorsubody, tutto il testo del documento lo assume (a meno di regole più specifiche). - Non ereditate:
margin,padding,border,background,width,height,display,position. Sarebbe assurdo che i figli ereditassero il bordo del padre.
Il valore ereditato ha priorità più bassa di qualsiasi regola che miri direttamente all'elemento, anche con specificità 0 (*). Parole chiave per controllare: inherit (prendi dal padre), initial (valore iniziale della proprietà), unset (inherit se la proprietà si eredita, altrimenti initial), revert. Esempio: i link hanno un colore del browser; a { color: inherit; } li fa del colore del testo intorno.
Dimensioni relative. Con .elenco { font-size: 0.875rem; } (14 px se la radice è 16 px) e li { font-size: 1.25em; }, l'em si riferisce alla dimensione del padre: i li hanno 1,25 × 14 = 17,5 px (verificato). Le em annidate si moltiplicano: per questo per le dimensioni generali conviene rem.
Box model
Ogni elemento è un riquadro a quattro strati, dall'interno all'esterno:
- content (contenuto):
widtheheight; - padding: spazio interno, con lo sfondo dell'elemento;
- border: bordo;
- margin: spazio esterno, trasparente, fra l'elemento e i vicini.
.scheda { width: 200px; padding: 20px; border: 5px solid black; margin: 10px; }Con box-sizing: content-box (il valore predefinito) width è solo il contenuto: la larghezza visibile è 200 + 2 × 20 + 2 × 5 = 250 px (verificato; l'area del contenuto più il padding è 240). Con box-sizing: border-box width include padding e bordo: la scheda è larga 200 px e il contenuto 150. Per questo quasi tutti i fogli di stile cominciano con
*, *::before, *::after { box-sizing: border-box; }Scorciatoie: margin: 10px (quattro lati), margin: 5px 10px (verticale, orizzontale), margin: 1px 2px 3px 4px (sopra, destra, sotto, sinistra: il senso orario). margin: 0 auto centra un blocco con larghezza fissata.
Collasso dei margini. I margini verticali adiacenti di elementi a blocco non si sommano: si usa il maggiore. Due paragrafi alti 40 px con margin-bottom: 20px e margin-top: 30px sono a 30 px di distanza (e non 50): la distanza fra le loro cime è 40 + 30 = 70 (verificato). I margini orizzontali, quelli dei contenitori flex e grid non collassano.
Display e posizionamento
display decide come l'elemento partecipa al layout:
| valore | effetto |
|---|---|
block |
occupa tutta la riga, va a capo; accetta width, height, margini |
inline |
scorre con il testo; width/height ignorati, margini verticali non contano |
inline-block |
scorre con il testo ma accetta dimensioni e margini |
none |
l'elemento non esiste per il layout (non lascia spazio); visibility: hidden invece lo nasconde lasciando lo spazio |
flex, grid |
l'elemento diventa un contenitore flessibile / a griglia per i suoi figli |
position sposta gli elementi rispetto al flusso normale:
| valore | comportamento |
|---|---|
static |
predefinito: nel flusso, ignora top/left/... |
relative |
nel flusso (lo spazio resta), poi spostato di top/left/... dalla posizione normale; diventa il riferimento per i figli assoluti |
absolute |
tolto dal flusso; posizionato rispetto al più vicino antenato posizionato (cioè non static), altrimenti rispetto alla pagina |
fixed |
tolto dal flusso, fisso rispetto alla finestra (non scorre) |
sticky |
come relative, ma "si incolla" quando lo scorrimento raggiunge la soglia (top: 0): intestazioni di tabella che restano visibili |
Esempio verificato: un contenitore position: relative; width: 300px con un figlio position: absolute; top: 10px; right: 10px; width: 50px mette il figlio a 300 - 10 - 50 = 240 px dal bordo sinistro del contenitore. z-index decide la sovrapposizione fra elementi posizionati. I float (testo che avvolge un'immagine) sono il vecchio metodo di impaginazione: oggi si usano flexbox e grid.
Flexbox
Il layout flessibile (flexbox) dispone i figli di un contenitore in una dimensione: una riga (row, predefinito) o una colonna (column).
.barra { display: flex; gap: 16px; justify-content: space-between; align-items: center; }Proprietà del contenitore:
flex-direction:row,column,row-reverse...: l'asse principale;justify-content: distribuzione sull'asse principale (flex-start,center,flex-end,space-between,space-around,space-evenly);align-items: allineamento sull'asse trasversale (stretchpredefinito,center,flex-start,flex-end);flex-wrap: wrap: va a capo quando manca lo spazio;gap: spazio tra i figli.
Proprietà dei figli: flex-grow (quota dello spazio libero da prendere), flex-shrink, flex-basis (dimensione di partenza); flex: 1 è la forma breve per "occupa lo spazio libero in parti uguali".
Verifiche: in un contenitore di 600 px con tre figli da 100 px e space-between, i figli partono a 0, 250 e 500 px (i 300 px liberi sono divisi in due intervalli); due figli con flex: 1 e flex: 2 senza larghezza propria prendono 200 e 400 px. È il modo naturale per la barra di navigazione, i gruppi di pulsanti, il centraggio.
Grid
Il layout a griglia dispone i figli in righe e colonne: lo strumento per l'impaginazione della pagina.
.griglia { display: grid; grid-template-columns: 200px 1fr 2fr; gap: 10px; }
.auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }grid-template-columnselenca le colonne.frè una frazione dello spazio rimanente: in un contenitore di 800 px, con colonne200px 1fr 2fregapdi 10 px, restano 800 - 200 - 20 = 580 px, quindi le colonne sono larghe 200, 193,33 e 386,67 px (verificato).repeat(n, ...)ripete;repeat(auto-fit, minmax(200px, 1fr))crea quante colonne da almeno 200 px ci stanno: in 700 px, tre colonne da 233,33 px (verificato); la finestra si stringe e scendono a due, poi a una, senza media query.gapdistanzia righe e colonne;grid-column: 1 / 3fa occupare più colonne;grid-template-areasassegna nomi alle aree della pagina.
Quale scegliere: flexbox per allineare elementi in una riga o colonna, grid per un'impaginazione a due dimensioni; si combinano (una grid di pagina, con flex dentro i singoli componenti).
Design responsive
Una pagina deve funzionare da 360 px di larghezza (telefono) a 1920 (schermo grande).
<meta name="viewport" content="width=device-width, initial-scale=1">nell'HTML, altrimenti il telefono mostra la pagina in una finestra virtuale di circa 980 px e rimpicciolisce tutto.- Unità relative (
rem,%,fr),max-width: 100%sulle immagini, niente larghezze fisse in px per i contenitori. - Media query: regole condizionate alla finestra.
main { display: grid; gap: 1rem; padding: 1rem; } /* telefono: una colonna */
@media (min-width: 48rem) { /* da 768 px in su */
main { grid-template-columns: 2fr 1fr; align-items: start; }
}L'approccio mobile-first scrive gli stili base per lo schermo piccolo e aggiunge con min-width per quelli più grandi (il contrario, max-width, parte dal desktop). Condizioni utili: (min-width: 48rem), (max-width: 600px), (prefers-color-scheme: dark), (prefers-reduced-motion: reduce). Verifica: con la finestra a 518 px una regola @media (max-width: 600px) { .mq { color: blue } } rende il testo blu, a 966 px rosso.
Il foglio di stile dell'applicazione
Il foglio stile.css della pagina di prenotazione (una colonna su telefono, tabella e form affiancati da 48 rem in su):
:root {
--colore-principale: #1b5e9b;
--sfondo: #f5f7fa;
--bordo: #c7d0da;
}
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.5;
color: #1c2530;
background: var(--sfondo);
}
header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 0.5rem 1rem;
padding: 0.75rem 1rem;
background: var(--colore-principale);
color: white;
}
header h1 { margin: 0; font-size: 1.25rem; }
nav ul { display: flex; gap: 1rem; margin: 0; padding: 0; list-style: none; }
nav a { color: inherit; text-decoration: none; }
nav a:hover, nav a:focus-visible { text-decoration: underline; }
main { display: grid; gap: 1rem; padding: 1rem; }
section { padding: 1rem; background: white; border: 1px solid var(--bordo); border-radius: 0.5rem; }
h2 { margin-top: 0; font-size: 1.1rem; }
table { width: 100%; border-collapse: collapse; }
caption { text-align: left; font-size: 0.875rem; color: #566; }
th, td { padding: 0.4rem 0.6rem; text-align: left; border-bottom: 1px solid var(--bordo); }
thead th { background: #e8eef5; }
tbody tr:nth-child(even) { background: #f7f9fb; }
fieldset { border: 1px solid var(--bordo); border-radius: 0.25rem; }
label { display: inline-block; min-width: 4.5rem; }
input, select, button { font: inherit; padding: 0.3rem 0.5rem; }
input:user-invalid, select:user-invalid { border-color: #b00020; }
button { color: white; background: var(--colore-principale); border: 0; border-radius: 0.25rem; cursor: pointer; }
button:hover { filter: brightness(1.15); }
footer { padding: 1rem; font-size: 0.875rem; color: #566; }
@media (min-width: 48rem) {
main { grid-template-columns: 2fr 1fr; align-items: start; }
}Che cosa fa:
- le variabili
--colore-principale,--sfondo,--bordostanno in:roote sono usate convar(); box-sizing: border-boxper tutto;bodyfissa carattere, interlinea e colori che i discendenti ereditano;- l'intestazione è un contenitore flex con
space-between(titolo a sinistra, menu a destra) eflex-wrapperché su telefono vada a capo; - il menu è un elenco ridotto a riga con
display: flexe senza puntini (list-style: none); i link ereditano il colore (color: inherit); mainè una grid (una colonna, poi due con la media query); lesectionsono schede con bordo e angoli arrotondati;- la tabella ha
border-collapse: collapse(bordi fusi), righe a strisce contbody tr:nth-child(even); - il campo non valido ha il bordo rosso con
:user-invalid, solo dopo che l'utente ha interagito (con:invalidapparirebbe subito su tutti i campi vuoti); - il foglio non usa
idné!important: tutte le regole hanno specificità bassa e prevedibile (il massimo è (0,1,2), pernav a:hoveretbody tr:nth-child(even)).
Errori tipici
- Credere che la specificità sia un numero in base 10 (dieci classi non battono un id).
- Contare gli spazi (combinatori) o il selettore universale nella specificità.
- Usare
!importantper far funzionare una regola invece di capire perché non vince. - Dimenticare che la larghezza predefinita (
content-box) non include padding e bordo: la scheda esce dal contenitore. - Aspettarsi che i margini verticali si sommino.
position: absolutesenza antenatorelative: l'elemento si posiziona rispetto alla pagina.- Confondere
justify-content(asse principale) ealign-items(asse trasversale). li .libera(discendente) al posto dili.libera(stesso elemento).- Dimenticare il meta viewport: le media query sembrano non funzionare sul telefono.
- Aspettarsi che
marginobordersi ereditino.
Domande d'esame
- Calcolare la specificità di
#app li.occupata,.contenitore .elenco .liberaeul li.aulae dire quale vince su unliche le soddisfa tutte. (1,1,1), (0,3,0), (0,1,2): vince la prima (a = 1), poi la seconda (b = 3 contro 1); a parità di specificità vince l'ultima nel documento;!importante stile inline cambiano l'ordine. - Spiegare il box model e la differenza fra
content-boxeborder-box. content, padding, border, margin; concontent-boxwidthè solo il contenuto (200 + 40 + 10 = 250 px di larghezza totale), conborder-boxinclude padding e bordo (200); i margini verticali collassano. - Quando si usa flexbox e quando grid? Come si rende una pagina responsive? Flexbox su una dimensione (barra di navigazione, allineamenti), grid su due (impaginazione); meta viewport, unità relative, media query
min-widthcon approccio mobile-first,repeat(auto-fit, minmax(...)).
Versione ripasso
Regola. selettore { proprietà: valore; }. Collegamento: <link rel="stylesheet">, <style>, style="". Variabili --x con var(--x). Unità: px, em (padre per font-size), rem (radice), %, vw, fr.
Selettori. Tipo td, classe .a, id #a, attributo [type="date"], *, gruppo a, b; combinatori: discendente (spazio), figlio >, fratello adiacente +, fratelli seguenti ~; pseudo-classi :hover, :focus-visible, :nth-child(even), :not(), :user-invalid; pseudo-elementi ::before, ::after. li.aula (stesso elemento) è diverso da li .aula (discendente).
Cascata, in ordine: importanza (!important; inline batte i fogli) → specificità → ordine di comparsa (l'ultima vince).
Specificità (a,b,c).
- a = id; b = classi + attributi + pseudo-classi; c = tipi + pseudo-elementi.
*e combinatori valgono 0;:where()vale 0;:not()e:is()valgono l'argomento più specifico.- Confronto cifra per cifra da sinistra, non in base 10: (0,10,0) < (1,0,0).
- Esempi:
ul li.aula(0,1,2);li.aula.libera(0,2,1);.contenitore .elenco .libera(0,3,0);#app li.occupata(1,1,1). - Con un
!importantsu.occupatailli#labdiventa grigio; senza, rosso.
Ereditarietà. Si ereditano color, font-*, line-height, text-align, visibility; non margin, padding, border, background, width, display. Controllo: inherit, initial, unset. em annidate si moltiplicano (0,875 rem × 1,25 = 17,5 px).
Box model. content, padding, border, margin. content-box (predefinito): width = contenuto (200 + 2·20 + 2·5 = 250); border-box: width totale (200). Scorciatoia in senso orario sopra-destra-sotto-sinistra. I margini verticali adiacenti collassano nel maggiore (20 e 30 danno 30).
Display. block, inline, inline-block, none (senza spazio), flex, grid. Position. static; relative (spazio conservato); absolute (tolto dal flusso, rispetto all'antenato posizionato); fixed; sticky.
Flexbox (1D): display: flex, flex-direction, justify-content (asse principale), align-items (trasversale), gap, flex-wrap; figli flex: 1, flex-grow. Grid (2D): grid-template-columns: 200px 1fr 2fr, fr = parte dello spazio rimanente, repeat(auto-fit, minmax(200px, 1fr)), gap.
Responsive. <meta name="viewport" content="width=device-width, initial-scale=1">; unità relative; @media (min-width: 48rem); mobile-first.
Errori tipici
- Specificità come numero in base 10.
!importantcome scorciatoia.content-boxche fa uscire la scheda dal contenitore.- Margini sommati invece che collassati.
absolutesenza antenatorelative.justify-contentealign-itemsscambiati.- Dimenticare il meta viewport.
Contesto: HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →, JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →, Esercizio - Calcolo della specificità e della cascata (applicazione web). Tabella di specificità.
| selettore | (a,b,c) |
|---|---|
li |
(0,0,1) |
.aula |
(0,1,0) |
ul li.aula |
(0,1,2) |
li.aula.libera |
(0,2,1) |
.contenitore .elenco .libera |
(0,3,0) |
#lab |
(1,0,0) |
#app li.occupata |
(1,1,1) |
Il confronto è cifra per cifra da sinistra: .contenitore .elenco .libera (0,3,0) batte ul li.aula (0,1,2); #lab batte qualsiasi numero di classi. Stile inline e !important stanno sopra.
Cascata sull'esempio. li.aula.libera ha colore arancione (R7), li.aula blu (R5), li#lab.occupata grigio per via di !important (senza, rosso per #app li.occupata). Regola che non si applica: tbody tr:nth-child(even) (0,1,2) batte .libera (0,1,0): si corregge con tbody tr.libera scritta dopo, non con !important.
Box model, valori verificati.
| caso | risultato |
|---|---|
content-box, width: 200px; padding: 20px; border: 5px |
larghezza totale 250 px |
stesso con border-box |
200 px, contenuto 150 px |
margini 20px e 30px fra due blocchi |
distanza 30 px (collasso) |
contenitore position: relative 300 px, figlio absolute; right: 10px; width: 50px |
figlio a 240 px dal bordo sinistro |
Flexbox e grid.
.barra { display: flex; gap: 16px; justify-content: space-between; align-items: center; }
.griglia { display: grid; grid-template-columns: 200px 1fr 2fr; gap: 10px; }
.auto { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }Verificati: tre figli da 100 px in 600 px con space-between partono a 0, 250, 500; flex: 1 e flex: 2 danno 200 e 400 px; con 800 px e colonne 200px 1fr 2fr e gap di 10 px le larghezze sono 200, 193,33, 386,67; auto-fit in 700 px dà tre colonne da 233,33 px.
Responsive.
main { display: grid; gap: 1rem; padding: 1rem; }
@media (min-width: 48rem) { main { grid-template-columns: 2fr 1fr; align-items: start; } }Domande d'esame, tracce.
- Specificità di
#app li.occupata,.contenitore .elenco .libera,ul li.aula: vince la prima, poi la seconda; a parità conta l'ordine. - Box model,
content-boxcontroborder-box, collasso dei margini. - Flexbox su una dimensione, grid su due; meta viewport, unità relative, media query.