CSS — Layout Avanzato

clamp() · container queries · nesting · @layer · subgrid · dark mode · print · 2026 · Marco Consiglio
Volta Institute · Napoli
A.A. 2026
📐 clamp() — tipografia e dimensioni fluide
clamp(MIN, PREFERITO, MAX) è la funzione CSS che imposta un valore fluido che cresce con il viewport ma non scende sotto il minimo né supera il massimo. Risolve la maggior parte dei casi d'uso delle media query per font e dimensioni.
/* sintassi: clamp(minimo, valore-preferito, massimo) */ h1 { font-size: clamp(1.5rem, 4vw, 3rem); /* ↑ min ↑ fluido ↑ max */ /* sotto 375px resta 1.5rem */ /* tra 375px e 750px cresce */ /* sopra 750px si ferma a 3rem */ } .container { width: clamp(300px, 90%, 1200px); padding: clamp(1rem, 5vw, 3rem); /* padding fluido */ } .card { gap: clamp(8px, 2vw, 24px); /* gap fluido in grid/flex */ }
▸ anteprima live — ridimensiona la finestra
Questo testo usa clamp(1rem, 3vw, 1.5rem)
📏 min() e max() — fratelli di clamp()
min() sceglie il valore più piccolo tra i candidati. max() sceglie il più grande. Si usano per vincoli semplici in una sola direzione.
/* min(): non superare 600px ma usa 90% se è più piccolo */ .sidebar { width: min(90%, 600px); } /* max(): non scendere sotto 200px ma usa 50% se è più grande */ .thumbnail { width: max(50%, 200px); } /* combinati: gap che cresce ma con un minimo garantito */ .grid { gap: max(12px, min(2vw, 32px)); }
FunzioneLogicaCaso d'uso tipico
clamp(min,pref,max)Valore fluido tra due estremiFont-size responsivo, padding, gap
min(a, b)Prende il minore dei dueLarghezza con limite massimo
max(a, b)Prende il maggiore dei dueAltezza con limite minimo
💡 Regola pratica: clamp() sostituisce spesso un'intera media query di tipografia. Invece di scrivere un @media solo per cambiare il font-size, scrivi un clamp() direttamente sulla proprietà.
✅ Supporto browser 2026: clamp(), min() e max() sono supportate al 97%+ da tutti i browser moderni (Chrome, Firefox, Safari, Edge).
📦 Container Queries — il futuro del responsive
Le media query classiche cambiano lo stile in base alla larghezza del viewport (finestra del browser). Le container queries cambiano lo stile in base alla larghezza del contenitore padre. Questo permette a un componente di adattarsi al suo contesto ovunque sia inserito.
/* 1. Dichiara il container sul padre */ .card-wrapper { container-type: inline-size; /* osserva la larghezza */ container-name: card; /* nome opzionale */ } /* 2. Scrivi la regola @container sul figlio */ @container card (min-width: 400px) { .card { display: flex; flex-direction: row; /* orizzontale se largo */ gap: 1rem; } } @container card (max-width: 399px) { .card { display: block; /* colonna se stretto */ } }
▸ stessa card, due contenitori di larghezza diversa
📦 Contenitore stretto
card verticale
img sopra
testo sotto
📦 Contenitore largo
card orizzontale
img a sinistra, testo a destra
✅ Vantaggio chiave: una card Flexbox/Grid si adatta al suo slot nella griglia, non al viewport. Lo stesso componente in una sidebar stretta mostra layout verticale, in un'area main largo mostra layout orizzontale.
🔍 Media query vs Container query — confronto
Aspetto@media (viewport)@container (contenitore)
Basata suLarghezza finestra browserLarghezza del parent diretto
Riutilizzo componente⚠️ Difficile — dipende dal contesto✅ Il componente è auto-adattivo
Design system⚠️ Richiede override per ogni contesto✅ Componente portabile
Supporto 2026✅ 100%✅ 93%+ (Chrome 105+, Safari 16+, FF 110+)
Caso d'uso idealeLayout globale della paginaComponenti riutilizzabili (card, widget)
💡 Strategia 2026: usa @media per la struttura della pagina (sidebar/main, breakpoint globali) e @container per i componenti (card, button, nav). Le due tecniche sono complementari, non alternative.
🪆 CSS Nesting — scrivere CSS come Sass, senza preprocessori
Dal 2023 i browser supportano nativamente il CSS nesting: puoi scrivere selettori annidati dentro altri selettori, esattamente come in Sass/Less, senza alcun build step.
/* CSS MODERNO — nesting nativo (2023+) */ .card { background: white; border-radius: 8px; padding: 1rem; /* & = il selettore padre (.card) */ & h2 { /* .card h2 */ font-size: 1.2rem; color: #1A1A1A; } &:hover { /* .card:hover */ box-shadow: 0 4px 20px rgba(0,0,0,.1); } &.featured { /* .card.featured */ border: 2px solid gold; } /* media query dentro il selettore */ @media (min-width: 768px) { display: flex; gap: 1rem; } }
✅ Supporto 2026: CSS nesting nativo è supportato in Chrome 112+, Safari 16.5+, Firefox 117+. Copre oltre il 93% degli utenti globali — usabile in produzione.
⚠️ Il simbolo & rappresenta sempre il selettore padre. Senza &, gli elementi annidati vengono trattati come discendenti (spazio implicito). La logica è identica a Sass.
🎯 @layer — controllare la cascata CSS
@layer organizza il CSS in livelli di priorità espliciti. I layer dichiarati prima hanno priorità minore — questo risolve i conflitti di specificità nei design system, senza ricorrere a !important.
/* 1. Dichiara l'ordine dei layer (dal meno al più prioritario) */ @layer reset, base, components, utilities; /* 2. Riempi ogni layer */ @layer reset { * { margin: 0; padding: 0; box-sizing: border-box; } } @layer base { body { font-family: sans-serif; color: #1A1A1A; } h1 { font-size: 2rem; } } @layer components { .btn { background: blue; color: white; padding: .5rem 1rem; } } @layer utilities { /* vince sempre — è l'ultimo layer dichiarato */ .text-red { color: red; } } /* CSS fuori da qualsiasi layer vince su tutti i layer */ .override { color: green; } /* questo batte utility layer */
💡 Ordine di vincita: CSS fuori layer > ultimo layer dichiarato > … > primo layer dichiarato. Il layer utilities dichiarato quarto batte reset dichiarato primo, anche se i selettori di reset hanno specificità più alta.
🗂️ CSS Columns — layout editoriale multi-colonna
column-count e column-width distribuiscono automaticamente il contenuto su più colonne, come in un giornale o rivista. Il browser bilancia il contenuto tra le colonne in modo autonomo.
.articolo { column-count: 3; /* 3 colonne fisse */ column-gap: 2rem; /* spazio tra colonne */ column-rule: 1px solid #ccc; /* linea separatrice */ } /* oppure: larghezza minima colonna, il browser decide quante */ .news { column-width: 250px; /* responsive automatico */ column-gap: 1.5rem; } /* un elemento che occupa tutte le colonne */ .titolo-principale { column-span: all; /* attraversa tutte le colonne */ font-size: 2rem; margin-bottom: 1rem; }
▸ testo distribuito su 3 colonne
Il CSS layout multi-colonna divide il contenuto in colonne come una rivista. Il browser distribuisce automaticamente il testo tra le colonne bilanciando l'altezza. Ottimo per articoli lunghi, glossari e elenchi estesi che si leggono meglio in formato editoriale a più colonne.
⬛ aspect-ratio — proporzioni fisse senza trucchi padding
La proprietà aspect-ratio mantiene il rapporto larghezza/altezza di un elemento fisso, qualunque sia la larghezza disponibile. Elimina il vecchio trucco del padding-top: 56.25% per i video 16:9.
.video-wrapper { width: 100%; aspect-ratio: 16 / 9; /* sempre in formato 16:9 */ } .avatar { width: 80px; aspect-ratio: 1 / 1; /* quadrato perfetto */ border-radius: 50%; } .card-cover { aspect-ratio: 4 / 3; object-fit: cover; /* immagine che riempie senza deformarsi */ }
▸ tre elementi con aspect-ratio diversi
16/9
1/1
4/3
🔲 Subgrid — allineare griglia padre e griglia figlia
subgrid permette a un elemento figlio di ereditare le colonne o le righe del grid padre, allineando perfettamente gli elementi interni alla griglia principale senza ridefinirla.
.grid-padre { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } /* la card occupa tutte e 3 le colonne del padre... */ .card { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; /* ...e usa le stesse 3 colonne */ } /* i figli della card si allineano alla griglia padre */ .card h2 { grid-column: 1; } /* prima colonna del padre */ .card p { grid-column: 2; } /* seconda colonna del padre */ .card img{ grid-column: 3; } /* terza colonna del padre */
💡 Caso d'uso tipico: una lista di card che devono avere tutti i titoli allineati in verticale tra loro, indipendentemente dalla lunghezza del testo. Con subgrid ogni card eredita le colonne del parent e gli elementi interni si allineano automaticamente.
⚠️ Supporto subgrid 2026: Chrome 117+, Safari 16+, Firefox 71+ (limitato). Copre circa 88% degli utenti — verificare prima di usare in produzione senza fallback.
🌙 @prefers-color-scheme — dark mode nativa
La media query @media (prefers-color-scheme: dark) si attiva automaticamente quando l'utente ha scelto il tema scuro nelle impostazioni del sistema operativo. Nessun JavaScript richiesto per il comportamento base.
/* variabili in modalità chiara (default) */ :root { --bg: #FFFFFF; --text: #1A1A1A; --card-bg: #F5F5F5; --accent: #7C3AED; } /* sovrascrive le variabili in dark mode */ @media (prefers-color-scheme: dark) { :root { --bg: #1E1E2E; --text: #CDD6F4; --card-bg: #313244; --accent: #CBA6F7; } } /* tutto il CSS usa le variabili — si adatta automaticamente */ body { background: var(--bg); color: var(--text); } .card { background: var(--card-bg); } a { color: var(--accent); }
▸ simulazione tema scuro

Titolo in dark mode

Testo con colore adattato automaticamente alle preferenze OS

✅ Pattern consigliato: definisci tutte le variabili in :root per il tema chiaro, poi sovrascrivile solo in @media (prefers-color-scheme: dark). Il resto del CSS non cambia — usa sempre le variabili. Questo approccio è molto più facile da mantenere rispetto a duplicare le regole.
♿ @prefers-reduced-motion — rispetta chi evita le animazioni
@media (prefers-reduced-motion: reduce) si attiva quando l'utente ha abilitato la riduzione del movimento nel sistema operativo. Questa impostazione è usata da persone con epilessia fotosensibile, vertigini o disturbi vestibolari.
/* animazione normale */ .spinner { animation: spin 1s linear infinite; } .card { transition: transform .3s ease; } .card:hover { transform: translateY(-4px); } /* disabilita/riduce le animazioni se richiesto dall'utente */ @media (prefers-reduced-motion: reduce) { * { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; } }
⚠️ Obbligo WCAG 2.1 (AA): il criterio 2.3.3 richiede che le animazioni non essenziali possano essere disabilitate dall'utente. Ignorare prefers-reduced-motion è una violazione di accessibilità.
💡 Pattern alternativo: invece di azzerare tutto, puoi ridurre l'animazione mantenendola funzionale: abbassa la durata da 300ms a 50ms, elimina il translateY ma mantieni il cambio di colore.
🖨️ @media print — stile ottimizzato per la stampa
La media query @media print si attiva quando l'utente stampa la pagina o la esporta in PDF dal browser. Permette di nascondere elementi inutili su carta (nav, sidebar, ads) e ottimizzare il layout per la stampa.
@media print { /* nascondi elementi inutili su carta */ nav, aside, .cookie-banner, .social-share, button, .ads { display: none !important; } /* layout a colonna singola */ body { font-size: 12pt; /* usa pt per la stampa */ color: #000; /* nero puro — risparmio inchiostro */ background: white; column-count: 1; /* una sola colonna */ } /* mostra l'URL dei link (invisibile a video) */ a::after { content: " (" attr(href) ")"; font-size: .8em; color: #666; } /* evita interruzioni di pagina dentro elementi importanti */ h1, h2, h3 { page-break-after: avoid; /* non separare il titolo dal testo */ } .card, table, figure { page-break-inside: avoid; /* non spezzare a metà */ } }
▸ simulazione pagina stampata
📄 @page — impostazioni della pagina stampata
@page controlla i margini, le dimensioni e l'orientamento del foglio stampato. Funziona in combinazione con @media print.
/* margini del foglio stampato */ @page { size: A4 portrait; /* A4 verticale */ margin: 2cm 2.5cm 2cm 2.5cm; /* top right bottom left */ } /* prima pagina senza intestazione */ @page :first { margin-top: 4cm; } /* pagine di sinistra e destra (per stampa fronte/retro) */ @page :left { margin-left: 3cm; } @page :right { margin-right: 3cm; } /* forza una nuova pagina prima di un elemento */ h1 { break-before: page; /* ogni H1 inizia una nuova pagina */ }
ProprietàValori utiliEffetto
page-break-beforealways, avoid, autoInterruzione prima dell'elemento
page-break-afteralways, avoid, autoInterruzione dopo l'elemento
page-break-insideavoid, autoEvita spezzare l'elemento
break-before/afterpage, column, avoidVersione moderna (CSS3)
💡 Le proprietà moderne sono break-before, break-after, break-inside (CSS Fragmentation Level 3). Le versioni page-break-* sono la forma precedente ancora supportata per compatibilità.