Salta al contenuto
Note per Studenti CSS3 - selettori, cascata, box model e layout

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

html
<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;:

css
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.

css
: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):

  1. Origine e importanza. Gli stili del browser (user agent), dell'utente e dell'autore (il nostro foglio). Le dichiarazioni con !important vincono sulle altre di pari origine; lo stile inline (style="...") vince su quelli normali dei fogli. (Un !important batte anche lo stile inline normale.)
  2. Specificità del selettore.
  3. 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

html
<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>
css
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, .occupata con !important batte tutte le dichiarazioni normali, anche quelle con specificità maggiore: grigio. Senza !important il 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 imposta color su body, 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:

  1. content (contenuto): width e height;
  2. padding: spazio interno, con lo sfondo dell'elemento;
  3. border: bordo;
  4. margin: spazio esterno, trasparente, fra l'elemento e i vicini.
css
.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

css
*, *::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).

css
.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 (stretch predefinito, 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.

css
.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-columns elenca le colonne. fr è una frazione dello spazio rimanente: in un contenitore di 800 px, con colonne 200px 1fr 2fr e gap di 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.
  • gap distanzia righe e colonne; grid-column: 1 / 3 fa occupare più colonne; grid-template-areas assegna 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).

  1. <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.
  2. Unità relative (rem, %, fr), max-width: 100% sulle immagini, niente larghezze fisse in px per i contenitori.
  3. Media query: regole condizionate alla finestra.
css
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):

css
: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, --bordo stanno in :root e sono usate con var();
  • box-sizing: border-box per tutto; body fissa carattere, interlinea e colori che i discendenti ereditano;
  • l'intestazione è un contenitore flex con space-between (titolo a sinistra, menu a destra) e flex-wrap perché su telefono vada a capo;
  • il menu è un elenco ridotto a riga con display: flex e senza puntini (list-style: none); i link ereditano il colore (color: inherit);
  • main è una grid (una colonna, poi due con la media query); le section sono schede con bordo e angoli arrotondati;
  • la tabella ha border-collapse: collapse (bordi fusi), righe a strisce con tbody tr:nth-child(even);
  • il campo non valido ha il bordo rosso con :user-invalid, solo dopo che l'utente ha interagito (con :invalid apparirebbe subito su tutti i campi vuoti);
  • il foglio non usa id né !important: tutte le regole hanno specificità bassa e prevedibile (il massimo è (0,1,2), per nav a:hover e tbody 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 !important per 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: absolute senza antenato relative: l'elemento si posiziona rispetto alla pagina.
  • Confondere justify-content (asse principale) e align-items (asse trasversale).
  • li .libera (discendente) al posto di li.libera (stesso elemento).
  • Dimenticare il meta viewport: le media query sembrano non funzionare sul telefono.
  • Aspettarsi che margin o border si ereditino.

Domande d'esame

  1. Calcolare la specificità di #app li.occupata, .contenitore .elenco .libera e ul li.aula e dire quale vince su un li che 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; !important e stile inline cambiano l'ordine.
  2. Spiegare il box model e la differenza fra content-box e border-box. content, padding, border, margin; con content-box width è solo il contenuto (200 + 40 + 10 = 250 px di larghezza totale), con border-box include padding e bordo (200); i margini verticali collassano.
  3. 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-width con 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 !important su .occupata il li#lab diventa 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.
  • !important come scorciatoia.
  • content-box che fa uscire la scheda dal contenitore.
  • Margini sommati invece che collassati.
  • absolute senza antenato relative.
  • justify-content e align-items scambiati.
  • 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.

css
.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.

css
main { display: grid; gap: 1rem; padding: 1rem; }
@media (min-width: 48rem) { main { grid-template-columns: 2fr 1fr; align-items: start; } }

Mobile-first: stili base per lo schermo piccolo, poi min-width. Con il meta viewport nell'HTML (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 →).

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-box contro border-box, collasso dei margini.
  • Flexbox su una dimensione, grid su due; meta viewport, unità relative, media query.

Esercizi su questo argomento

Teoria collegata