Dà profondità alle superfici e trasforma la barra in vetro

Fondo pagina, carte e `secondary` stavano dentro tre punti di luminosità:
carta e fondo avevano un rapporto di contrasto di 1.04, cioè erano lo stesso
bianco. Le carte non si leggevano come carte, e l'unica cosa che le staccava
era `shadow-card` — 6% di nero, che su un telefono al sole non esiste. Da qui
l'impressione che fondo, barra ed elementi fossero «tre bianchi».

La rampa dei neutri è ridistanziata: fondo 0.93, carta 1.0, `secondary` 0.90.
Carta e fondo passano a 1.23, un elemento dentro una carta sta a 1.35 dalla
carta ed è più scuro di essa, come nelle liste raggruppate di iOS. 0.93 è il
fondo più scuro possibile senza toccare altro: il limite lo impone
`text-accent` appoggiato sul fondo, che a 0.92 scenderebbe sotto 4.5.

Due colori vanno corretti di conseguenza, altrimenti la modifica peggiora la
leggibilità: l'accento scende a 0.54 (a 0.58 come testo faceva 4.07 sul nuovo
fondo; ora fa 4.62, e migliora anche il bianco che ci sta sopra, da 4.65 a
5.51) e `muted-foreground` a 0.48. Verificati convertendo le oklch in sRGB e
calcolando i rapporti, non a occhio.

`--destructive` e `--ring` erano *lo stesso identico colore* dell'accento:
«elimina», «selezionato» e «ho il focus qui» davano il medesimo segnale. Il
distruttivo resta rosso ma più scuro e cupo, il focus viene dal neutro.

Le ombre passano da una a tre quote: `shadow-card` per il contenuto,
`shadow-chrome` per barra, drawer e toast (più profonda, più il filo chiaro sul
bordo alto), `shadow-alza` neutra per l'hover — `premi` metteva un alone rosso
sotto ogni riga di classifica.

La barra ora usa `vetro`: fondo al 62% invece dell'85%, così ci si vede
attraverso, più tre ombre interne che sono il bordo illuminato. L'85% di
`materiale` esiste per tenere allineati WebKit e Blink (608f2ed) su una fascia
larga quanto lo schermo; su una pillola di 60 px lo scarto non si legge.

Dietro `@supports`, un `feDisplacementMap` distorce davvero il fondale: solo
Blink accetta un filtro SVG in `backdrop-filter`, e WebKit ignorando l'url
scarterebbe anche il blur. Miglioria progressiva, non l'effetto principale.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 20:02:13 +02:00
co-authored by Claude Opus 5
parent bb4fb624f5
commit c089d9e8ba
6 changed files with 185 additions and 27 deletions
+122 -12
View File
@@ -75,7 +75,25 @@
*/
--altezza-nav: 3.75rem;
--pad-sicura-fondo: max(env(safe-area-inset-bottom), 0.5rem);
--background: oklch(0.985 0.002 240);
/*
* Rampa dei neutri, distanziata per essere vista.
*
* Prima fondo (0.985), carta (1.0) e `secondary` (0.955) stavano dentro tre
* punti di luminosità: carta e fondo avevano un rapporto di contrasto di
* 1.04, cioè erano lo stesso bianco. Le carte non si leggevano come carte e
* l'unica cosa che le staccava era `shadow-card`, che su un telefono al sole
* sparisce.
*
* Ora fondo 0.93 e carta 1.0 stanno a 1.23, e `secondary` (0.90) sta a 1.35
* dalla carta: un elemento dentro una carta è più scuro della carta, come
* nelle liste raggruppate di iOS.
*
* 0.93 è il fondo più scuro possibile senza toccare altro: il limite lo
* impone `text-accent` appoggiato sul fondo, che qui vale 4.62 e a 0.92
* scenderebbe a 4.48, sotto AA. Per andare più giù va scurito anche
* l'accento.
*/
--background: oklch(0.93 0.008 255);
--foreground: oklch(0.16 0.01 260);
--card: oklch(1 0 0);
--card-foreground: oklch(0.16 0.01 260);
@@ -83,17 +101,29 @@
--popover-foreground: oklch(0.16 0.01 260);
--primary: oklch(0.16 0.012 265);
--primary-foreground: oklch(0.99 0 0);
--secondary: oklch(0.955 0.004 250);
--secondary: oklch(0.9 0.01 255);
--secondary-foreground: oklch(0.2 0.012 265);
--muted: oklch(0.955 0.004 250);
--muted-foreground: oklch(0.52 0.015 260);
--accent: oklch(0.58 0.22 27);
--muted: oklch(0.925 0.008 255);
/* 0.48 e non 0.52: sul nuovo `secondary` il vecchio valore scendeva a 4.2. */
--muted-foreground: oklch(0.48 0.015 260);
/*
* Accento più scuro (era 0.58): su un fondo più scuro il rosso di prima
* scendeva a 4.07 come testo. A 0.54 migliora in tutte e tre le direzioni —
* 4.62 sul fondo, 5.67 sulla carta, 5.51 per il bianco che ci sta sopra.
*/
--accent: oklch(0.54 0.22 27);
--accent-foreground: oklch(0.99 0 0);
--destructive: oklch(0.58 0.22 27);
/*
* Distruttivo e accento erano lo stesso identico colore: «elimina» e
* «selezionato» davano lo stesso segnale. Resta rosso — è la convenzione —
* ma più scuro e più cupo dell'accento del brand.
*/
--destructive: oklch(0.47 0.19 18);
--destructive-foreground: oklch(0.99 0 0);
--border: oklch(0.915 0.006 255);
--input: oklch(0.915 0.006 255);
--ring: oklch(0.58 0.22 27);
--border: oklch(0.875 0.01 255);
--input: oklch(0.875 0.01 255);
/* Il focus non è una selezione: viene dal neutro, non dall'accento. */
--ring: oklch(0.35 0.03 265);
/* Luminosità scelte perché il testo bianco sopra superi 4.5:1 (WCAG AA). */
--success: oklch(0.53 0.16 152);
--success-foreground: oklch(0.99 0 0);
@@ -117,9 +147,26 @@
oklch(0.24 0.03 20) 55%,
oklch(0.45 0.19 27)
);
--gradient-accent: linear-gradient(120deg, oklch(0.58 0.22 27), oklch(0.68 0.19 40));
/* Parte dall'accento nuovo: era rimasto sul vecchio 0.58 e il gradiente
risultava più chiaro del colore pieno che gli sta accanto. */
--gradient-accent: linear-gradient(120deg, oklch(0.54 0.22 27), oklch(0.64 0.19 40));
/*
* Tre quote, non una. Prima `shadow-card` valeva sia per una tessera 3x3 sia
* per la barra di navigazione: superfici grandi e piccole sullo stesso piano.
* Una superficie più grande deve leggersi più spessa.
*/
--shadow-card: 0 1px 2px oklch(0.16 0.01 260 / 6%), 0 12px 28px -18px oklch(0.16 0.01 260 / 35%);
--shadow-pop: 0 18px 40px -20px oklch(0.58 0.22 27 / 55%);
/*
* Chrome flottante: barra, drawer. Ombra più profonda e più diffusa, più il
* filo chiaro sul bordo alto — la luce che prende il materiale, ed è quello
* che lo fa leggere come un oggetto sopra il contenuto invece che un buco.
*/
--shadow-chrome:
inset 0 1px 0 oklch(1 0 0 / 60%), 0 1px 3px oklch(0.16 0.01 260 / 10%),
0 24px 48px -24px oklch(0.16 0.01 260 / 45%);
/* Sollevamento al passaggio del mouse: neutro, non tinto di accento. */
--shadow-alza: 0 12px 28px -14px oklch(0.16 0.01 260 / 40%);
--shadow-pop: 0 18px 40px -20px oklch(0.54 0.22 27 / 55%);
}
@theme inline {
@@ -158,6 +205,10 @@
box-shadow: var(--shadow-pop);
}
@utility shadow-chrome {
box-shadow: var(--shadow-chrome);
}
/*
* Il tracking del display è specifico per taglia: Bebas Neue a corpo grande
* legge troppo spaziato (serve tracking negativo), a corpo piccolo troppo
@@ -290,7 +341,9 @@
@media (hover: hover) {
&:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-pop);
/* Neutra: `shadow-pop` è un alone di accento, e sotto una riga di
classifica era colore senza significato. */
box-shadow: var(--shadow-alza);
}
}
}
@@ -378,6 +431,63 @@
-webkit-backdrop-filter: blur(20px) saturate(150%);
}
/*
* Vetro della barra flottante. È `materiale` spinto: si vede attraverso.
*
* `materiale` sta all'85% di card perché è una superficie larga quanto lo
* schermo, dove il divario di blur fra WebKit e Blink si nota (608f2ed). Qui
* la superficie è una pillola piccola: si può scendere al 62% e lasciare che
* sia il blur a fare il lavoro, che è la condizione perché si legga come vetro
* invece che come plastica bianca.
*
* Le tre ombre interne sono la luce sul bordo, non decorazione: filo chiaro in
* alto (la luce che entra), filo scuro in basso (lo spessore del vetro), alone
* chiaro diffuso appena dentro il bordo (il riflesso sulla curva). Senza queste
* un rettangolo sfocato resta un rettangolo sfocato.
*/
@utility vetro {
background-color: color-mix(in srgb, var(--color-card) 62%, transparent);
backdrop-filter: blur(18px) saturate(180%) brightness(1.04);
-webkit-backdrop-filter: blur(18px) saturate(180%) brightness(1.04);
box-shadow:
inset 0 1px 0 oklch(1 0 0 / 85%),
inset 0 -1px 0 oklch(0.16 0.01 260 / 8%),
inset 0 0 12px oklch(1 0 0 / 35%),
0 1px 3px oklch(0.16 0.01 260 / 10%),
0 24px 48px -24px oklch(0.16 0.01 260 / 45%);
}
/*
* La distorsione vera: `feDisplacementMap` sposta i pixel del fondale, quindi
* quello che sta sotto si deforma davvero invece di sfocarsi soltanto.
*
* Sta dietro `@supports` perché solo Blink accetta un filtro SVG dentro
* `backdrop-filter`: WebKit lo ignora — e ignorandolo scarterebbe tutta la
* dichiarazione, blur compreso — quindi su iPhone resta la regola sopra. È una
* miglioria progressiva, non l'effetto principale: se sparisse domani la barra
* resterebbe quella giusta.
*/
@supports (backdrop-filter: url("#vetro-rifrazione")) {
.vetro {
backdrop-filter: url("#vetro-rifrazione") blur(18px) saturate(180%) brightness(1.04);
}
}
/* Il vetro traslucido è un vezzo: se l'utente chiede meno trasparenza sparisce. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
.vetro {
background-color: var(--color-card);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.vetro {
background-color: var(--color-card);
}
}
/*
* Chrome su Android disattiva `backdrop-filter` quando l'accelerazione
* hardware non è disponibile: senza questo, su quei device la barra resta