LezIA|HUB
← Informatica →🎮 CSS — Cascading Style Sheets
CSS Manuale Web

Manuale completo di CSS

Dalla prima regola di stile al layout responsive: guida a 3 livelli con centinaia di esempi spiegati nel dettaglio, demo live, 60 esercizi e un progetto finale.

✓ 3 livelli ✓ 200+ esempi ✓ 60 esercizi ✓ Progetto finale
Livello Base

0Cos'è CSS Base

Immagina di costruire una casa. L'HTML sono i mattoni, le travi, i muri: definisce la struttura. Il CSS è tutto il resto: la vernice, il colore delle piastrelle, la posizione dei mobili. Senza CSS, il web sarebbe una noiosa sequenza di testo nero su sfondo bianco.

CSS (Cascading Style Sheets) è il linguaggio che descrive come apparire gli elementi HTML. Il termine "a cascata" si riferisce al modo in cui le regole vengono applicate: se più regole si applicano allo stesso elemento, il browser decide quale usare seguendo un ordine preciso.

Anatomia di una regola

Ogni regola CSS è composta da un selettore e un blocco di dichiarazioni:

anatomia.css
h1 {
  color: #142850;   /* dichiarazione */
  font-size: 2rem;
}
  • Selettore (h1): dice al browser quale elemento deve essere stilizzato.
  • Dichiarazione (color: #142850): è composta da una proprietà (color) e un valore (#142850).
  • Regola: è l'insieme di selettore + blocco { }.
i
Separazione delle responsabilità

HTML = struttura · CSS = presentazione · JavaScript = comportamento. Tenerli separati rende il codice più pulito e manutenibile.

1Sintassi e collegamento Base

Ci sono tre modi per collegare il CSS a una pagina HTML. Solo uno è quello giusto per un progetto serio.

1.1 CSS inline (sconsigliato)

Scrivi lo stile direttamente nell'HTML. Funziona, ma è un incubo da gestire se devi cambiare qualcosa. Immagina di avere 100 paragrafi e voler cambiare il colore: dovresti modificarli tutti a mano.

inline.html
<p style="color: red; font-size: 20px;">Ciao</p>

1.2 CSS interno

Scrivi il codice in un tag <style> dentro l'<head>. Va bene per pagine singole o prototipi.

interno.html
<head>
  <style>
    h1 { color: #2E6FF2; }
  </style>
</head>

1.3 CSS esterno (consigliato)

Il CSS vive in un file separato (es. style.css) che viene collegato con il tag <link>. Questo è il metodo standard: puoi riutilizzare lo stesso foglio di stile su mille pagine diverse. Se cambi il colore in style.css, tutte le pagine collegate si aggiornano automaticamente.

esterno.html
<link rel="stylesheet" href="style.css">
✓
Regola d'oro

Usa sempre il CSS esterno. Inline solo per test rapidi, interno solo per pagine singole. Su progetti veri, il CSS esterno è l'unica scelta sensata.

2Selettori Base

I selettori sono lo strumento più importante del CSS: dicono al browser quali elementi devono essere stilizzati. Senza selettori, non puoi applicare alcuna proprietà. È il primo argomento da padroneggiare dopo la sintassi.

2.1 Selettore universale *

Seleziona tutti gli elementi della pagina. Si usa quasi sempre per il reset iniziale (margin, padding, box-sizing).

universale.css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
⚠
Attenzione alle prestazioni

Il selettore universale applica lo stile a ogni elemento, incluse le pseudo-classi ::before e ::after. Su pagine enormi può rallentare. Per il reset va benissimo, ma non abusarne.

2.2 Selettore di tipo (o di tag)

Seleziona tutti gli elementi di un certo tipo. Es: p seleziona tutti i <p>.

tag.css
p { color: gray; }
h1, h2, h3 { font-family: 'Sora', sans-serif; }
✓
Selettori raggruppati

Con la virgola puoi applicare la stessa regola a più selettori: h1, h2, h3 { ... }. Riduce la duplicazione del codice.

2.3 Selettore di classe .nome

Seleziona tutti gli elementi con un certo attributo class. È il selettore più usato in assoluto, perché è riutilizzabile.

classe.html
<p class="intro">Benvenuto</p>
<p class="intro evidenziato">Importante</p>
<p>Testo normale</p>
classe.css
.intro { color: #2E6FF2; font-weight: 600; }
.evidenziato { background: #FEF2E0; }
Demo — selettore di classe

Benvenuto (classe .intro)

Importante (classi .intro .evidenziato)

Testo normale (nessuna classe)

2.4 Selettore di ID #nome

Seleziona l'elemento con un certo attributo id. L'ID deve essere unico nella pagina. Ha specificità più alta della classe.

id.html
<div id="main">Contenuto principale</div>
id.css
#main { max-width: 1080px; margin: 0 auto; }
⚠
ID vs classe: quando usarli

Gli ID si usano per identificare un unico elemento (es. per JavaScript o ancore). Le classi si usano per lo stile, perché sono riutilizzabili. Regola pratica: non usare mai ID per lo stile, solo classi.

2.5 Selettore di attributo [attr]

Seleziona elementi in base alla presenza o al valore di un attributo. Utilissimo per stilizzare link, input, immagini.

SelettoreSelezionaEsempio
[href]Elementi con attributo hrefa[href] { color: blue; }
[type="email"]Attributo esattamente ugualeinput[type="email"] { border: 2px solid blue; }
[href^="https"]Inizia con "https"a[href^="https"] { color: green; }
[href$=".pdf"]Finisce con ".pdf"a[href$=".pdf"]::after { content: " 📄"; }
[href*="lezia"]Contiene "lezia"a[href*="lezia"] { font-weight: bold; }
[class~="box"]Contiene la parola "box"[class~="box"] { padding: 1rem; }
[lang|="it"]Inizia con "it-" o è "it"[lang|="it"] { font-style: italic; }

2.6 Combinatori: relazioni tra elementi

I combinatori selezionano elementi in base alla loro posizione nell'albero HTML.

CombinatoreSintassiSelezionaEsempio
DiscendenteA BTutti i B dentro A (anche annidati)div p
Figlio direttoA > BSolo i B figli diretti di Aul > li
Fratello adiacenteA + BIl primo B subito dopo Ah2 + p
Fratelli generaliA ~ BTutti i B dopo A (stesso genitore)h2 ~ p
Demo — discendente vs figlio diretto
HTML:
<ul class="menu">
  <li>Voce 1</li>
  <li><a href="#">Voce 2</a></li>
</ul>

ul > li seleziona solo i <li> figli diretti.

ul a (discendente) seleziona il link dentro il <li>.

2.7 Riepilogo dei selettori

TipoSintassiEsempio
Universale** { margin: 0; }
Tagpp { color: gray; }
Classe.box.box { padding: 1rem; }
ID#main#main { max-width: 1080px; }
Attributo[type="email"]input[type="email"] { border: 2px solid blue; }
Discendentediv pdiv p { margin: 1rem 0; }
Figliodiv > pdiv > p { font-weight: 700; }
Fratello adiacenteh2 + ph2 + p { margin-top: 0; }
Fratelli generalih2 ~ ph2 ~ p { color: gray; }

3Colori Base

Il colore è l'elemento più visibile. In CSS puoi definirlo in diversi formati: nomi, esadecimali, RGB, HSL. Ognuno ha i suoi vantaggi.

3.1 Formati a confronto

#2E6FF2esadecimale
rgb(46,111,242)rgb()
rgba(...,0.5)trasparenza
hsl(220,88%,57%)tonalità
tealnome
gradientgradiente
FormatoEsempioQuando usarlo
Nomered, teal, tomatoPrototipi veloci
Esadecimale#2E6FF2, #fffStandard, preciso
RGB / RGBArgb(46 111 242 / 50%)Trasparenze
HSL / HSLAhsl(220 88% 57%)Palette programmatiche
oklchoklch(60% 0.15 250)Colori percettivi (moderno)

3.2 opacity vs rgba: la differenza chiave

Questa è una delle distinzioni più importanti e confuse. opacity rende trasparente tutto l'elemento (incluso il testo e i bordi), mentre rgba agisce solo sul colore di sfondo.

Demo — opacity vs rgba
rgba(...,0.5)
solo lo sfondo è trasparente
opacity: 0.5
tutto è trasparente
⚠
Attenzione al contrasto

Un testo leggibile deve avere un rapporto di contrasto di almeno 4.5:1 rispetto allo sfondo. Testi grigi su sfondo bianco o viceversa sono spesso illeggibili. Verifica su WebAIM.

4Unità di misura Base

Quando scrivi font-size: 16px, stai usando un'unità di misura. Ma non tutte le unità sono uguali: alcune sono assolute (sempre uguali), altre relative (cambiano in base al contesto).

4.1 Unità assolute

Le unità assolute hanno sempre lo stesso valore, indipendentemente dal contesto. Si usano raramente perché non si adattano ai diversi dispositivi.

UnitàCorrisponde a...Quando usarla
pxPixel CSS (1/96 di pollice)Bordi, ombre, dettagli fissi
cmCentimetri (1cm ≈ 37.8px)Stampanti (raramente)
mmMillimetri (1mm ≈ 3.78px)Stampanti (raramente)
inPollici (1in = 96px = 2.54cm)Stampanti (raramente)
ptPunti (1pt = 1/72 di pollice)Stampanti (raramente)
pcPica (1pc = 12pt)Stampanti (raramente)

4.2 Unità relative al font

UnitàRelativa a...EsempioQuando usarla
emfont-size dell'elemento (o del genitore)1.5emSpaziature proporzionali al testo
remfont-size di <html> (di solito 16px)1.5rem = 24pxFont, spaziature (prevedibile)
chLarghezza del carattere "0"65chLimitare righe di testo
exAltezza della lettera "x"1exRaramente usato

4.3 Unità relative al viewport

Il viewport è l'area visibile della finestra del browser. Queste unità si adattano alle dimensioni della finestra.

UnitàCorrisponde a...Esempio
vw1% della larghezza viewport50vw
vh1% dell'altezza viewport100vh
vmin1% del lato più piccolo10vmin
vmax1% del lato più grande10vmax
dvhViewport dinamico (mobile)100dvh
svhViewport piccolo100svh
lvhViewport grande100lvh
i
Perché dvh/svh/lvh?

Su mobile, la barra degli indirizzi del browser può apparire/scomparire, cambiando l'altezza del viewport. vh non si adatta, causando problemi di layout. dvh (dynamic), svh (small) e lvh (large) risolvono questo problema.

4.4 Unità percentuali e frazionarie

UnitàRelativa a...Esempio
%Dimensione del genitorewidth: 50%
frFrazione dello spazio disponibile (solo Grid)grid-template-columns: 1fr 2fr

4.5 em vs rem: la differenza cruciale

Questa è una delle fonti di confusione principali. em è relativo alla dimensione del font del genitore, mentre rem è relativo alla dimensione del font della radice (<html>).

em-rem.css
html { font-size: 16px; }
.a { font-size: 20px; padding: 1em; }  /* = 20px (relativo al genitore) */
.b { font-size: 20px; padding: 1rem; } /* = 16px (relativo alla radice) */
Demo — em vs rem a confronto
Genitore con font-size:20px
padding: 1em → 20px
padding: 1rem → 16px (fisso, indipendente dal genitore)
✓
Regola d'oro per i principianti

Usa rem per font e spaziature (è prevedibile), px per bordi sottili, % e fr per layout, ch per limitare la lunghezza delle righe di testo, e dvh per altezze a schermo intero su mobile.

5Sfondi Base

Lo sfondo di un elemento può essere un colore solido, un'immagine, o un gradiente. CSS offre molte proprietà background-* per controllare ogni aspetto dello sfondo.

5.1 background-color

Imposta il colore di sfondo. Accetta qualsiasi formato colore.

bg-color.css
.box { background-color: #2E6FF2; }
.box-2 { background-color: rgb(46 111 242 / 50%); }
.box-3 { background-color: transparent; } /* default */

5.2 background-image

Imposta un'immagine di sfondo. Può essere un URL, un gradiente, o più immagini sovrapposte.

bg-image.css
.a { background-image: url('foto.jpg'); }
.b { background-image: linear-gradient(135deg, #2E6FF2, #7C5CFC); }
.c {
  background-image:
    linear-gradient(rgba(0,0,0,.5), rgba(0,0,0,.5)),
    url('foto.jpg'); /* overlay scuro sopra foto */
}

5.3 background-size: cover vs contain

Controlla come l'immagine si adatta al contenitore. Questa è la proprietà più confusa per i principianti.

ValoreEffettoQuando usarlo
autoDimensione originaleImmagini piccole decorative
coverCopre tutto il contenitore (ritaglia)Hero, sfondi a schermo intero
containMostra tutta l'immagine (lascia spazi)Loghi, icone, immagini che non si possono tagliare
100% 100%Stira l'immagineRaramente (distorce)
200px 100pxLarghezza e altezza fissePattern, texture
Demo — background-size: cover
cover — l'immagine copre tutto il contenitore (potrebbe ritagliare)
Demo — background-size: contain
contain — l'immagine è tutta visibile (potrebbe lasciare spazi vuoti)

5.4 background-repeat

Controlla se e come l'immagine si ripete.

ValoreEffetto
repeatRipete in entrambe le direzioni (default)
no-repeatNessuna ripetizione
repeat-xSolo orizzontale
repeat-ySolo verticale
spaceRipete con spazi uguali
roundRipete e scala per adattarsi

5.5 background-position

Posiziona l'immagine di sfondo. Accetta parole chiave, percentuali o misure.

bg-pos.css
.a { background-position: center; }
.b { background-position: top left; }
.c { background-position: 50% 50%; }
.d { background-position: 20px 40px; }
.e { background-position: right 20px bottom 40px; }

5.6 background-attachment

Controlla se lo sfondo scorre con la pagina o rimane fisso.

ValoreEffetto
scrollScorre con la pagina (default)
fixedRimane fisso mentre scorri (effetto parallasse)
localScorre con il contenuto dell'elemento

5.7 background-clip e background-origin

background-clip decide dove si applica lo sfondo (fino al bordo, al padding, al contenuto, o al testo). background-origin decide da dove parte il posizionamento.

bg-clip.css
.a { background-clip: border-box; }    /* default: fino al bordo */
.b { background-clip: padding-box; }   /* fino al padding */
.c { background-clip: content-box; }   /* solo il contenuto */
.d {
  background: linear-gradient(90deg, #2E6FF2, #7C5CFC);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent; /* testo con gradiente */
}

5.8 background-blend-mode

Mescola più immagini di sfondo o un'immagine con un colore, usando le stesse modalità di Photoshop.

ValoreEffetto
normalNessun blending (default)
multiplyMoltiplica (scurisce)
screenSchiarisce
overlayContrasto
darkenPiù scuro dei due
lightenPiù chiaro dei due
color-dodgeSchiarisce i toni
differenceDifferenza assoluta

5.9 background: shorthand

Tutte le proprietà precedenti possono essere scritte insieme con la scorciatoia background.

bg-shorthand.css
/* background: colore immagine posizione/size repeat attachment */
.d {
  background: #2E6FF2 url('foto.jpg') center / cover no-repeat fixed;
}
⚠
Attenzione all'ordine nello shorthand

Nello shorthand background, la position e la size vanno insieme separate da /. Se sbagli l'ordine, il browser ignora la regola.

5.10 Riepilogo proprietà sfondo

ProprietàValori principaliCosa fa
background-colorQualsiasi coloreColore di sfondo
background-imageurl(), gradient()Immagine o gradiente
background-sizecover, contain, 100%Dimensione immagine
background-positioncenter, top left, 50% 50%Posizione
background-repeatno-repeat, repeat-x, repeat-yRipetizione
background-attachmentscroll, fixed, localScorrimento
background-clipborder-box, padding-box, content-box, textArea di applicazione
background-originborder-box, padding-box, content-boxOrigine posizionamento
background-blend-modemultiply, screen, overlay, ...Modalità fusione

6Bordi e outline Base

Il bordo è una linea che circonda l'elemento. Puoi controllarne spessore, stile e colore. La proprietà border è una scorciatoia per border-width, border-style e border-color.

6.1 border-width

Lo spessore del bordo. Accetta misure (px, em, rem) o parole chiave (thin, medium, thick).

border-width.css
.a { border-width: 2px; }              /* tutti i lati */
.b { border-width: 1px 2px; }           /* vert | orizz */
.c { border-width: 1px 2px 3px 4px; }     /* top right bottom left */
.d { border-top-width: 4px; }          /* solo sopra */

6.2 border-style

Lo stile del bordo. Senza border-style, il bordo non appare nemmeno se hai impostato width e color.

Demo — stili di bordo
solid
dashed
dotted
double
groove
ridge
inset
outset
none
hidden
ValoreEffetto
solidLinea continua
dashedTratteggiata
dottedPunteggiata
doubleDoppia linea
grooveEffetto incavo 3D
ridgeEffetto rilievo 3D
insetEffetto incassato
outsetEffetto in rilievo
noneNessun bordo (default)
hiddenCome none, ma in tabelle prevale

6.3 border-color

border-color.css
.a { border-color: #2E6FF2; }
.b { border-color: red blue green yellow; } /* top right bottom left */
.c { border-color: currentColor; } /* usa il colore del testo */

6.4 Shorthand: border

Le tre proprietà possono essere scritte insieme. L'ordine non conta, ma la convenzione è width style color.

border-shorthand.css
.box { border: 2px solid #2E6FF2; }
.misto {
  border-top: 2px solid red;
  border-right: 4px dashed blue;
  border-bottom: 1px dotted green;
  border-left: 3px double orange;
}

6.5 border-radius: angoli arrotondati

Arrotonda gli angoli del bordo. Accetta uno, due, tre o quattro valori.

radius.css
.a { border-radius: 8px; }                       /* tutti gli angoli */
.b { border-radius: 8px 16px; }                  /* top-left/bottom-right | top-right/bottom-left */
.c { border-radius: 8px 16px 24px; }             /* top-left | top-right/bottom-left | bottom-right */
.d { border-radius: 8px 16px 24px 32px; }        /* TL TR BR BL */
.pill { border-radius: 999px; }                  /* pillola */
.circle { border-radius: 50%; }                   /* cerchio (se quadrato) */
.ellisse { border-radius: 50% / 30%; }              /* ellisse */
Demo — border-radius
8px
50%
999px (pillola)
50% / 30%

6.6 outline vs border

outline è una linea fuori dal bordo che non occupa spazio nel layout. È usata per il focus accessibile (quando navighi con il Tab).

Proprietàborderoutline
Occupazione spazioSìNo
Angoli arrotondabiliSì (border-radius)No
Lati separatiSì (top, right, bottom, left)No (unica linea)
Uso tipicoStruttura visivaFocus accessibile
outline.css
button:focus-visible {
  outline: 3px solid #2E6FF2;
  outline-offset: 2px; /* distanza dal bordo */
}
⚠
Non rimuovere mai l'outline senza alternativa

Chi naviga da tastiera usa il Tab. Se rimuovi l'outline, rendi impossibile capire dove si trovi il focus. Usa :focus-visible con uno stile alternativo se vuoi rimuoverlo.

7Margin e padding Base

Questa è una delle distinzioni più importanti. Immagina una scatola da spedizione: il padding è il pluriball all'interno, il margin è lo spazio che lasci tra una scatola e l'altra.

  • Padding: spazio interno, tra il contenuto e il bordo.
  • Margin: spazio esterno, tra l'elemento e gli altri elementi.

7.1 Padding

padding.css
.a { padding: 20px; }              /* tutti i lati */
.b { padding: 10px 20px; }         /* vert | orizz */
.c { padding: 10px 20px 30px; }    /* top | orizz | bottom */
.d { padding: 10px 20px 30px 40px; } /* top right bottom left */
.e { padding-top: 10px; }          /* solo sopra */
.f { padding-inline: 20px; }       /* proprietà logica: sinistra+destra */

7.2 Margin

margin.css
.a { margin: 20px; }              /* tutti i lati */
.b { margin: 0 auto; }             /* centrato orizzontalmente */
.c { margin-top: -20px; }          /* margine negativo */
.d { margin-inline: auto; }        /* centrato (logico) */

7.3 Margin collapse: il comportamento che sorprende

Quando due margini verticali si incontrano, non si sommano ma si "sovrappongono". Vince il più grande. Questo è chiamato margin collapse.

Demo — margin collapse

P1 con margin-bottom: 30px

P2 con margin-top: 20px

Lo spazio tra i due è 30px, non 50px.

✓
Trucco per centrare

Un blocco con width fissa e margin: 0 auto si centra orizzontalmente. Non funziona con margin: auto su elementi senza larghezza definita.

i
Regola pratica

Usa padding per distanziare il contenuto dal bordo (dentro la scatola). Usa margin per distanziare un elemento dagli altri (fuori dalla scatola).

8Proprietà del testo Base

Il testo è il contenuto principale di una pagina web. CSS offre decine di proprietà per controllarne l'aspetto.

8.1 color e text-align

text-base.css
p { color: #1B2733; }
.center { text-align: center; }
.justify { text-align: justify; }

8.2 text-decoration

ValoreEffetto
noneNessuna decorazione
underlineSottolineato
overlineLinea sopra
line-throughBarrato
underline dottedSottolineatura punteggiata
Demo — text-decoration

Sottolineato

Linea sopra

Barrato

Sottolineato punteggiato

8.3 text-transform

Demo — text-transform

testo in maiuscolo

TESTO IN MINUSCOLO

testo con iniziali maiuscole

8.4 text-indent, letter-spacing, word-spacing

Demo

Questo paragrafo ha un rientro di 2em sulla prima riga.

Testo con spaziatura tra le lettere.

Testo con spaziatura tra le parole.

8.5 line-height

Controlla l'altezza della riga. Fondamentale per la leggibilità: un valore tra 1.5 e 1.7 è l'ideale per il corpo del testo.

Demo — line-height

Line-height 1.1 — molto compatto, difficile da leggere su testi lunghi.

Line-height 1.6 — il valore ideale per il corpo del testo. Offre buona leggibilità senza sprecare spazio.

Line-height 2 — troppo arioso, adatto solo per titoli o citazioni.

8.6 text-shadow

Sintassi: text-shadow: offset-x offset-y blur color;

Demo

Ombra base

Glow blu

Ombra retro multipla

8.7 text-overflow: troncare il testo

Per troncare il testo con ..., servono tre proprietà insieme: white-space: nowrap, overflow: hidden e text-overflow: ellipsis.

ellipsis.css
.titolo {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 300px;
}
Demo — text-overflow: ellipsis

Testo molto lungo che verrà troncato con ellipsis quando supera la larghezza del contenitore

8.8 Altre proprietà del testo

ProprietàValori principaliEffetto
white-spacenormal, nowrap, pre, pre-wrap, pre-lineGestione spazi e a capo
word-breaknormal, break-all, keep-allInterruzione parole
overflow-wrapnormal, break-word, anywhereA capo parole lunghe
hyphensnone, manual, autoSillabazione
directionltr, rtlDirezione testo
writing-modehorizontal-tb, vertical-rl, vertical-lrOrientamento testo

9Font Base

9.1 font-family

Definisce la famiglia tipografica. È buona norma specificare più font di fallback, in ordine di preferenza.

font-family.css
body {
  font-family: 'Sora', 'Helvetica Neue', Arial, sans-serif;
}

/* Generic families */
/* serif — con grazie (Times, Georgia) */
/* sans-serif — senza grazie (Arial, Helvetica) */
/* monospace — larghezza fissa (Courier, Consolas) */
/* cursive — corsivo (Comic Sans) */
/* fantasy — decorativo (Impact) */

9.2 font-size

Dimensione del testo. Puoi usare misure assolute (px) o relative (em, rem, %).

UnitàEsempioQuando usarla
px16pxMisure fisse (raramente)
rem1rem = 16pxConsigliata per font
em1.5emProporzionale al genitore
%150%Come em
clamp()clamp(1rem, 2vw, 1.5rem)Fluido (moderno)

9.3 font-weight

Spessore del font. I valori vanno da 100 (thin) a 900 (black).

Demo — font-weight

100 Thin

300 Light

400 Regular (default)

500 Medium

700 Bold

900 Black

9.4 font-style

font-style.css
.normal { font-style: normal; }
.italic { font-style: italic; }
.oblique { font-style: oblique 15deg; }

9.5 font shorthand

Puoi scrivere tutte le proprietà in una sola riga. L'ordine è obbligatorio: style weight size/line-height family.

font-shorthand.css
.titolo {
  font: italic 700 2rem/1.2 'Sora', sans-serif;
}

9.6 Google Fonts: come usare font personalizzati

Per usare un font personalizzato come "Inter" o "Sora", puoi collegarti a Google Fonts.

font.html
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

body { font-family: 'Inter', system-ui, sans-serif; }
✓
Regole pratiche
  • Base 16px (1rem): minimo leggibile
  • Line-height 1.5–1.7 per il corpo
  • Max 70-75 caratteri per riga (max-width: 65ch)
  • Massimo 2-3 font per progetto

11Liste Base

Le liste (<ul>, <ol>) hanno proprietà specifiche per controllare i marker (pallini, numeri).

11.1 list-style-type

Definisce il tipo di marker. Valori comuni per <ul> e <ol>:

TipoValori
Unordered list (ul)disc (default), circle, square, none
Ordered list (ol)decimal (default), decimal-leading-zero, lower-roman, upper-roman, lower-alpha, upper-alpha, lower-greek
Altrinone (rimuove il marker)
Demo — list-style-type

disc

  • Primo
  • Secondo

circle

  • Primo
  • Secondo

square

  • Primo
  • Secondo

upper-roman

  1. Primo
  2. Secondo

lower-alpha

  1. Primo
  2. Secondo

none

  • Primo
  • Secondo

11.2 list-style-position

Decide se il marker è dentro o fuori dal contenuto della lista.

Demo — list-style-position

outside (default)

  • Il marker è fuori dal testo, allineato a sinistra
  • Il testo è allineato verticalmente

inside

  • Il marker è dentro il blocco di testo
  • Il testo va a capo sotto il marker

11.3 list-style-image

Sostituisce il marker con un'immagine. Raramente usato perché poco controllabile.

list-style-image.css
ul {
  list-style-image: url('checkmark.svg');
}

11.4 list-style shorthand

list-style.css
ul { list-style: square inside; }
ul.menu { list-style: none; }

11.5 ::marker

Il pseudo-elemento ::marker permette di stilizzare direttamente il marker della lista.

Demo — ::marker stilizzato
  • Primo elemento con marker blu ← il marker è blu
  • Secondo elemento ← il marker è blu

Con li::marker { color: #2E6FF2; }

12Tabelle Base

Le tabelle hanno proprietà specifiche che le rendono più leggibili. La più importante è border-collapse.

12.1 border-collapse

Di default i bordi delle celle sono separati (con spaziatura). Con collapse, i bordi si fondono in un'unica linea.

table.css
table {
  width: 100%;
  border-collapse: collapse; /* bordi uniti */
  border-spacing: 0;       /* spaziatura (se separate) */
}
th { background: #142850; color: #fff; padding: 12px; text-align: left; }
td { padding: 12px; border-bottom: 1px solid #E1E7F0; }
tbody tr:nth-child(even) { background: #F7F9FC; } /* zebra */
tbody tr:hover { background: #E8F0FE; }              /* hover */
Demo — tabella con zebra striping e hover
NomeCognomeEtà
MarioRossi17
LucaBianchi18
SofiaVerdi16
AnnaNeri17

12.2 table-layout

Controlla come il browser calcola la larghezza delle colonne.

ValoreComportamento
autoDefault. Si adatta al contenuto.
fixedLarghezze fisse, più veloce da renderizzare.

12.3 caption-side

Posiziona il <caption> della tabella sopra o sotto.

caption.css
caption { caption-side: bottom; }

13Display Base

La proprietà display è la più importante per il layout: definisce come un elemento si comporta nel flusso del documento.

ValoreComportamentoEsempi
blockVa a capo, tutta la larghezza disponibilediv, p, h1, section
inlineNella riga, solo lo spazio necessariospan, a, strong, em
inline-blockCome inline ma accetta width/heightbottoni, badge
flexAttiva Flexbox per i figlinavbar, card
gridAttiva Grid per i figlilayout pagina
noneNasconde completamente (fuori dal layout)modali nascoste
contentsL'elemento "scompare", i figli restanowrapper trasparenti
Demo — block vs inline vs inline-block
block 1
block 2
inline 1 inline 2
inline-block inline-block
⚠
display: none vs visibility: hidden
  • display: none → scompare dal layout, non occupa spazio
  • visibility: hidden → invisibile ma occupa spazio

14Position Base

La proprietà position controlla come un elemento è posizionato nella pagina. È una delle più potenti e confuse.

ValoreComportamento
staticDefault, nel flusso normale
relativeNel flusso, spostabile con top/right/bottom/left, riferimento per absolute
absoluteFuori dal flusso, rispetto al primo antenato positioned
fixedFuori dal flusso, rispetto al viewport (non scorre)
stickyRelative poi fixed a una soglia di scroll

14.1 position: absolute dentro relative

Il pattern più comune: un genitore con position: relative e un figlio con position: absolute. Il figlio si posiziona rispetto al genitore.

Demo — position: absolute dentro relative

Il genitore ha position: relative. Il box rosa ha position: absolute.

Sono absolute
position.css
.parent { position: relative; }
.badge { position: absolute; top: 10px; right: 10px; }
.sticky { position: sticky; top: 0; z-index: 100; }
.fab { position: fixed; bottom: 20px; right: 20px; }

14.2 z-index

Quando due elementi si sovrappongono, z-index decide chi sta davanti. Funziona solo su elementi con position diversa da static.

z-index.css
.modal {
  position: fixed;
  z-index: 9999; /* sta davanti a tutto */
}
.header {
  position: sticky;
  top: 0;
  z-index: 100;
}

15Il Box Model Base

Ogni elemento HTML è una scatola rettangolare. Il Box Model descrive come questa scatola è composta, dall'interno verso l'esterno:

  1. Content: il contenuto vero e proprio (testo, immagine).
  2. Padding: lo spazio tra il contenuto e il bordo.
  3. Border: la linea di confine.
  4. Margin: lo spazio esterno, che separa l'elemento dagli altri.
Demo — Box Model completo
MARGIN
BORDER + PADDING
CONTENT

15.1 box-sizing: la trappola da conoscere

Di default, se dai a un elemento width: 200px e padding: 20px, la sua larghezza totale sarà 240px (200 + 20 + 20). Questo perché il padding si aggiunge alla larghezza. La proprietà box-sizing: border-box cambia questo comportamento: la larghezza include padding e bordo.

Demo — content-box vs border-box

Entrambi con width: 200px; padding: 20px; border: 5px:

content-box → 250px
border-box → 200px
reset.css
/* Reset universale: SEMPRE all'inizio del tuo CSS */
*, *::before, *::after { box-sizing: border-box; }

15.2 box-shadow

Sintassi: box-shadow: offset-x offset-y blur spread color inset;

base
colorata
inset
multipla

16Float e clear Base

float serviva per layout multi-colonna prima di Flex/Grid. Oggi si usa principalmente per far scorrere il testo attorno a un'immagine.

Demo — float: left
float left

Il testo scorre attorno al box blu. Se è abbastanza lungo, continuerà sotto di esso. Questo è il comportamento tipico di un'immagine con testo che la circonda.

float.css
.float-img { float: left; margin-right: 1rem; }
.clear { clear: both; }

/* Clearfix tradizionale */
.clearfix::after { content: ""; display: table; clear: both; }

/* Metodo moderno */
.clearfix { display: flow-root; }
✓
Oggi: Flexbox o Grid

Per layout multi-colonna usa Flexbox o Grid. Sono più potenti, prevedibili e non richiedono clearfix.

17Overflow Base

Cosa succede quando il contenuto è troppo grande per il suo contenitore? La proprietà overflow decide se mostrarlo, nasconderlo o aggiungere barre di scorrimento.

ValoreEffetto
visibleDefault, il contenuto esce
hiddenTagliato
scrollBarre sempre visibili
autoBarre solo se servono
clipCome hidden senza scroll
Demo — overflow

visible

Testo che esce dal contenitore quando è troppo lungo.

hidden

Testo che esce dal contenitore quando è troppo lungo.

scroll

Testo che esce dal contenitore quando è troppo lungo.

auto

Testo che esce dal contenitore quando è troppo lungo.

18Pseudo-classi Base

Le pseudo-classi selezionano elementi in uno stato particolare (es. quando il mouse ci passa sopra, quando un campo è a fuoco, quando un link è stato visitato). Sono scritte con i due punti :.

18.1 Pseudo-classi di stato

Pseudo-classeSeleziona...
:hoverElemento sotto il mouse
:focusElemento a fuoco (input, button)
:focus-visibleFocus da tastiera (non da mouse)
:activeElemento attivo (durante il click)
:visitedLink già visitato
:linkLink non ancora visitato
:checkedCheckbox/radio selezionato
:disabledElemento disabilitato
:enabledElemento abilitato
:requiredCampo obbligatorio
:valid / :invalidValidità campo form
stato.css
a:hover { color: #E8A34E; text-decoration: underline; }
input:focus { outline: 2px solid #2E6FF2; }
button:active { transform: scale(.97); }
input:checked + label { font-weight: 700; }
input:disabled { opacity: .5; }

18.2 Pseudo-classi strutturali

Pseudo-classeSeleziona...
:first-childPrimo figlio
:last-childUltimo figlio
:nth-child(n)n-esimo figlio
:nth-child(even)Figli pari
:nth-child(odd)Figli dispari
:nth-child(3n)Ogni 3 figli
:first-of-typePrimo elemento del suo tipo
:last-of-typeUltimo elemento del suo tipo
:only-childUnico figlio
:emptyElemento senza figli/testo
strutturali.css
li:first-child { font-weight: 700; }
li:last-child { border-bottom: none; }
li:nth-child(even) { background: #EEF2FA; }
li:nth-child(3n) { color: red; }

18.3 Pseudo-classi di negazione

:not(...) esclude elementi che corrispondono al selettore passato.

not.css
p:not(.intro) { margin-top: 1rem; }
button:not([disabled]) { cursor: pointer; }

18.4 Pseudo-classi avanzate (livello intermedio)

Pseudo-classeDescrizione
:is(...)Raggruppa selettori (riduce ripetizione)
:where(...)Come :is() ma con specificità 0
:has(...)Seleziona il genitore in base al figlio (rivoluzionario)
:focus-withinGenitore con figlio a fuoco
avanzate.css
/* :is() — raggruppa selettori */
:is(article, section) :is(h1, h2) { color: #142850; }

/* :where() — come :is() ma specificità 0 */
:where(ul, ol) { padding-left: 1.5rem; }

/* :has() — seleziona il genitore in base al figlio */
form:has(input:invalid) { border-color: red; }
.card:has(img) { padding: 0; }

/* :focus-within — genitore con figlio a fuoco */
fieldset:focus-within {
  border-color: #2E6FF2;
  background: #E8F0FE;
}

19Pseudo-elementi Base

I pseudo-elementi creano "finti" elementi che non esistono nell'HTML. Sono scritti con due due punti :: (invece che uno).

Pseudo-elementoUso
::beforeContenuto prima (richiede content)
::afterContenuto dopo (richiede content)
::first-linePrima riga di testo
::first-letterPrima lettera (capolettera)
::markerMarker di lista
::placeholderPlaceholder di input
::selectionTesto selezionato dall'utente
::backdropSfondo di dialoghi fullscreen

19.1 ::before e ::after

I più usati. Creano contenuto prima o dopo un elemento. Devono avere obbligatoriamente la proprietà content, anche solo content: "".

before-after.css
/* Freccia sui link esterni */
a[target="_blank"]::after { content: " ↗"; }

/* Linea decorativa sotto h2 */
h2::after {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  background: #2E6FF2;
  margin-top: .5rem;
}

/* Clearfix */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

19.2 ::first-line e ::first-letter

Demo — ::first-letter (capolettera)

Questo paragrafo ha un capolettera stilizzato con il pseudo-elemento ::first-letter. È un effetto tipico dei giornali e delle riviste.

19.3 ::marker

Stilizza il marker di una lista (pallino, numero).

marker.css
li::marker {
  color: #2E6FF2;
  font-size: 1.5em;
}

19.4 ::placeholder

placeholder.css
input::placeholder {
  color: #9dabc2;
  font-style: italic;
}

19.5 ::selection

Demo — ::selection (seleziona il testo)

Questo testo ha uno stile di selezione personalizzato: seleziona queste parole e vedrai il colore.

20Specificità e cascata Base

Quando due regole si applicano allo stesso elemento, vince quella con specificità maggiore. La specificità è calcolata come una specie di punteggio (a, b, c, d):

  • a: stili inline (0 o 1)
  • b: numero di #id
  • c: numero di classi, pseudo-classi, attributi
  • d: numero di tag e pseudo-elementi
SelettoreSpecificità
*(0,0,0,0)
p(0,0,0,1)
.box(0,0,1,0)
nav a(0,0,0,2)
.box p(0,0,1,1)
#main .box p(0,1,1,1)
style="..."(1,0,0,0)
⚠
!important è una trappola

Se ti serve, c'è un problema di architettura. Usalo solo per override di terze parti o utility class.

★Esempi pratici · Base

Tre componenti completi che mettono insieme tutto il livello Base: card, menu di navigazione e layout di pagina.

Esempio 1 — Card

Una card riutilizzabile con immagine, titolo, testo e pulsante.

card.html
<article class="card">
  <img src="foto.jpg" alt="Descrizione" class="card-img">
  <div class="card-body">
    <h3>Titolo card</h3>
    <p>Breve descrizione del contenuto della card.</p>
    <a href="#" class="btn">Scopri di più</a>
  </div>
</article>
card.css
.card {
  background: #fff;
  border-radius: 12px;
  border: 1px solid #E1E7F0;
  overflow: hidden;
  max-width: 320px;
  transition: transform .2s, box-shadow .2s;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 15px 30px -15px rgba(46,111,242,.4);
}
.card-img {
  width: 100%;
  height: 180px;
  object-fit: cover;
  display: block;
}
.card-body { padding: 1.2rem; }
.card-body h3 { margin: 0 0 .5rem; color: #142850; }
.card-body p { color: #566072; font-size: .9rem; margin-bottom: 1rem; }
.btn {
  display: inline-block;
  padding: .5rem 1rem;
  background: #2E6FF2;
  color: #fff;
  text-decoration: none;
  border-radius: 6px;
  font-size: .85rem;
  transition: background .15s;
}
.btn:hover { background: #1e5bd6; }
Risultato

Titolo card

Breve descrizione del contenuto della card.

Scopri di più

Esempio 2 — Menu di navigazione

Logo a sinistra, voci a destra, hover e voce attiva, responsive su mobile.

menu.css
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background: #fff;
  box-shadow: 0 2px 10px rgba(0,0,0,.05);
}
.logo { font-size: 1.3rem; font-weight: 800; color: #2E6FF2; text-decoration: none; }
.menu {
  display: flex;
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.menu a {
  color: #1B2733;
  text-decoration: none;
  font-weight: 600;
  padding: .4rem .8rem;
  border-radius: 8px;
  transition: background .15s, color .15s;
}
.menu a:hover { background: #E8F0FE; color: #2E6FF2; }
.menu a.attivo { background: #2E6FF2; color: #fff; }

@media (max-width: 640px) {
  .site-header { flex-direction: column; gap: 1rem; }
  .menu { flex-direction: column; text-align: center; }
}
Risultato

Esempio 3 — Layout di sito web

Header sticky, hero con gradiente, sezione contenuti e footer. Struttura base riutilizzabile.

layout.css
/* Reset */
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #F7F9FC; line-height: 1.6; }

/* Header sticky */
.site-header {
  position: sticky; top: 0; z-index: 100;
  display: flex; justify-content: space-between; align-items: center;
  padding: 1rem 2rem; background: #fff;
  border-bottom: 1px solid #E1E7F0;
}

/* Hero */
.hero {
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  text-align: center; min-height: 60vh; padding: 2rem;
  background: linear-gradient(135deg, #2E6FF2, #7C5CFC); color: #fff;
}
.hero h1 { font-size: clamp(1.8rem, 5vw, 3rem); margin-bottom: 1rem; }
.hero .btn {
  display: inline-block; padding: .8rem 1.6rem;
  background: #fff; color: #2E6FF2; text-decoration: none;
  font-weight: 700; border-radius: 8px;
  transition: transform .2s;
}

/* Container + card */
.container { max-width: 1080px; margin: 0 auto; padding: 3rem 1.5rem; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.5rem; }

/* Footer */
.site-footer {
  text-align: center; padding: 2rem 1.5rem;
  background: #1B2733; color: #9dabc2; font-size: .85rem;
}

★20 esercizi · Livello Base

Prova prima da solo, poi apri la soluzione.

B1 · Sintassi

Collega un CSS esterno

Scrivi il tag per collegare style.css.

Soluzione
<link rel="stylesheet" href="style.css">
B2 · Selettori

Seleziona p con classe intro

Stilizza solo i <p> con classe intro.

Soluzione
p.intro { color: #2E6FF2; }
B3 · Colori

Colore del titolo

Imposta h1 a #142850.

Soluzione
h1 { color: #142850; }
B4 · Unità

Font-size in rem

h1 a 2rem, p a 1rem.

Soluzione
h1 { font-size: 2rem; }
p { font-size: 1rem; }
B5 · Sfondi

Sfondo sul body

Imposta sfondo #F7F9FC.

Soluzione
body { background-color: #F7F9FC; }
B6 · Sfondi

Immagine che copre

.hero con immagine di sfondo che copre, centrata, non ripetuta.

Soluzione
.hero {
  background: url('hero.jpg') center / cover no-repeat;
}
B7 · Bordi

Bordo tratteggiato

Bordo tratteggiato 2px viola.

Soluzione
.box { border: 2px dashed #7C5CFC; }
B8 · Bordi

Angoli arrotondati

Raggio 12px su una card.

Soluzione
.card { border-radius: 12px; }
B9 · Padding

Padding misto

1rem verticale e 2rem orizzontale.

Soluzione
.section { padding: 1rem 2rem; }
B10 · Margin

Centrare container

Container max 960px centrato.

Soluzione
.container {
  max-width: 960px;
  margin: 0 auto;
}
B11 · Testo

Testo centrato

Centra un paragrafo.

Soluzione
p { text-align: center; }
B12 · Testo

Maiuscolo

h2 tutti in maiuscolo.

Soluzione
h2 { text-transform: uppercase; }
B13 · Font

Font Google

Carica Sora e usalo nel body.

Soluzione
<link href="...family=Sora&display=swap" rel="stylesheet">

body { font-family: 'Sora', sans-serif; }
B14 · Link

Link senza sottolineatura

Rimuovi la sottolineatura.

Soluzione
a { text-decoration: none; }
B15 · Liste

Rimuovi pallini

Rimuovi i marker da una ul.

Soluzione
ul { list-style: none; padding: 0; }
B16 · Tabelle

Zebra striping

Colora le righe pari.

Soluzione
tbody tr:nth-child(even) {
  background: #F7F9FC;
}
B17 · Display

Span come block

Fai comportare uno span come blocco.

Soluzione
span.block { display: block; }
B18 · Position

Badge in alto a destra

Badge posizionato in alto a destra dentro una card.

Soluzione
.card { position: relative; }
.badge {
  position: absolute;
  top: 10px; right: 10px;
}
B19 · Box model

Reset universale

box-sizing: border-box su tutto.

Soluzione
*, *::before, *::after {
  box-sizing: border-box;
}
B20 · Overflow

Nascondi overflow

Nascondi contenuto in eccesso in un box alto 100px.

Soluzione
.box { height: 100px; overflow: hidden; }
Livello Intermedio

21Flexbox Intermedio

Sistema di layout monodimensionale (una riga o una colonna). Perfetto per navbar, card, centrare contenuti. Flexbox è diventato lo standard per la maggior parte dei layout moderni.

21.1 Proprietà del container

ProprietàValoriEffetto
displayflex | inline-flexAttiva Flexbox
flex-directionrow | column | row-reverse | column-reverseAsse principale
justify-contentflex-start | center | space-between | space-around | space-evenlyDistribuzione asse principale
align-itemsstretch | center | flex-start | flex-end | baselineAllineamento asse trasversale
gap1remSpazio tra i figli
flex-wrapnowrap | wrap | wrap-reverseVa a capo

21.2 flex-direction

La direzione principale. Di default è row (riga), ma puoi usare column per impilare verticalmente.

Demo — flex-direction: row (default)
A
B
C
Demo — flex-direction: column
Uno
Due
Tre

21.3 justify-content

Distribuisce gli elementi lungo l'asse principale (orizzontale se row, verticale se column).

Demo — justify-content: space-between
Logo
Menu
Demo — justify-content: center
Perfettamente centrato

21.4 align-items

Allinea gli elementi lungo l'asse trasversale (verticale se row, orizzontale se column).

Demo — align-items: flex-start
A
B
C
Demo — align-items: flex-end
A
B
C
Demo — align-items: center
A
B
C

21.5 Proprietà dei figli

ProprietàSignificato
flexShorthand grow/shrink/basis
flex-growQuanto cresce
flex-shrinkQuanto si restringe
flex-basisDimensione di partenza
align-selfOverride di align-items
orderCambia ordine visivo
✓
Pattern flex: 1

Se dai flex: 1 a due figli, si dividono lo spazio equamente. Se lo dai solo a uno, occupa tutto lo spazio rimasto. Perfetto per sidebar + contenuto.

navbar.css
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1rem 2rem;
}

22Responsive design Intermedio

Il responsive design permette a una pagina di adattarsi a qualsiasi dimensione di schermo (smartphone, tablet, desktop). È una competenza fondamentale: oltre il 60% del traffico web arriva da mobile.

22.1 Meta viewport

Il meta viewport è fondamentale per il responsive. Senza di esso, il browser mobile simula una larghezza desktop (es. 980px) e rimpicciolisce tutto.

viewport.html
<meta name="viewport" content="width=device-width, initial-scale=1.0">

22.2 Media query

Le media query permettono di applicare CSS diverso in base alle caratteristiche del dispositivo (larghezza, orientamento, preferenze).

media.css
/* Mobile-first: parti dal piccolo e aggiungi */
.container { padding: 1rem; }

@media (min-width: 768px) {
  .container { padding: 2rem; }
}

@media (min-width: 1024px) {
  .container { max-width: 1080px; margin: 0 auto; }
}

/* Combinazioni */
@media (min-width: 768px) and (max-width: 1023px) { /* tablet */ }

/* Preferenze utente */
@media (prefers-color-scheme: dark) { /* tema scuro */ }
@media (prefers-reduced-motion: reduce) { /* disabilita animazioni */ }
@media (orientation: landscape) { /* schermo orizzontale */ }
@media (hover: hover) { /* dispositivo con mouse */ }
@media (pointer: coarse) { /* touch screen */ }
BreakpointDispositivo
< 480pxSmartphone verticale
480 – 767pxSmartphone orizzontale
768 – 1023pxTablet
1024 – 1439pxDesktop
≥ 1440pxDesktop grande

22.3 Immagini e testo responsive

responsive.css
img { max-width: 100%; height: auto; display: block; }
h1 { font-size: clamp(1.5rem, 5vw, 3rem); }

/* Immagini con art direction (browser moderni) */
<picture>
  <source media="(min-width: 768px)" srcset="grande.jpg">
  <img src="piccola.jpg" alt="...">
</picture>
✓
Mobile-first

Parti da mobile e aggiungi con min-width. Se funziona su mobile, funziona ovunque. Le media query con min-width sono più facili da gestire di quelle con max-width.

23Transizioni Intermedio

Le transizioni rendono fluido il passaggio da uno stato all'altro. Invece di un cambiamento istantaneo, l'animazione avviene gradualmente.

23.1 Proprietà

ProprietàEsempioCosa fa
transition-propertybackgroundCosa animare
transition-duration.3sDurata
transition-timing-functionease-in-outCurva temporale
transition-delay.1sRitardo
transitionShorthandTutto insieme
transition.css
/* transition: proprietà durata timing delay */
.btn {
  background: #2E6FF2;
  transition: background .2s ease-in-out;
}

/* Più proprietà */
.card {
  transition: transform .2s, box-shadow .3s;
}

/* Anima tutto (attento alle prestazioni) */
.link { transition: all .2s; }
TimingEffetto
linearCostante
easeDefault
ease-inLento → veloce
ease-outVeloce → lento
ease-in-outLento ai lati
cubic-bezier(...)Personalizzata
steps(n)A scatti
Demo — hover con transizione
⚠
Anima transform e opacity

Sono le proprietà più performanti (gestite dalla GPU). width, height, margin, top/left causano reflow e sono più lente.

24Animazioni Intermedio

Le animazioni permettono di creare sequenze di trasformazioni nel tempo, controllate tramite @keyframes.

animation.css
@keyframes spin {
  from { transform: rotate(0); }
  to   { transform: rotate(360deg); }
}

.loader {
  width: 44px;
  height: 44px;
  border: 5px solid #E1E7F0;
  border-top-color: #2E6FF2;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}
.card { animation: fadeInUp .5s ease-out both; }
ProprietàValori
animation-namespin
animation-duration1s
animation-timing-functionlinear, ease
animation-delay.5s
animation-iteration-count1, infinite
animation-directionnormal, reverse, alternate
animation-fill-modenone, forwards, backwards, both
animation-play-staterunning, paused
Demo — spin e pulse
⚠
prefers-reduced-motion

Rispetta le preferenze degli utenti che soffrono di disturbi vestibolari.

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

25Variabili CSS Intermedio

Le variabili CSS (custom properties) permettono di riutilizzare valori in tutto il foglio di stile. Sono fondamentali per temi, palette colori e design system.

variabili.css
:root {
  --primary: #2E6FF2;
  --accent: #7C5CFC;
  --radius: 12px;
  --space: 1rem;
}

.btn {
  background: var(--primary);
  border-radius: var(--radius);
  padding: var(--space);
}

/* Fallback */
.box { color: var(--testo, black); }

/* Scope locale: sovrascrive --primary solo dentro .box-verde */
.box-verde { --primary: #2FAE66; }

25.1 Tema scuro con un solo blocco

Le variabili CSS rendono il tema scuro estremamente semplice: basta riassegnare i valori in un blocco.

tema.css
:root {
  --bg: #F7F9FC;
  --ink: #1B2733;
}

html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
}

body {
  background: var(--bg);
  color: var(--ink);
  transition: background .3s, color .3s;
}
✓
Design token

Usa variabili per colori, spaziature, radii, font. Cambiare un valore in un solo posto aggiornerà tutto il sito. È il principio dei "design token".

26Pseudo-classi avanzate Intermedio

Pseudo-classi moderne che risolvono problemi complessi in modo elegante.

Pseudo-classeDescrizioneEsempio
:is(...)Raggruppa selettori:is(h1, h2, h3) { color: red; }
:where(...)Come :is() ma specificità 0:where(ul, ol) { padding: 0; }
:has(...)Seleziona il genitore in base al figlio.card:has(img) { padding: 0; }
:not(...)Esclude elementip:not(.intro) { margin: 0; }
:focus-visibleFocus da tastierabutton:focus-visible { outline: 2px solid blue; }
:focus-withinGenitore con figlio a fuocofieldset:focus-within { border-color: blue; }
:checkedCheckbox/radio selezionatoinput:checked + label { font-weight: 700; }
:disabledElemento disabilitatobutton:disabled { opacity: .5; }
:requiredCampo obbligatorioinput:required { border-color: red; }
:valid / :invalidValidità campoinput:invalid { border-color: red; }
:emptyElemento vuotop:empty { display: none; }
:targetElemento bersaglio di un'ancora:target { background: yellow; }
pseudo.css
/* :is() — riduce ripetizione */
:is(article, section) :is(h1, h2) { color: #142850; }

/* :has() — selettore genitore (rivoluzionario) */
form:has(input:invalid) { border-color: red; }
.card:has(img) { padding: 0; }

/* :focus-visible — outline solo da tastiera */
button:focus-visible {
  outline: 3px solid #2E6FF2;
  outline-offset: 2px;
}

/* :focus-within — genitore con figlio a fuoco */
fieldset:focus-within {
  border-color: #2E6FF2;
  background: #E8F0FE;
}

27Pseudo-elementi avanzati Intermedio

Oltre a ::before e ::after, ci sono altri pseudo-elementi utili in situazioni specifiche.

27.1 ::selection

Stilizza il testo selezionato dall'utente.

Demo — ::selection (seleziona il testo)

Questo testo ha uno stile di selezione personalizzato: seleziona queste parole e vedrai il colore.

27.2 ::placeholder

placeholder.css
input::placeholder {
  color: #9dabc2;
  font-style: italic;
}

27.3 ::marker

marker.css
li::marker {
  color: #2E6FF2;
  font-size: 1.5em;
}

27.4 ::backdrop

Stilizza lo sfondo di un dialogo fullscreen (es. <dialog>).

backdrop.css
dialog::backdrop {
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(4px);
}

28Ombre e gradienti Intermedio

28.1 box-shadow

Sintassi: box-shadow: offset-x offset-y blur spread color inset;

base
colorata
inset
multipla

28.2 text-shadow

Sintassi: text-shadow: offset-x offset-y blur color;

Demo

Ombra base

Glow blu

Ombra retro multipla

28.3 Gradienti

gradient.css
/* Lineare */
.a { background: linear-gradient(#2E6FF2, #7C5CFC); }
.b { background: linear-gradient(135deg, #2E6FF2, #D6479B); }

/* Radiale */
.c { background: radial-gradient(circle, #2E6FF2, #7C5CFC); }

/* Conica */
.d { background: conic-gradient(#2E6FF2, #7C5CFC, #D6479B, #E8792E, #2E6FF2); }

/* Testo con gradiente */
.gradient-text {
  background: linear-gradient(90deg, #2E6FF2, #7C5CFC);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
Demo — gradienti
lineare verticale
diagonale
radiale
conico

29Trasformazioni Intermedio

Le trasformazioni modificano la posizione, la rotazione, la scala e l'inclinazione di un elemento, senza influire sul layout degli altri elementi.

FunzioneEffetto
translate(x, y)Sposta
translateX(x)Sposta orizzontalmente
translateY(y)Sposta verticalmente
rotate(deg)Ruota
scale(n)Scala
scaleX(n) / scaleY(n)Scala su un asse
skew(x, y)Inclina
matrix(...)Trasformazione combinata
Demo — trasformazioni
originale
rotate
scale
translate
skew
transform.css
.elemento {
  transform: translateX(20px) rotate(15deg) scale(1.1);
  transform-origin: top left; /* punto di origine */
}
⚠
transform non funziona su elementi inline

Su <span> o <a> serve display: inline-block o block.

★Esempi pratici · Intermedio

Tre componenti reali che combinano Flexbox, transizioni, variabili e responsive.

Esempio 1 — Card di pricing

Tre piani di prezzo affiancati, con piano evidenziato al centro.

pricing.css
.pricing {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  max-width: 1000px;
  margin: 3rem auto;
  padding: 0 1.5rem;
}

.plan {
  position: relative;
  background: #fff;
  border: 1px solid #E1E7F0;
  border-radius: 12px;
  padding: 2rem 1.5rem;
  text-align: center;
  transition: transform .2s, box-shadow .2s;
}
.plan:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 40px -20px rgba(0,0,0,.2);
}
.plan--featured {
  border-color: #2E6FF2;
  box-shadow: 0 20px 40px -20px rgba(46,111,242,.5);
  transform: scale(1.03);
}
.plan .badge {
  position: absolute;
  top: -12px; left: 50%; transform: translateX(-50%);
  background: #2E6FF2; color: #fff;
  font-size: .75rem; font-weight: 700;
  padding: .3rem .8rem; border-radius: 999px;
}
Risultato

Base

9€/mese

5 progetti · 1 GB

Consigliato

Pro

19€/mese

Illimitati · 50 GB

Business

49€/mese

Tutto · 500 GB

Esempio 2 — Toggle tema scuro

Bottone che cambia tema con variabili CSS e transition.

toggle.css
:root {
  --bg: #F7F9FC;
  --ink: #1B2733;
  --surface: #fff;
}
html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
  --surface: #152040;
}
body {
  background: var(--bg);
  color: var(--ink);
  transition: background .3s, color .3s;
}
toggle.js
const btn = document.getElementById('themeToggle');
const root = document.documentElement;
btn.addEventListener('click', () => {
  const current = root.getAttribute('data-theme') || 'light';
  root.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
});

Esempio 3 — Menu hamburger animato

Icona che diventa X quando il menu si apre, con transizione delle barre.

hamburger.css
.hamburger {
  width: 44px; height: 44px;
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  gap: 6px; background: none; border: none;
  cursor: pointer;
}
.hamburger span {
  display: block; width: 26px; height: 3px;
  background: #1B2733; border-radius: 2px;
  transition: transform .3s, opacity .3s;
}
.hamburger.open span:nth-child(1) {
  transform: translateY(9px) rotate(45deg);
}
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) {
  transform: translateY(-9px) rotate(-45deg);
}

★20 esercizi · Livello Intermedio

I1 · Flexbox

Navbar con logo e menu

Logo a sinistra, voci a destra, centrati.

Soluzione
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
I2 · Flexbox

Centra in tutta la pagina

Centra in sezione 100vh.

Soluzione
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
I3 · Flexbox

Card con footer in fondo

Footer sempre in fondo.

Soluzione
.card { display: flex; flex-direction: column; min-height: 250px; }
.card-body { flex: 1; }
I4 · Flexbox

Due colonne 30/70

Sidebar e main.

Soluzione
.layout { display: flex; gap: 1rem; }
.sidebar { flex: 3; }
.main { flex: 7; }
I5 · Responsive

Media query tablet

Padding body 1rem → 2rem sopra 768px.

Soluzione
@media (min-width: 768px) {
  body { padding: 2rem; }
}
I6 · Responsive

Immagine responsive

Mai più larga del contenitore.

Soluzione
img { max-width: 100%; height: auto; }
I7 · Transizioni

Bottone hover animato

Colore + sollevamento + ombra, 0.2s.

Soluzione
.btn { transition: all .2s; }
.btn:hover {
  background: #7C5CFC;
  transform: translateY(-3px);
  box-shadow: 0 10px 20px -8px #7C5CFC;
}
I8 · Animazioni

Cerchio pulsante

Scala + opacità in 1.4s infinito.

Soluzione
@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.2); opacity: .6; }
}
.pulse {
  width: 40px; height: 40px;
  background: #2FAE66; border-radius: 50%;
  animation: pulse 1.4s ease-in-out infinite;
}
I9 · Animazioni

Fade-in con ritardo

Card che entra con dissolvenza e movimento.

Soluzione
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}
.card { animation: fadeIn .5s ease-out both; }
I10 · Variabili

Palette custom properties

Definisci --primary e --bg.

Soluzione
:root {
  --primary: #2E6FF2;
  --bg: #F7F9FC;
}
body { background: var(--bg); }
.btn { background: var(--primary); }
I11 · Variabili

Tema scuro

Riassegna --bg e --ink in [data-theme="dark"].

Soluzione
html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
}
I12 · Pseudo-classi

:has() per form non valido

Bordo rosso se contiene input non valido.

Soluzione
form:has(input:invalid) {
  border: 2px solid #E2534D;
}
I13 · Pseudo-classi

:focus-visible

Outline solo da tastiera.

Soluzione
button:focus-visible {
  outline: 3px solid #2E6FF2;
  outline-offset: 2px;
}
I14 · Pseudo-elementi

Freccia link esterni

↗ su target="_blank".

Soluzione
a[target="_blank"]::after {
  content: " ↗";
}
I15 · Pseudo-elementi

Linea sotto h2

Linea decorativa sotto i titoli.

Soluzione
h2::after {
  content: "";
  display: block;
  width: 40px; height: 3px;
  background: #2E6FF2;
  margin-top: .5rem;
}
I16 · Ombre

Box-shadow card

Ombra morbida, più profonda al hover.

Soluzione
.card { box-shadow: 0 4px 12px rgba(0,0,0,.08); }
.card:hover { box-shadow: 0 20px 40px rgba(0,0,0,.15); }
I17 · Gradienti

Bottone con gradiente

Gradiente lineare blu-viola.

Soluzione
.btn {
  background: linear-gradient(135deg, #2E6FF2, #7C5CFC);
  color: #fff;
}
I18 · Gradienti

Testo con gradiente

Titolo con gradiente.

Soluzione
.gradient-text {
  background: linear-gradient(90deg, #2E6FF2, #7C5CFC);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
I19 · Trasformazioni

Card che si alza

translateY(-4px) al hover.

Soluzione
.card { transition: transform .2s; }
.card:hover { transform: translateY(-4px); }
I20 · Trasformazioni

Ruota icona

180° al hover.

Soluzione
.icon { transition: transform .3s; }
.icon:hover { transform: rotate(180deg); }

22Responsive design Intermedio

Il responsive design permette a una pagina di adattarsi a qualsiasi dimensione di schermo (smartphone, tablet, desktop). È una competenza fondamentale: oltre il 60% del traffico web arriva da mobile.

22.1 Meta viewport

Il meta viewport è fondamentale per il responsive. Senza di esso, il browser mobile simula una larghezza desktop (es. 980px) e rimpicciolisce tutto.

viewport.html
<meta name="viewport" content="width=device-width, initial-scale=1.0">

22.2 Media query

Le media query permettono di applicare CSS diverso in base alle caratteristiche del dispositivo (larghezza, orientamento, preferenze).

media.css
/* Mobile-first: parti dal piccolo e aggiungi */
.container { padding: 1rem; }

@media (min-width: 768px) {
  .container { padding: 2rem; }
}

@media (min-width: 1024px) {
  .container { max-width: 1080px; margin: 0 auto; }
}

/* Combinazioni */
@media (min-width: 768px) and (max-width: 1023px) { /* tablet */ }

/* Preferenze utente */
@media (prefers-color-scheme: dark) { /* tema scuro */ }
@media (prefers-reduced-motion: reduce) { /* disabilita animazioni */ }
@media (orientation: landscape) { /* schermo orizzontale */ }
@media (hover: hover) { /* dispositivo con mouse */ }
@media (pointer: coarse) { /* touch screen */ }
BreakpointDispositivo
< 480pxSmartphone verticale
480 – 767pxSmartphone orizzontale
768 – 1023pxTablet
1024 – 1439pxDesktop
≥ 1440pxDesktop grande

22.3 Immagini e testo responsive

responsive.css
img { max-width: 100%; height: auto; display: block; }
h1 { font-size: clamp(1.5rem, 5vw, 3rem); }

/* Immagini con art direction (browser moderni) */
<picture>
  <source media="(min-width: 768px)" srcset="grande.jpg">
  <img src="piccola.jpg" alt="...">
</picture>
✓
Mobile-first

Parti da mobile e aggiungi con min-width. Se funziona su mobile, funziona ovunque. Le media query con min-width sono più facili da gestire di quelle con max-width.

23Transizioni Intermedio

Le transizioni rendono fluido il passaggio da uno stato all'altro. Invece di un cambiamento istantaneo, l'animazione avviene gradualmente.

23.1 Proprietà

ProprietàEsempioCosa fa
transition-propertybackgroundCosa animare
transition-duration.3sDurata
transition-timing-functionease-in-outCurva temporale
transition-delay.1sRitardo
transitionShorthandTutto insieme
transition.css
/* transition: proprietà durata timing delay */
.btn {
  background: #2E6FF2;
  transition: background .2s ease-in-out;
}

/* Più proprietà */
.card {
  transition: transform .2s, box-shadow .3s;
}

/* Anima tutto (attento alle prestazioni) */
.link { transition: all .2s; }
TimingEffetto
linearCostante
easeDefault
ease-inLento → veloce
ease-outVeloce → lento
ease-in-outLento ai lati
cubic-bezier(...)Personalizzata
steps(n)A scatti
Demo — hover con transizione
⚠
Anima transform e opacity

Sono le proprietà più performanti (gestite dalla GPU). width, height, margin, top/left causano reflow e sono più lente.

24Animazioni Intermedio

Le animazioni permettono di creare sequenze di trasformazioni nel tempo, controllate tramite @keyframes.

animation.css
@keyframes spin {
  from { transform: rotate(0); }
  to   { transform: rotate(360deg); }
}

.loader {
  width: 44px;
  height: 44px;
  border: 5px solid #E1E7F0;
  border-top-color: #2E6FF2;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}
.card { animation: fadeInUp .5s ease-out both; }
ProprietàValori
animation-namespin
animation-duration1s
animation-timing-functionlinear, ease
animation-delay.5s
animation-iteration-count1, infinite
animation-directionnormal, reverse, alternate
animation-fill-modenone, forwards, backwards, both
animation-play-staterunning, paused
Demo — spin e pulse
⚠
prefers-reduced-motion

Rispetta le preferenze degli utenti che soffrono di disturbi vestibolari.

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

25Variabili CSS Intermedio

Le variabili CSS (custom properties) permettono di riutilizzare valori in tutto il foglio di stile. Sono fondamentali per temi, palette colori e design system.

variabili.css
:root {
  --primary: #2E6FF2;
  --accent: #7C5CFC;
  --radius: 12px;
  --space: 1rem;
}

.btn {
  background: var(--primary);
  border-radius: var(--radius);
  padding: var(--space);
}

/* Fallback */
.box { color: var(--testo, black); }

/* Scope locale: sovrascrive --primary solo dentro .box-verde */
.box-verde { --primary: #2FAE66; }

25.1 Tema scuro con un solo blocco

Le variabili CSS rendono il tema scuro estremamente semplice: basta riassegnare i valori in un blocco.

tema.css
:root {
  --bg: #F7F9FC;
  --ink: #1B2733;
}

html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
}

body {
  background: var(--bg);
  color: var(--ink);
  transition: background .3s, color .3s;
}
✓
Design token

Usa variabili per colori, spaziature, radii, font. Cambiare un valore in un solo posto aggiornerà tutto il sito. È il principio dei "design token".

26Pseudo-classi avanzate Intermedio

Pseudo-classi moderne che risolvono problemi complessi in modo elegante.

Pseudo-classeDescrizioneEsempio
:is(...)Raggruppa selettori:is(h1, h2, h3) { color: red; }
:where(...)Come :is() ma specificità 0:where(ul, ol) { padding: 0; }
:has(...)Seleziona il genitore in base al figlio.card:has(img) { padding: 0; }
:not(...)Esclude elementip:not(.intro) { margin: 0; }
:focus-visibleFocus da tastierabutton:focus-visible { outline: 2px solid blue; }
:focus-withinGenitore con figlio a fuocofieldset:focus-within { border-color: blue; }
:checkedCheckbox/radio selezionatoinput:checked + label { font-weight: 700; }
:disabledElemento disabilitatobutton:disabled { opacity: .5; }
:requiredCampo obbligatorioinput:required { border-color: red; }
:valid / :invalidValidità campoinput:invalid { border-color: red; }
:emptyElemento vuotop:empty { display: none; }
:targetElemento bersaglio di un'ancora:target { background: yellow; }
pseudo.css
/* :is() — riduce ripetizione */
:is(article, section) :is(h1, h2) { color: #142850; }

/* :has() — selettore genitore (rivoluzionario) */
form:has(input:invalid) { border-color: red; }
.card:has(img) { padding: 0; }

/* :focus-visible — outline solo da tastiera */
button:focus-visible {
  outline: 3px solid #2E6FF2;
  outline-offset: 2px;
}

/* :focus-within — genitore con figlio a fuoco */
fieldset:focus-within {
  border-color: #2E6FF2;
  background: #E8F0FE;
}

27Pseudo-elementi avanzati Intermedio

Oltre a ::before e ::after, ci sono altri pseudo-elementi utili in situazioni specifiche.

27.1 ::selection

Stilizza il testo selezionato dall'utente.

Demo — ::selection (seleziona il testo)

Questo testo ha uno stile di selezione personalizzato: seleziona queste parole e vedrai il colore.

27.2 ::placeholder

placeholder.css
input::placeholder {
  color: #9dabc2;
  font-style: italic;
}

27.3 ::marker

marker.css
li::marker {
  color: #2E6FF2;
  font-size: 1.5em;
}

27.4 ::backdrop

Stilizza lo sfondo di un dialogo fullscreen (es. <dialog>).

backdrop.css
dialog::backdrop {
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(4px);
}

28Ombre e gradienti Intermedio

28.1 box-shadow

Sintassi: box-shadow: offset-x offset-y blur spread color inset;

base
colorata
inset
multipla

28.2 text-shadow

Sintassi: text-shadow: offset-x offset-y blur color;

Demo

Ombra base

Glow blu

Ombra retro multipla

28.3 Gradienti

gradient.css
/* Lineare */
.a { background: linear-gradient(#2E6FF2, #7C5CFC); }
.b { background: linear-gradient(135deg, #2E6FF2, #D6479B); }

/* Radiale */
.c { background: radial-gradient(circle, #2E6FF2, #7C5CFC); }

/* Conica */
.d { background: conic-gradient(#2E6FF2, #7C5CFC, #D6479B, #E8792E, #2E6FF2); }

/* Testo con gradiente */
.gradient-text {
  background: linear-gradient(90deg, #2E6FF2, #7C5CFC);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
Demo — gradienti
lineare verticale
diagonale
radiale
conico

29Trasformazioni Intermedio

Le trasformazioni modificano la posizione, la rotazione, la scala e l'inclinazione di un elemento, senza influire sul layout degli altri elementi.

FunzioneEffetto
translate(x, y)Sposta
translateX(x)Sposta orizzontalmente
translateY(y)Sposta verticalmente
rotate(deg)Ruota
scale(n)Scala
scaleX(n) / scaleY(n)Scala su un asse
skew(x, y)Inclina
matrix(...)Trasformazione combinata
Demo — trasformazioni
originale
rotate
scale
translate
skew
transform.css
.elemento {
  transform: translateX(20px) rotate(15deg) scale(1.1);
  transform-origin: top left; /* punto di origine */
}
⚠
transform non funziona su elementi inline

Su <span> o <a> serve display: inline-block o block.

★Esempi pratici · Intermedio

Tre componenti reali che combinano Flexbox, transizioni, variabili e responsive.

Esempio 1 — Card di pricing

Tre piani di prezzo affiancati, con piano evidenziato al centro.

pricing.css
.pricing {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  max-width: 1000px;
  margin: 3rem auto;
  padding: 0 1.5rem;
}

.plan {
  position: relative;
  background: #fff;
  border: 1px solid #E1E7F0;
  border-radius: 12px;
  padding: 2rem 1.5rem;
  text-align: center;
  transition: transform .2s, box-shadow .2s;
}
.plan:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 40px -20px rgba(0,0,0,.2);
}
.plan--featured {
  border-color: #2E6FF2;
  box-shadow: 0 20px 40px -20px rgba(46,111,242,.5);
  transform: scale(1.03);
}
.plan .badge {
  position: absolute;
  top: -12px; left: 50%; transform: translateX(-50%);
  background: #2E6FF2; color: #fff;
  font-size: .75rem; font-weight: 700;
  padding: .3rem .8rem; border-radius: 999px;
}
Risultato

Base

9€/mese

5 progetti · 1 GB

Consigliato

Pro

19€/mese

Illimitati · 50 GB

Business

49€/mese

Tutto · 500 GB

Esempio 2 — Toggle tema scuro

Bottone che cambia tema con variabili CSS e transition.

toggle.css
:root {
  --bg: #F7F9FC;
  --ink: #1B2733;
  --surface: #fff;
}
html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
  --surface: #152040;
}
body {
  background: var(--bg);
  color: var(--ink);
  transition: background .3s, color .3s;
}
toggle.js
const btn = document.getElementById('themeToggle');
const root = document.documentElement;
btn.addEventListener('click', () => {
  const current = root.getAttribute('data-theme') || 'light';
  root.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
});

Esempio 3 — Menu hamburger animato

Icona che diventa X quando il menu si apre, con transizione delle barre.

hamburger.css
.hamburger {
  width: 44px; height: 44px;
  display: flex; flex-direction: column;
  justify-content: center; align-items: center;
  gap: 6px; background: none; border: none;
  cursor: pointer;
}
.hamburger span {
  display: block; width: 26px; height: 3px;
  background: #1B2733; border-radius: 2px;
  transition: transform .3s, opacity .3s;
}
.hamburger.open span:nth-child(1) {
  transform: translateY(9px) rotate(45deg);
}
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) {
  transform: translateY(-9px) rotate(-45deg);
}

★20 esercizi · Livello Intermedio

I1 · Flexbox

Navbar con logo e menu

Logo a sinistra, voci a destra, centrati.

Soluzione
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
I2 · Flexbox

Centra in tutta la pagina

Centra in sezione 100vh.

Soluzione
.hero {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
I3 · Flexbox

Card con footer in fondo

Footer sempre in fondo.

Soluzione
.card { display: flex; flex-direction: column; min-height: 250px; }
.card-body { flex: 1; }
I4 · Flexbox

Due colonne 30/70

Sidebar e main.

Soluzione
.layout { display: flex; gap: 1rem; }
.sidebar { flex: 3; }
.main { flex: 7; }
I5 · Responsive

Media query tablet

Padding body 1rem → 2rem sopra 768px.

Soluzione
@media (min-width: 768px) {
  body { padding: 2rem; }
}
I6 · Responsive

Immagine responsive

Mai più larga del contenitore.

Soluzione
img { max-width: 100%; height: auto; }
I7 · Transizioni

Bottone hover animato

Colore + sollevamento + ombra, 0.2s.

Soluzione
.btn { transition: all .2s; }
.btn:hover {
  background: #7C5CFC;
  transform: translateY(-3px);
  box-shadow: 0 10px 20px -8px #7C5CFC;
}
I8 · Animazioni

Cerchio pulsante

Scala + opacità in 1.4s infinito.

Soluzione
@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.2); opacity: .6; }
}
.pulse {
  width: 40px; height: 40px;
  background: #2FAE66; border-radius: 50%;
  animation: pulse 1.4s ease-in-out infinite;
}
I9 · Animazioni

Fade-in con ritardo

Card che entra con dissolvenza e movimento.

Soluzione
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}
.card { animation: fadeIn .5s ease-out both; }
I10 · Variabili

Palette custom properties

Definisci --primary e --bg.

Soluzione
:root {
  --primary: #2E6FF2;
  --bg: #F7F9FC;
}
body { background: var(--bg); }
.btn { background: var(--primary); }
I11 · Variabili

Tema scuro

Riassegna --bg e --ink in [data-theme="dark"].

Soluzione
html[data-theme="dark"] {
  --bg: #0a1428;
  --ink: #e6ecf5;
}
I12 · Pseudo-classi

:has() per form non valido

Bordo rosso se contiene input non valido.

Soluzione
form:has(input:invalid) {
  border: 2px solid #E2534D;
}
I13 · Pseudo-classi

:focus-visible

Outline solo da tastiera.

Soluzione
button:focus-visible {
  outline: 3px solid #2E6FF2;
  outline-offset: 2px;
}
I14 · Pseudo-elementi

Freccia link esterni

↗ su target="_blank".

Soluzione
a[target="_blank"]::after {
  content: " ↗";
}
I15 · Pseudo-elementi

Linea sotto h2

Linea decorativa sotto i titoli.

Soluzione
h2::after {
  content: "";
  display: block;
  width: 40px; height: 3px;
  background: #2E6FF2;
  margin-top: .5rem;
}
I16 · Ombre

Box-shadow card

Ombra morbida, più profonda al hover.

Soluzione
.card { box-shadow: 0 4px 12px rgba(0,0,0,.08); }
.card:hover { box-shadow: 0 20px 40px rgba(0,0,0,.15); }
I17 · Gradienti

Bottone con gradiente

Gradiente lineare blu-viola.

Soluzione
.btn {
  background: linear-gradient(135deg, #2E6FF2, #7C5CFC);
  color: #fff;
}
I18 · Gradienti

Testo con gradiente

Titolo con gradiente.

Soluzione
.gradient-text {
  background: linear-gradient(90deg, #2E6FF2, #7C5CFC);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
I19 · Trasformazioni

Card che si alza

translateY(-4px) al hover.

Soluzione
.card { transition: transform .2s; }
.card:hover { transform: translateY(-4px); }
I20 · Trasformazioni

Ruota icona

180° al hover.

Soluzione
.icon { transition: transform .3s; }
.icon:hover { transform: rotate(180deg); }
Livello Avanzato

30CSS Grid Avanzato

CSS Grid è un sistema di layout bidimensionale: gestisce righe e colonne insieme. È lo strumento più potente per creare layout complessi come dashboard, gallerie fotografiche, pagine di riviste.

30.1 Proprietà principali

ProprietàValoriEffetto
displaygrid | inline-gridAttiva Grid
grid-template-columns1fr 1fr, repeat(3,1fr)Definisce le colonne
grid-template-rowsauto 1fr autoDefinisce le righe
gap1remSpazio tra celle
grid-columnspan 2, 1 / 3Occupazione colonne
grid-rowspan 2, 1 / 3Occupazione righe
grid-template-areasStringhe ASCIILayout nominati
justify-itemsstretch, center, start, endAllineamento orizzontale celle
align-itemsstretch, center, start, endAllineamento verticale celle

30.2 Griglia a 3 colonne

grid.css
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
Demo — 3 colonne uguali
1
2
3
4
5
6

30.3 Griglia asimmetrica

Demo — 1fr 2fr 1fr
1fr
2fr
1fr

30.4 Griglia responsive automatica

Il pattern più utile: auto-fill o auto-fit con minmax() crea una griglia che si adatta automaticamente alla larghezza disponibile.

auto-grid.css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1.2rem;
}

/* auto-fit: le colonne vuote collassano */
.cards-fit {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

30.5 Layout con grid-template-areas

Questo è il modo più leggibile per creare layout complessi. Ogni stringa rappresenta una riga, e i nomi definiscono le aree.

areas.css
.layout {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 260px 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
  min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
Demo — layout con aree
header
sidebar
main
✓
Grid vs Flexbox: quando usarli
  • Flexbox: layout monodimensionali (navbar, card, form, righe o colonne singole)
  • Grid: layout bidimensionali (pagine intere, gallerie, dashboard, righe E colonne)
  • Combinati: Grid per la struttura della pagina, Flexbox per i componenti interni

31Funzioni CSS Avanzato

31.1 calc(): calcoli dinamici

La funzione calc() permette di eseguire calcoli matematici mescolando unità diverse.

calc.css
.content { width: calc(100% - 250px); }
h1 { font-size: calc(1.5rem + 2vw); }
.modal { width: 600px; left: calc(50% - 300px); }

31.2 clamp(): minimo, preferito, massimo

clamp.css
h1 { font-size: clamp(1rem, 5vw, 2rem); }
.section { padding: clamp(1rem, 3vw, 3rem); }
.container { width: clamp(320px, 90%, 1200px); }
Demo — clamp() su titolo (ridimensiona la finestra)

Titolo fluido con clamp()

Questo titolo si adatta: mai meno di 1rem, mai più di 2.5rem.

31.3 min() e max()

minmax.css
.card { width: min(300px, 100%); }
.hero { padding: max(2rem, 5vw); }

31.4 var() con fallback

var.css
.btn { background: var(--primary, blue); }
.box { color: var(--custom, var(--primary, #000)); }

32Proprietà moderne Avanzato

32.1 aspect-ratio

Mantiene un rapporto fisso tra larghezza e altezza. Fondamentale per video, immagini, avatar.

aspect.css
.video { aspect-ratio: 16 / 9; width: 100%; }
.avatar { aspect-ratio: 1 / 1; width: 80px; border-radius: 50%; }
Demo — aspect-ratio: 16/9
16 / 9

32.2 object-fit

Controlla come un'immagine o un video si adatta al suo contenitore.

ValoreEffetto
fillDefault, stira
coverRiempie, ritaglia
containMostra tutto, con spazi
noneOriginale
scale-downIl minore tra none/contain

32.3 scroll-snap

Crea caroselli che si "agganciano" a posizioni precise durante lo scorrimento.

snap.css
.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 1rem;
}
.carousel > * {
  scroll-snap-align: center;
  flex-shrink: 0;
  width: 80%;
}
Demo — scroll-snap (scorri orizzontalmente)
Slide 1
Slide 2
Slide 3

32.4 backdrop-filter: l'effetto vetro

glass.css
.glass {
  background: rgba(255 255 255 / .15);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.3);
}

32.5 Container queries

Come le media query ma basate sulla dimensione del contenitore, non del viewport.

container.css
.card-wrapper {
  container-type: inline-size;
  container-name: card;
}
@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 120px 1fr;
  }
}

32.6 Proprietà logiche

logiche.css
.b {
  margin-inline-start: 1rem;
  padding-block-start: 2rem;
  margin-inline: 1rem 2rem;
  margin-block: 1rem;
  inset: 0;
}

33Prestazioni e ottimizzazione Avanzato

Non tutte le proprietà CSS sono uguali in termini di prestazioni. Alcune sono gestite dalla GPU (veloci), altre causano ricalcoli del layout (lente).

ProprietàCostoNote
transform, opacityBassoSolo GPU, molto veloce
color, background-colorMedioSolo repaint
width, height, marginAltoReflow completo
top, leftAltoReflow
✓
Anima transform e opacity

Preferisci transform: translateY(-5px) invece di margin-top: -5px. Il primo è gestito dalla GPU, il secondo causa un ricalcolo del layout.

33.1 Ottimizzazione web font

font-optimization.html
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="...family=Inter:wght@400;700&display=swap" rel="stylesheet">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

33.2 Contenuto fuori schermo

La proprietà content-visibility permette al browser di saltare il rendering delle sezioni non visibili.

visibility.css
.section-lunga {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

34Architettura CSS Avanzato

34.1 Naming: BEM

BEM (Block Element Modifier) è una convenzione di naming che rende il CSS più leggibile e manutenibile.

bem.css
/* Blocco */
.card { /* ... */ }

/* Elemento (doppio underscore) */
.card__title { /* ... */ }
.card__body { /* ... */ }

/* Modificatore (doppio trattino) */
.card--featured { /* ... */ }

34.2 Struttura file CSS

struttura.css
/* 1. RESET E VARIABILI */
/* 2. BASE (tipografia, body) */
/* 3. LAYOUT (container, grid pagina) */
/* 4. COMPONENTI (bottoni, card, form) */
/* 5. UTILITY (classi monouso) */
/* 6. MEDIA QUERY (mobile-first) */

34.3 Utility-first vs component-first

component

.card, .btn-primary, .navbar

HTML pulito, CSS più lungo. Es. Bootstrap, BEM.

utility

.p-4, .text-center, .bg-blue

HTML verboso, CSS corto. Es. Tailwind.

✓
Regole d'oro
  • Una responsabilità per classe
  • Specificità più bassa possibile
  • Evita !important e #id per lo stile
  • Commenta a blocchi
  • Variabili per colori, spazi, font

35Best practice Avanzato

Mobile-first

Parti dal piccolo e aggiungi con min-width.

Organizza il CSS

Sezioni con commenti.

Classi, non id

Riutilizzabili e specificità bassa.

Evita !important

Se serve, c'è un problema.

border-box

Sempre, su tutto.

Variabili

Un solo posto per i colori.

Accessibilità

Contrasto, focus, reduced-motion.

Commenta a blocchi

Non riga per riga.

Testa su mobile

320, 375, 768, 1280px.

★Esempi pratici · Avanzato

Esempio 1 — Dashboard con Grid

Layout completo con sidebar, topbar e area contenuti.

dashboard.css
.dashboard {
  display: grid;
  grid-template-areas:
    "sidebar topbar"
    "sidebar content";
  grid-template-columns: 240px 1fr;
  grid-template-rows: 60px 1fr;
  min-height: 100vh;
  gap: 1rem;
  padding: 1rem;
  background: #F7F9FC;
}

.sidebar { grid-area: sidebar; background: #142850; border-radius: 12px; padding: 1.5rem; color: #fff; }
.topbar { grid-area: topbar; background: #fff; border-radius: 12px; padding: 1rem 1.5rem; display: flex; justify-content: space-between; align-items: center; }
.content { grid-area: content; background: #fff; border-radius: 12px; padding: 1.5rem; }

@media (max-width: 768px) {
  .dashboard {
    grid-template-areas:
      "topbar"
      "content"
      "sidebar";
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
  }
}

Esempio 2 — Galleria portfolio

Griglia fotografica con pattern masonry semplificato.

gallery.css
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-auto-rows: 200px;
  gap: 1rem;
}

/* Alcuni item occupano 2 righe */
.gallery > :nth-child(3n) { grid-row: span 2; }
.gallery > :nth-child(5n) { grid-column: span 2; }

.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 8px;
  transition: transform .3s;
}
.gallery img:hover { transform: scale(1.05); }

Esempio 3 — Card con container query

Card che cambia layout in base alla larghezza del contenitore.

container-card.css
.card-wrapper {
  container-type: inline-size;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.2rem;
  background: #fff;
  border-radius: 12px;
  border: 1px solid #E1E7F0;
}

@container (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: center;
  }
  .card img { width: 120px; height: 120px; }
}

★20 esercizi · Livello Avanzato

A1 · Grid

3 colonne uguali

Grid con 3 colonne e gap 1rem.

Soluzione
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
A2 · Grid

Griglia responsive automatica

Min 250px per card.

Soluzione
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1rem;
}
A3 · Grid

Item largo 2 colonne

Primo elemento span 2.

Soluzione
.grid { grid-template-columns: repeat(3, 1fr); }
.grid > :first-child { grid-column: span 2; }
A4 · Grid

Layout con aree

Header, sidebar, main, footer.

Soluzione
.layout {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 200px 1fr;
}
A5 · Grid

Layout pagina intera

Main che si allarga.

Soluzione
.page {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}
A6 · Funzioni

calc() per larghezza

100% meno 250px.

Soluzione
.content { width: calc(100% - 250px); }
A7 · Funzioni

Titolo fluido

Font tra 2rem e 4rem.

Soluzione
h1 { font-size: clamp(2rem, 5vw, 4rem); }
A8 · Funzioni

Padding fluido

1rem → 3rem.

Soluzione
.section { padding: clamp(1rem, 3vw, 3rem); }
A9 · Moderne

Video 16:9

Rapporto aspetto.

Soluzione
.video { aspect-ratio: 16 / 9; width: 100%; }
A10 · Moderne

Avatar con object-fit

Immagine senza distorsioni.

Soluzione
.avatar {
  width: 80px; height: 80px;
  border-radius: 50%;
  object-fit: cover;
}
A11 · Moderne

Scroll-snap orizzontale

Carousel che si aggancia.

Soluzione
.carousel {
  display: flex; overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.carousel > * {
  scroll-snap-align: center;
  flex-shrink: 0;
}
A12 · Moderne

Container query

Card che cambia layout se contenitore > 400px.

Soluzione
.wrapper { container-type: inline-size; }
@container (min-width: 400px) {
  .card { display: grid; grid-template-columns: 120px 1fr; }
}
A13 · Moderne

Proprietà logiche

margin-inline e padding-block.

Soluzione
.box {
  margin-inline: 1rem;
  padding-block: 2rem;
}
A14 · Moderne

Effetto vetro

backdrop-filter blur.

Soluzione
.glass {
  background: rgba(255 255 255 / .15);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.3);
}
A15 · Prestazioni

content-visibility

Saltare rendering fuori schermo.

Soluzione
.section-lunga {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}
A16 · Prestazioni

Anima con transform

Sollevamento senza margin.

Soluzione
.card { transition: transform .2s; }
.card:hover { transform: translateY(-4px); }
A17 · Architettura

Naming BEM

Riscrivi in BEM: .card-title, .card-featured.

Soluzione
.card__title { /* ... */ }
.card--featured { /* ... */ }
A18 · Architettura

Design token

Variabili per spaziature e radius.

Soluzione
:root {
  --space-sm: .5rem;
  --space-md: 1rem;
  --space-lg: 2rem;
  --radius-sm: 6px;
  --radius-md: 12px;
}
A19 · Layout

Dashboard Grid

Sidebar + topbar + contenuto.

Soluzione
.dashboard {
  display: grid;
  grid-template-areas:
    "sidebar topbar"
    "sidebar content";
  grid-template-columns: 240px 1fr;
  grid-template-rows: 60px 1fr;
  min-height: 100vh;
}
A20 · Layout

Galleria masonry

Grid con item che occupano più righe.

Soluzione
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  grid-auto-rows: 180px;
  gap: .8rem;
}
.gallery > :nth-child(3n) { grid-row: span 2; }

36Progetto finale

Costruisci un sito portfolio personale responsive con tema chiaro/scuro. Perfetto per l'esame di stato.

i
Obiettivi didattici
  • Layout con CSS Grid (header / main / footer)
  • Componenti con Flexbox (navbar, card, form)
  • Variabili CSS per tema chiaro/scuro
  • Responsive mobile-first
  • Transizioni e animazioni di ingresso
  • Accessibilità: contrasto, focus, prefers-reduced-motion

Requisiti

  • Header: nome + navbar con 3 link, sticky in alto
  • Hero: titolo gradiente, sottotitolo, bottone CTA
  • Sezione "Progetti": griglia responsive di card
  • Sezione "Contatti": form con nome, email, messaggio
  • Footer: copyright centrato
  • Tema scuro: bottone toggle
  • Responsive: da 320px in su

Struttura file

struttura.txt
portfolio/
├── index.html
├── css/
│   └── style.css
└── img/

Soluzione HTML

index.html
<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Portfolio — Mario Rossi</title>
  <link rel="stylesheet" href="css/style.css">
</head>
<body>
  <header class="site-header">
    <a href="#" class="logo">Mario Rossi</a>
    <nav>
      <a href="#progetti">Progetti</a>
      <a href="#contatti">Contatti</a>
      <button id="themeToggle" type="button" aria-label="Cambia tema">🌓</button>
    </nav>
  </header>

  <section class="hero">
    <h1>Ciao, sono <span class="accent">Mario</span></h1>
    <p>Studente di informatica, appassionato di sviluppo web.</p>
    <a href="#progetti" class="btn">Vedi i miei progetti</a>
  </section>

  <main>
    <section id="progetti">
      <h2>Progetti</h2>
      <div class="cards">
        <article class="card">
          <h3>To-do list</h3>
          <p>App per gestire attività con localStorage.</p>
        </article>
        <article class="card">
          <h3>Meteo API</h3>
          <p>Ricerca meteo per città con API REST.</p>
        </article>
        <article class="card">
          <h3>Quiz interattivo</h3>
          <p>Quiz a risposta multipla con punteggio.</p>
        </article>
      </div>
    </section>

    <section id="contatti">
      <h2>Contattami</h2>
      <form class="contact-form">
        <label for="nome">Nome</label>
        <input type="text" id="nome" required>
        <label for="email">Email</label>
        <input type="email" id="email" required>
        <label for="msg">Messaggio</label>
        <textarea id="msg" rows="5" required></textarea>
        <button type="submit" class="btn">Invia</button>
      </form>
    </section>
  </main>

  <footer class="site-footer">
    <p>© 2026 Mario Rossi</p>
  </footer>

  <script>
    const btn = document.getElementById('themeToggle');
    const root = document.documentElement;
    btn.addEventListener('click', () => {
      const current = root.getAttribute('data-theme') || 'light';
      root.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
    });
  </script>
</body>
</html>

Soluzione CSS

css/style.css
/* ============================================================
   1. RESET E VARIABILI
   ============================================================ */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --bg: #F7F9FC;
  --surface: #FFFFFF;
  --ink: #1B2733;
  --ink-soft: #566072;
  --primary: #2E6FF2;
  --accent: #7C5CFC;
  --border: #E1E7F0;
  --radius: 12px;
  --max: 1080px;
}

html[data-theme="dark"] {
  --bg: #0a1428;
  --surface: #152040;
  --ink: #e6ecf5;
  --ink-soft: #9dabc2;
  --border: #253557;
}

/* ============================================================
   2. BASE
   ============================================================ */
body {
  font-family: system-ui, -apple-system, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.6;
  transition: background .2s, color .2s;
}

h1, h2, h3 { line-height: 1.2; }
a { color: var(--primary); text-decoration: none; }

/* ============================================================
   3. LAYOUT
   ============================================================ */
.site-header, main, .site-footer, .hero {
  max-width: var(--max);
  margin: 0 auto;
  padding: 1rem 1.5rem;
}

/* ============================================================
   4. HEADER
   ============================================================ */
.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: sticky;
  top: 0;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  z-index: 100;
}

.site-header nav {
  display: flex;
  gap: 1.2rem;
  align-items: center;
}

.logo {
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--ink);
}

/* ============================================================
   5. HERO
   ============================================================ */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  min-height: 60vh;
  gap: 1.2rem;
}

.hero h1 { font-size: clamp(2rem, 5vw, 3rem); }
.accent {
  background: linear-gradient(90deg, var(--primary), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ============================================================
   6. BOTTONE
   ============================================================ */
.btn {
  display: inline-block;
  background: var(--primary);
  color: #fff;
  padding: .75rem 1.4rem;
  border: none;
  border-radius: var(--radius);
  font-weight: 600;
  cursor: pointer;
  transition: transform .15s, background .15s, box-shadow .15s;
}

.btn:hover {
  background: var(--accent);
  transform: translateY(-2px);
  box-shadow: 0 10px 20px -8px var(--accent);
}

/* ============================================================
   7. CARDS
   ============================================================ */
main section { padding: 3rem 1.5rem; }
main h2 { font-size: 1.8rem; margin-bottom: 1.5rem; }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.2rem;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.5rem;
  transition: transform .2s, box-shadow .2s, border-color .2s;
}

.card:hover {
  transform: translateY(-4px);
  border-color: var(--primary);
  box-shadow: 0 15px 30px -15px rgba(46,111,242,.4);
}

.card h3 { margin-bottom: .5rem; }
.card p { color: var(--ink-soft); }

/* ============================================================
   8. FORM
   ============================================================ */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-width: 520px;
}

.contact-form label {
  font-weight: 600;
  font-size: .9rem;
  margin-top: .5rem;
}

.contact-form input,
.contact-form textarea {
  padding: .7rem .9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  font-size: 1rem;
  background: var(--surface);
  color: var(--ink);
  transition: border-color .15s, box-shadow .15s;
}

.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(46,111,242,.2);
}

.contact-form button { align-self: flex-start; margin-top: 1rem; }

/* ============================================================
   9. FOOTER
   ============================================================ */
.site-footer {
  text-align: center;
  padding: 2rem 1.5rem;
  color: var(--ink-soft);
  font-size: .85rem;
  border-top: 1px solid var(--border);
}

/* ============================================================
   10. RESPONSIVE
   ============================================================ */
@media (min-width: 768px) {
  .hero h1 { font-size: 3.5rem; }
  main section { padding: 4rem 2rem; }
}

/* ============================================================
   11. ACCESSIBILITÀ
   ============================================================ */
:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
✓
Estensioni possibili
  • Animazione ingresso card con animation-delay progressivo
  • Menu mobile con hamburger
  • Barra progresso scroll con position: fixed
  • Tema salvato in localStorage
  • Sezione Skills con barre animate