Guida completa alle ombre CSS: box-shadow, drop-shadow e text-shadow spiegati

Padroneggia tutte e tre le tecniche di ombra CSS — sintassi, parametri, differenze di rendering, pattern reali e implicazioni sulle performance.

~15 min di lettura Feb 2025

Le ombre sono tra gli strumenti più semplici in CSS, eppure la maggior parte dei tutorial le tratta solo in superficie. Questa guida analizza in profondità tutti e tre i meccanismi — sintassi, parametri, differenze di rendering, casi d'uso reali e implicazioni sulle performance — così puoi scegliere sempre la tecnica giusta.

Perché CSS ha tre proprietà per le ombre?

Ogni meccanismo di ombra esiste per risolvere un problema diverso. Sono emersi in momenti diversi della storia di CSS e si rivolgono a target di rendering fondamentalmente differenti:

  • box-shadow — ombre per box rettangolari (il box model CSS). Disponibile da CSS 2.1, standardizzato in CSS3.
  • filter: drop-shadow() — ombre che seguono la forma visibile reale dell'elemento, inclusa la trasparenza. Parte della specifica CSS Filter Effects Level 1.
  • text-shadow — ombre applicate direttamente ai contorni dei glifi. Tecnicamente la più antica delle tre, introdotta in CSS 2, temporaneamente rimossa, poi ri-standardizzata in CSS3.

La confusione nasce perché tutte e tre producono ciò che l'occhio umano percepisce come "un'ombra", ma il motore di rendering le gestisce in fasi completamente diverse della pipeline di pittura.

⚡ Regola pratica

Usa box-shadow per elementi UI con sfondi solidi. Usa drop-shadow per PNG, SVG o qualsiasi cosa con trasparenza. Usa text-shadow esclusivamente sul testo.

box-shadow: il cavallo di battaglia

Disegna una o più ombre dietro (o dentro) il border box di un elemento — la proprietà ombra più versatile e utilizzata.

Sintassi

box-shadow: [inset] offset-x offset-y [blur-radius] [spread-radius] color;

Ogni valore svolge esattamente un compito:

Parametro Default Cosa controlla
insetomesso (esterno)Disegna l'ombra dentro l'elemento invece che dietro
offset-xobbligatorioDistanza orizzontale. Positivo = destra, negativo = sinistra
offset-yobbligatorioDistanza verticale. Positivo = basso, negativo = alto
blur-radius0Quantità di sfocatura gaussiana. Più alto = più morbido e diffuso
spread-radius0Espande (+) o contrae (–) l'ombra prima della sfocatura
colorcurrentColorColore dell'ombra — usa sempre rgba() o hsla() per realismo

Lo spread radius: il parametro sottoutilizzato

La maggior parte degli sviluppatori usa offset + blur e si ferma lì. Lo spread radius sblocca una classe di effetti completamente diversa. Con spread: 0 e blur: 0 diventa un bordo CSS perfetto e componibile che non influenza il layout:

/* Layered outline rings — no layout impact */
box-shadow:
  0 0 0 4px rgba(201,184,154,.4),
  0 0 0 8px rgba(201,184,154,.1);

Con uno spread negativo puoi trasformare un'ombra sfocata in una direzionale che appare solo sotto l'elemento:

/* Shadow only at the bottom — more realistic */
box-shadow: 0 12px 24px -8px rgba(0,0,0,.6);

Esempi live

4px 4px 8px rgba(0,0,0,.7)
0 0 0 4px accent
inset 0 4px 12px
0 2px 4px + 0 8px 24px + ring
0 0 24px + 0 0 48px
light + dark inset pair
backdrop-blur + shadow

Ombre multiple: l'ordine conta

Puoi impilare un numero illimitato di ombre con una lista separata da virgole. Il rendering avviene dall'avanti all'indietro — la prima ombra della lista è sopra. Questo permette di stratificare ombre ambientali e direzionali per una profondità naturale sia in modalità chiara che scura.

/* Three-layer system used in serious design systems */
box-shadow:
  0 1px 2px rgba(0,0,0,.3),    /* close shadow: sharp, small */
  0 4px 16px rgba(0,0,0,.25),  /* mid shadow: soft ambient */
  0 0 0 1px rgba(255,255,255,.05); /* subtle highlight ring */

Ombre inset: profondità e stati premuti

La parola chiave inset sposta l'ombra all'interno del bordo dell'elemento. La direzione dell'offset si inverte intuitivamente: un offset Y positivo posiziona l'ombra lungo il bordo interno superiore, come se la luce venisse dall'alto. Essenziale per pulsanti premuti, input testuali in rilievo e neumorfismo:

/* Input focus state — depth without a visible border */
input:focus {
  box-shadow:
    inset 0 2px 6px rgba(0,0,0,.5),
    0 0 0 2px rgba(201,184,154,.4);
}
Tool gratuito Generatore Box Shadow Regola tutti i parametri e copia il CSS pronto per la produzione

filter: drop-shadow() — ombre che seguono la forma

filter: drop-shadow() non è una proprietà — è una funzione CSS filter. I filtri vengono applicati dopo la pittura, operando sui pixel renderizzati finali di un elemento e dei suoi discendenti. Questa distinzione ha due conseguenze importanti:

  • L'ombra segue il contorno visibile reale, rispettando la trasparenza alpha nei PNG e la forma dei percorsi SVG.
  • Il filtro influenza l'intero sottoalbero, inclusi i figli. Questo significa che funziona automaticamente su gruppi di elementi.

Sintassi

filter: drop-shadow(offset-x offset-y blur-radius color);

Nota: nessun spread-radius e nessuna parola chiave inset. La specifica li ha deliberatamente omessi. Se hai bisogno di spread su un'ombra che segue la forma, combina due chiamate drop-shadow() con raggi di sfocatura diversi.

Dove box-shadow fallisce e drop-shadow eccelle

Immagina un logo PNG trasparente su uno sfondo colorato. Applica box-shadow e otterrai un'ombra rettangolare attorno al bounding box invisibile — l'ombra sconfina nelle aree trasparenti. Applica drop-shadow() e l'ombra abbraccia la forma visibile reale del logo.

La stessa logica si applica a:

  • Elementi SVG — percorsi, poligoni, forme composite
  • CSS clip-path — l'ombra segue il confine del clip
  • Elementi ruotati o trasformati — l'ombra segue correttamente la forma post-trasformazione
  • Gruppi di componenti — un filtro sul parent ombreggia tutti i figli come unità
/* SVG icon with proper shadow */
.icon-wrapper {
  filter: drop-shadow(0 4px 8px rgba(0,0,0,.6));
}

/* PNG logo — shadow follows logo shape, not its bounding box */
.logo {
  filter: drop-shadow(2px 4px 12px rgba(0,0,0,.5));
}

/* Stacked for a glow effect on an irregular shape */
.neon-svg {
  filter:
    drop-shadow(0 0 6px rgba(201,184,154,.8))
    drop-shadow(0 0 20px rgba(201,184,154,.4));
}

Il compromesso chiave: il contesto di impilamento

Applicare filter crea un nuovo contesto di impilamento e un nuovo layer di compositing. Di solito va bene, ma significa che l'elemento non può più sovrapporsi correttamente ad altri layer di compositing — il che causa occasionalmente problemi di z-index. Se lo incontri, valuta se box-shadow può approssimare l'effetto.

Tool gratuito Generatore Filtri CSS Combina drop-shadow con blur, luminosità e saturazione — anteprima live

text-shadow: profondità tipografica

text-shadow viene applicato esclusivamente ai contorni dei glifi del testo — non al box dell'elemento. Viene disegnato nella stessa fase del testo, dietro i glifi, rendendolo la scelta giusta quando si vuole profondità o leggibilità su elementi tipografici.

Sintassi

text-shadow: offset-x offset-y [blur-radius] color;

Rispetto a box-shadow, non ci sono spread-radiusinset. Le ombre multiple sono separate da virgole, con lo stesso ordine dall'avanti all'indietro.

Esempi live

Heading
2px 2px 4px rgba(0,0,0,.8)
Neon
0 0 10px + 0 0 30px
Emboss
light + dark offset pair
Retro
hard double offset

Casi d'uso comuni

Leggibilità su immagini: Una sottile text-shadow: 0 1px 3px rgba(0,0,0,.6) rende il testo bianco leggibile su fotografie luminose senza necessità di un overlay scuro.

Tipografia neon/glow: Impila due ombre con offset zero e raggi di sfocatura crescenti. L'ombra interna crea il nucleo intenso, quella esterna crea il bagliore atmosferico:

.neon {
  color: #c9b89a;
  text-shadow:
    0 0 8px rgba(201,184,154,.9),
    0 0 24px rgba(201,184,154,.5),
    0 0 60px rgba(201,184,154,.2);
}

Letterpress / in rilievo: Combina un'ombra chiara in alto a sinistra con una scura in basso a destra. La direzione determina se il testo appare in rilievo o in incasso:

/* Raised (light = up-left, dark = down-right) */
text-shadow: -1px -1px 0 rgba(255,255,255,.15), 1px 1px 0 rgba(0,0,0,.6);

/* Recessed (reversed) */
text-shadow:  1px  1px 0 rgba(255,255,255,.1), -1px -1px 0 rgba(0,0,0,.5);

Hard drop shadow (stile retro/fumetto): Zero blur, offset maggiore, ombre hard impilate:

.retro {
  text-shadow: 3px 3px 0 #7a5c38, 6px 6px 0 rgba(0,0,0,.25);
}
Tool gratuito Generatore Text Shadow Crea ed esporta effetti text-shadow con anteprima in tempo reale

Confronto affiancato

Caratteristicabox-shadowdrop-shadow()text-shadow
TargetBox model elementoForma pixel renderizzataContorni glifi testo
Rispetta trasparenzaNo — ignora alphaSì — segue la formaN/A (solo testo)
spread-radiusNoNo
Parola chiave insetNoNo
Layer multipliSì, separati da virgolaSì, funzioni concatenateSì, separati da virgola
Contesto di impilamentoNessun nuovo contestoCrea nuovo contestoNessun nuovo contesto
Si applica ai figliNoSì (intero sottoalbero)No
Funziona su forme SVGSolo bounding boxSì, per percorsoN/A
Animazione CSSAnimabileAnimabileAnimabile
Compositing GPUSpesso, su layer promossiSì, sempreRaramente

La domanda che determina quale usare

Chiediti: l'elemento ha uno sfondo rettangolare e opaco? Se sì, usa box-shadow — è più semplice da ragionare e non ha effetti collaterali sul contesto di impilamento. Se no (PNG trasparente, SVG, forma irregolare, clip-path), usa drop-shadow(). Se il target è il testo, usa text-shadow.

Ricette e pattern per la produzione

Sistema di elevazione (stile Material)

Invece di hardcodare i valori delle ombre in tutto il codebase, definisci una scala di elevazione come proprietà CSS personalizzate. Questo rende la profondità globale coerente e facile da aggiornare:

:root {
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 2px 6px rgba(0,0,0,.35), 0 1px 2px rgba(0,0,0,.3);
  --shadow-3: 0 4px 16px rgba(0,0,0,.3), 0 2px 4px rgba(0,0,0,.3);
  --shadow-4: 0 8px 32px rgba(0,0,0,.28), 0 4px 8px rgba(0,0,0,.25);
  --shadow-5: 0 16px 48px rgba(0,0,0,.25), 0 8px 16px rgba(0,0,0,.2);
}

.card      { box-shadow: var(--shadow-2); }
.card:hover { box-shadow: var(--shadow-4); transition: box-shadow .2s ease; }
.modal     { box-shadow: var(--shadow-5); }

Ombre colorate

Una delle tecniche più sottoutilizzate: invece di ombre nere, tinta l'ombra con il colore dominante dell'elemento. Si integra meglio nei temi chiari e scuri e crea una qualità simile al glow senza risultare aggressiva:

/* Button with colored shadow matching brand color */
.btn-primary {
  background: #c9b89a;
  box-shadow: 0 4px 20px rgba(201,184,154,.4), 0 2px 6px rgba(201,184,154,.3);
}
.btn-primary:hover {
  box-shadow: 0 6px 28px rgba(201,184,154,.55), 0 3px 8px rgba(201,184,154,.4);
}

Glassmorfismo con ombra

Il glassmorfismo richiede un interplay calibrato tra backdrop-filter, sfondo traslucido, bordo semi-trasparente e box-shadow per separare la card dallo sfondo:

.glass-card {
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  box-shadow:
    0 8px 32px rgba(0,0,0,.4),    /* ambient depth */
    inset 0 1px 0 rgba(255,255,255,.08); /* top highlight */
}
🔧

PixCode Glassmorphism Generator esporta il CSS completo inclusi i prefissi vendor.

Focus ring con box-shadow

Sostituire il outline predefinito del browser con box-shadow dà pieno controllo sullo stile mantenendo l'accessibilità. Il trucco è usare un'ombra solo di spread con blur a 0:

:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--bg),         /* gap between element and ring */
    0 0 0 4px rgba(201,184,154,.7); /* visible ring */
}

Neumorfismo

Il neumorfismo usa coppie di ombre inset e outer derivate dal colore di sfondo. Elemento, ombra e sfondo devono usare tonalità strettamente correlate — il contrasto eccessivo rompe l'illusione:

/* Element bg = slightly lighter than page bg */
.neumorphic {
  background: #1c1c1c;
  border-radius: 16px;
  box-shadow:
     8px  8px 16px #0a0a0a,   /* dark shadow: down-right */
    -8px -8px 16px #2e2e2e;   /* light shadow: up-left */
}
.neumorphic.pressed {
  box-shadow:
    inset  4px  4px 10px #0a0a0a,
    inset -4px -4px 10px #2e2e2e;
}

Considerazioni sulle performance

Le ombre sono tra le operazioni di rendering di cui gli sviluppatori si preoccupano di più, spesso senza motivo. Ecco cosa accade realmente:

✓ Percorsi veloci

box-shadow su layer compositing GPU (position:fixed, will-change:transform). filter: drop-shadow() è sempre accelerato GPU. Animare box-shadow tramite transizioni CSS su elementi promossi.

✗ Percorsi lenti

Animare box-shadow su elementi non promossi innesca layout + paint ad ogni frame. Raggi di sfocatura grandi su filter: drop-shadow() sono costosi. text-shadow con sfocatura molto grande su molti elementi.

Quando si animano le ombre

Il pattern più sicuro per ombre animate (elevazioni hover, stati di caricamento) è promuovere prima l'elemento, poi animare l'ombra:

.card {
  will-change: transform;         /* promote to compositing layer */
  transform: translateZ(0);       /* trigger layer in older browsers */
  transition: box-shadow .2s ease, transform .2s ease;
  box-shadow: var(--shadow-2);
}
.card:hover {
  transform: translateY(-2px);    /* move on GPU — free */
  box-shadow: var(--shadow-4);    /* re-composite — also fast */
}
⚠️ Attenzione

Non applicare will-change indiscriminatamente — ogni layer promosso consuma memoria GPU. Usalo solo su elementi che si animano davvero, e rimuovilo al termine dell'animazione se aggiunto via JavaScript.

Performance: blur-radius vs spread-radius

Aumentare blur-radius è più costoso che aumentare spread-radius, perché il blur richiede una convoluzione gaussiana che scala con l'area in pixel. Un'ombra con spread: 10px, blur: 2px è meno costosa di spread: 0, blur: 12px per la stessa impronta visiva.

Generatori di ombre interattivi su PixCode.io

Tutte e tre le tecniche di ombra hanno generatori interattivi dedicati su PixCode — regola i parametri con slider, vedi il risultato live e copia il CSS pronto per la produzione con un clic.

Domande frequenti

Cos'e CSS box-shadow? +
CSS box-shadow aggiunge un'ombra rettangolare dietro un elemento con la sintassi: offset-x offset-y blur-radius spread-radius color. Puoi sovrapporre piu ombre con virgole e usare la parola chiave inset per disegnare l'ombra all'interno dell'elemento.
Come si differenzia filter drop-shadow da box-shadow? +
box-shadow segue il riquadro rettangolare ignorando i pixel trasparenti. filter drop-shadow traccia la forma visibile reale — indispensabile per PNG con trasparenza, SVG e forme irregolari.
Si puo animare le ombre CSS senza problemi di performance? +
Si, ma con attenzione. Animare box-shadow attiva layout e paint su elementi non compositi. Il pattern piu sicuro e animare l'opacita tra due pseudo-elementi con le ombre, oppure usare transform su un elemento gia promosso al layer GPU.
Cos'e il parametro spread-radius in box-shadow? +
Lo spread-radius e il quarto valore di box-shadow. Un valore positivo espande l'ombra oltre l'area di blur; uno negativo la restringe. Spread 0 significa che l'ombra e grande quanto l'elemento prima del blur.
Quando usare text-shadow invece di drop-shadow? +
Usa text-shadow per effetti tipografici — leggibilita, glow, testo in rilievo e stili retro. Usa filter drop-shadow su elementi che devono seguire un bordo non rettangolare, come una nuvoletta SVG o un logo con trasparenza.
Come creo una card neomorfica con box-shadow? +
Il neumorfismo richiede due ombre: una piu chiara del fondo (in alto a sinistra) e una piu scura (in basso a destra). Esempio: box-shadow: 8px 8px 16px #0a0a0a, -8px -8px 16px #2e2e2e su una card #1c1c1c su sfondo #0e0e0e.
Quali browser supportano box-shadow e CSS filter? +
box-shadow e supportato in tutti i browser dal 2011 (IE 9). filter drop-shadow e supportato nei browser moderni dal 2013. Internet Explorer non supporta filter.