Funzionalità di stile web di oggi e di domani, come mostrato al Google I/O 2022, più alcuni extra.
Il 2022 si preannuncia come uno degli anni migliori per i CSS, sia per le funzionalità che per le versioni delle funzionalità dei browser cooperativi, con l'obiettivo collaborativo di implementare 14 funzionalità.
Panoramica
Questo post è la versione scritta dell'intervento tenuto al Google I/O 2022. Non è pensata per essere una guida approfondita su ogni funzionalità, ma piuttosto un'introduzione e una breve panoramica per suscitare il tuo interesse, fornendo ampiezza anziché profondità. Se ti interessa, controlla la fine di una sezione per i link alle risorse per ulteriori informazioni.
Sommario
Utilizza l'elenco di seguito per passare agli argomenti di interesse:
Compatibilità del browser
Uno dei motivi principali per cui così tante funzionalità CSS sono impostate per il rilascio cooperativo è dovuto agli sforzi di Interop 2022. Prima di studiare gli sforzi di Interop, è importante esaminare quelli di Compat 2021.
Compat 2021
Gli obiettivi per il 2021, basati sul feedback degli sviluppatori tramite sondaggi, erano di stabilizzare le funzionalità attuali, migliorare la suite di test e aumentare i punteggi di superamento dei browser per cinque funzionalità:
sticky
posizionamentoaspect-ratio
dimensionamento- Layout
flex
- Layout
grid
- Posizionamento e animazione di
transform
I punteggi dei test sono aumentati in tutti i casi, a dimostrazione di una maggiore stabilità e affidabilità. Congratulazioni ai team presenti.
Interop 2022
Quest'anno, i browser si sono riuniti per discutere delle funzionalità e delle priorità su cui intendevano lavorare, unendo le loro forze. Avevano pianificato di fornire le seguenti funzionalità web per gli sviluppatori:
@layer
- Spazi colore e funzioni
- Contenimento
<dialog>
- Compatibilità con i moduli
- Scorrimento
- Subgrid
- Tipografia
- Unità di misura dell'area visibile
- Compatibilità web
Si tratta di un elenco entusiasmante e ambizioso che non vedo l'ora di vedere realizzarsi.
Novità del 2022
Non sorprende che lo stato di CSS 2022 sia influenzato in modo significativo dal lavoro di Interop 2022.
Livelli a cascata
Prima di @layer
, l'ordine di caricamento dei fogli di stile era molto importante,
in quanto gli stili caricati per ultimi possono sovrascrivere quelli caricati in precedenza. Ciò ha portato a
fogli di stile di ingresso gestiti meticolosamente, in cui gli sviluppatori dovevano caricare prima gli stili meno
importanti e poi quelli più importanti. Esistono metodologie complete
per aiutare gli sviluppatori a gestire questa importanza, come
ITCSS.
Con @layer
, il file di ingresso può predefinire i livelli e il loro ordine in anticipo. Poi, man mano che gli stili vengono caricati o definiti, possono essere inseriti in un
livello, consentendo di preservare l'importanza dell'override dello stile, ma senza l'orchestrazione
meticolosamente gestita del caricamento.
Il video mostra come i livelli a cascata definiti consentono un processo di creazione e caricamento più libero e in stile libero, mantenendo comunque la cascata come necessario.
Chrome DevTools è utile per visualizzare gli stili provenienti dai vari livelli:
Risorse
- Specifica CSS Cascade 5
- Spiegazione dei livelli a cascata
- Livelli a cascata su MDN
- Una Kravets: Cascade Layers
- Ahmad Shadeed: Hello, CSS Cascade Layers
Subgrid
Prima del giorno subgrid
, una griglia all'interno di un'altra griglia non poteva allinearsi alle celle o alle linee della griglia principale. Ogni layout a griglia era unico. Molti designer posizionano una
singola griglia sull'intero design e allineano costantemente gli elementi al suo interno, cosa che
non era possibile fare in CSS.
Dopo subgrid
, un elemento secondario di una griglia può adottare le colonne o le righe dei genitori come proprie e allineare se stesso o i suoi elementi secondari.
Nella seguente demo, l'elemento body crea una griglia classica di tre colonne:
la colonna centrale è chiamata main
, mentre le colonne sinistra e destra nominano le
linee
fullbleed
. Poi, ogni elemento nel corpo, <nav>
e <main>
, adotta le
linee denominate dal corpo impostando grid-template-columns: subgrid
.
body {
display: grid;
grid-template-columns:
[fullbleed-start]
auto [main-start] min(90%, 60ch) [main-end] auto
[fullbleed-end]
;
}
body > * {
display: grid;
grid-template-columns: subgrid;
}
Infine, i figli di <nav>
o <main>
possono allinearsi o dimensionarsi utilizzando le
colonne e le righe fullbleed
e main
.
.main-content {
grid-column: main;
}
.fullbleed {
grid-column: fullbleed;
}
Gli strumenti di sviluppo possono aiutarti a visualizzare le linee e le griglie secondarie (al momento solo Firefox). Nell'immagine seguente, la griglia principale e le griglie secondarie sono state sovrapposte. Ora assomiglia al modo in cui i designer pensavano al layout.
Nel riquadro degli elementi di DevTools puoi vedere quali elementi sono griglie e sottogriglie, il che è molto utile per il debug o la convalida del layout.

Risorse
Query sui container
Prima del giorno @container
, gli elementi di una pagina web potevano rispondere solo alle dimensioni dell'intera area visibile. Questa soluzione è ideale per i layout macro, ma per i layout micro, in cui
il contenitore esterno non è l'intera area visibile, è impossibile per il layout
adattarsi di conseguenza.
Dopo @container
, gli elementi possono rispondere alle dimensioni o allo stile di un contenitore principale.
L'unico avvertimento è che i contenitori devono dichiararsi come possibili target di query, il che è un piccolo requisito per un grande vantaggio.
/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
}
Questi stili consentono di eseguire query sulle colonne Lun, Mar, Mer, Gio e Ven nel video seguente in base agli elementi dell'evento.
Ecco il CSS per eseguire query sul contenitore calendar-day
per la sua dimensione, quindi
regolare un layout e le dimensioni dei caratteri:
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
Ecco un altro esempio: un componente libro si adatta allo spazio disponibile nella colonna in cui viene trascinato:
Una ha ragione a definire la situazione come il nuovo
responsive. Quando utilizzi @container
, puoi prendere molte decisioni di design interessanti e significative.
Risorse
- Specifiche delle query sui contenitori
- Spiegazione delle query sui container
- Container Queries su MDN
- Nuovo design adattabile su web.dev
- Demo di Calendar di Una
- Awesome container queries collection
- Come abbiamo creato Designcember su web.dev
- Ahmad Shadeed: Say Hello To CSS Container Queries
accent-color
Prima di accent-color
, quando volevi un modulo con colori corrispondenti al brand, potevi ritrovarti con librerie complesse o soluzioni CSS difficili da gestire nel tempo. Anche se ti hanno fornito tutte le opzioni e, si spera, incluso
l'accessibilità, la scelta di utilizzare i componenti integrati o adottare i tuoi
diventa noiosa da continuare a scegliere.
Dopo accent-color
, una riga di CSS porta un colore del brand nei componenti
integrati. Oltre a una tonalità, il browser sceglie in modo intelligente i colori di contrasto appropriati per le parti ausiliarie del componente e si adatta alle combinazioni di colori del sistema (chiaro o scuro).
/* tint everything */
:root {
accent-color: hotpink;
}
/* tint one element */
progress {
accent-color: indigo;
}
Per saperne di più su accent-color
, consulta il mio post su
web.dev, in cui esploro molti altri aspetti di
questa utile proprietà CSS.
Risorse
- specifica accent-color
- accent-color su MDN
- accent-color su web.dev
- Bramus: Tint User-Interface Controls with CSS accent-color
Livello di colore 4 e 5
Il web è stato dominato da sRGB negli ultimi decenni, ma in un mondo digitale in espansione di display ad alta definizione e dispositivi mobili preinstallati con schermi OLED o QLED, sRGB non è sufficiente. Inoltre, sono previste pagine dinamiche che si adattano alle preferenze degli utenti e la gestione del colore è diventata una preoccupazione sempre più importante per designer, sistemi di progettazione e responsabili della manutenzione del codice.
Non nel 2022, però: CSS ha una serie di nuove funzioni e spazi di colore: - Colori che sfruttano le funzionalità di colore HD dei display. - Spazi colore che corrispondono a un intento, ad esempio l'uniformità percettiva. - Spazi colore per sfumature che modificano drasticamente i risultati dell'interpolazione. - Funzioni di colore per aiutarti a mescolare e contrastare i colori e scegliere lo spazio in cui lavorare.
Prima di tutte queste funzionalità di colore, i sistemi di progettazione dovevano precalcolare i colori di contrasto appropriati e garantire tavolozze adeguatamente vivaci, mentre i preprocessor o JavaScript facevano il lavoro più pesante.
Dopo tutte queste funzionalità di colore, il browser e CSS possono fare tutto il lavoro, in modo dinamico e appena in tempo. Anziché inviare agli utenti molti KB di CSS e JavaScript per consentire la creazione di temi e la visualizzazione dei colori dei dati, CSS può eseguire l'orchestrazione e i calcoli. Inoltre, CSS è meglio attrezzato per verificare il supporto prima dell'utilizzo o gestire i fallback in modo appropriato.
@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);
}
}
@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
}
}
hwb()
HWB è l'acronimo di tonalità, bianco e nero. Si presenta come un modo semplice per esprimere il colore, in quanto si tratta solo di una tonalità e di una quantità di bianco o nero per schiarire o scurire. Gli artisti che mescolano i colori con il bianco o il nero potrebbero apprezzare questa aggiunta alla sintassi dei colori.
L'utilizzo di questa funzione di colore genera colori dello spazio colore sRGB, lo stesso di HSL e RGB. In termini di novità per il 2022, non offre nuovi colori, ma potrebbe semplificare alcune attività per gli appassionati della sintassi e del modello mentale.
Risorse
Spazi colore
Il modo in cui i colori vengono rappresentati avviene tramite uno spazio colore. Ogni spazio colore offre varie funzionalità e compromessi per lavorare con il colore. Alcuni potrebbero raggruppare tutti i colori vivaci, altri potrebbero allinearli in base alla loro luminosità.
Le specifiche CSS del 2022 prevedono 10 nuovi spazi colore, ognuno con caratteristiche uniche per aiutare designer e sviluppatori a visualizzare, scegliere e combinare i colori. In precedenza, sRGB era l'unica opzione per lavorare con il colore, ma ora CSS offre nuove potenzialità e un nuovo spazio colore predefinito, LCH.
color-mix()
Prima di color-mix()
, gli sviluppatori e i designer avevano bisogno di preprocessor come
Sass per combinare i colori prima che il browser li visualizzasse.
La maggior parte delle funzioni di miscelazione dei colori non offriva nemmeno la possibilità di specificare in quale
spazio colore eseguire la miscelazione, il che a volte portava a risultati confusi.
Dopo color-mix()
, sviluppatori e designer possono combinare i colori nel browser,
insieme a tutti gli altri stili, senza eseguire processi di compilazione o includere
JavaScript. Inoltre, possono specificare lo spazio colore in cui eseguire la combinazione
o utilizzare lo spazio colore di combinazione predefinito LCH.
Spesso, un colore del brand viene utilizzato come base e vengono create varianti, ad esempio
colori più chiari o più scuri per gli stili al passaggio del mouse. Ecco come si presenta con
color-mix()
:
.color-mix-example {
--brand: #0af;
--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
}
e se volessi mescolare questi colori in uno spazio colore diverso, ad esempio sRGB, modificalo:
.color-mix-example {
--brand: #0af;
--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
}
Di seguito è riportata una demo della personalizzazione dei temi che utilizza color-mix()
. Prova a cambiare il colore del brand
e guarda l'aggiornamento del tema:
Nel 2022 potrai divertirti a combinare i colori in vari spazi colore nei tuoi fogli di stile.
Risorse
- Specifiche di color-mix()
- color-mix() su MDN
- Demo dei temi
- Un'altra demo di temi
- Fabio Giolito: Create a color theme with these upcoming CSS features
color-contrast()
Prima di color-contrast()
, gli autori dei fogli di stile dovevano conoscere in anticipo i colori accessibili. Spesso una tavolozza mostra testo nero o bianco su un campione di colore,
per indicare a un utente del sistema di colori quale colore del testo sarebbe necessario per
contrastare correttamente con quel campione.

Dopo color-contrast()
, gli autori dei fogli di stile possono delegare completamente l'attività al browser. Non solo puoi utilizzare il browser per scegliere automaticamente un colore nero o bianco, ma puoi anche fornirgli un elenco di colori appropriati per il sistema di progettazione e fargli scegliere il primo che supera il rapporto di contrasto desiderato.
Ecco uno screenshot di una demo di un set di tavolozze di colori HWB in cui i colori del testo vengono scelti automaticamente dal browser in base al colore del campione:

Le basi della sintassi sono le seguenti, dove il grigio viene passato alla funzione e il browser determina se il nero o il bianco hanno il contrasto maggiore:
color: color-contrast(gray);
La funzione può anche essere personalizzata con un elenco di colori, da cui verrà scelto il colore con il contrasto più elevato della selezione:
color: color-contrast(gray vs indigo, rebeccapurple, hotpink);
Infine, nel caso in cui sia preferibile non scegliere il colore con il contrasto più elevato dall'elenco, è possibile fornire un rapporto di contrasto target e viene scelto il primo colore che lo supera:
color: color-contrast(
var(--bg-blue-1)
vs
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
);
Questa funzione può essere utilizzata per molto più del semplice colore del testo, anche se ritengo che sarà il suo caso d'uso principale. Pensa a quanto sarà più facile fornire interfacce accessibili e leggibili una volta che la scelta dei colori di contrasto appropriati sarà integrata nel linguaggio CSS stesso.
Risorse
Sintassi del colore relativo
Prima della sintassi del colore relativo, per eseguire calcoli sul colore e apportare modifiche, i
canali colore dovevano essere inseriti singolarmente nelle proprietà personalizzate. Questa
limitazione ha reso HSL la funzione di colore principale per la manipolazione dei colori
perché la tonalità, la saturazione o la luminosità potevano essere regolate in modo
semplice con calc()
.
Dopo la sintassi del colore relativo, qualsiasi colore in qualsiasi spazio può essere decostruito, modificato e restituito come colore, tutto in una riga di CSS. Nessuna limitazione all'HSL: le manipolazioni possono essere eseguite in qualsiasi spazio colore desiderato e devono essere create molte meno proprietà personalizzate per facilitarlo.
Nel seguente esempio di sintassi, viene fornito un esadecimale di base e vengono creati due nuovi colori
relativi a questo. Il primo colore --absolute-change
crea un nuovo colore
in LCH dal colore di base, quindi procede a sostituire la luminosità del colore di base
con 75%
, mantenendo la croma (c
) e la tonalità (h
). Il secondo colore
--relative-change
crea un nuovo colore in LCH dal colore di base, ma questa
volta riduce la croma (c
) del 20%.
.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
}
È come mescolare i colori, ma è più simile alle alterazioni che alla mescolanza. Puoi eseguire il cast di un colore da un altro colore, ottenendo l'accesso ai tre valori dei canali in base alla funzione di colore utilizzata, con la possibilità di regolare questi canali. Nel complesso, si tratta di una sintassi molto interessante e potente per il colore.
Nella seguente demo ho utilizzato la sintassi dei colori relativi per creare varianti più chiare e
più scure di un colore di base e ho utilizzato color-contrast()
per garantire che
le etichette abbiano un contrasto adeguato:

Questa funzione può essere utilizzata anche per la generazione di tavolozze di colori. Ecco una demo in cui vengono generate intere tavolozze a partire da un colore di base fornito. Questo unico insieme di CSS alimenta tutte le varie tavolozze, ognuna delle quali fornisce semplicemente una base diversa. Come bonus, dato che ho utilizzato LCH, guarda come le tavolozze sono uniformi dal punto di vista percettivo: non ci sono punti caldi o morti, grazie a questo spazio colore.
:root {
--_color-base: #339af0;
--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
}

A questo punto, dovresti aver capito come gli spazi colore e le diverse funzioni di colore possono essere utilizzati per scopi diversi, in base ai loro punti di forza e di debolezza.
Risorse
- Specifica della sintassi del colore relativo
- Creare tavolozze di colori con la sintassi dei colori relativi
- Creare varianti di colore con la sintassi del colore relativo
Spazi colore del gradiente
Prima degli spazi colore con gradiente, veniva utilizzato lo spazio colore sRGB predefinito. sRGB è generalmente affidabile, ma presenta alcuni punti deboli, come la zona grigia morta.
Dopo gli spazi colore del gradiente, indica al browser quale spazio colore utilizzare per l'interpolazione del colore. In questo modo, sviluppatori e designer possono scegliere il gradiente che preferiscono. Anche lo spazio colore predefinito cambia in LCH anziché sRGB.
L'aggiunta della sintassi segue la direzione del gradiente, utilizza la nuova sintassi in
ed è facoltativa:
background-image: linear-gradient(
to right in hsl,
black, white
);
background-image: linear-gradient(
to right in lch,
black, white
);
Ecco una sfumatura di base ed essenziale dal nero al bianco. Esamina l'intervallo di risultati in ogni spazio colore. Alcuni raggiungono il nero intenso prima di altri, alcuni sbiadiscono al bianco troppo tardi.
Nel prossimo esempio, il nero viene trasformato in blu perché è un problema noto spazio per i gradienti. La maggior parte degli spazi colore tende al viola durante l'interpolazione del colore o, come mi piace pensare, mentre i colori si spostano all'interno dello spazio colore dal punto A al punto B. Poiché il gradiente segue una linea retta dal punto A al punto B, la forma dello spazio colore cambia drasticamente le tappe del percorso.
Per esplorazioni più approfondite, esempi e commenti, leggi questo thread di Twitter.
Risorse
- Specifiche dell'interpolazione del gradiente
- Demo che confronta i gradienti negli spazi
- Confronto dei notebook Observable con i gradienti
inert
Prima di inert
, era buona prassi indirizzare l'attenzione dell'utente verso le aree della
pagina o dell'app che richiedevano attenzione immediata. Questa strategia di messa a fuoco guidata è diventata
nota come intrappolamento dello stato attivo perché gli sviluppatori posizionavano lo stato attivo in uno spazio
interattivo, ascoltavano gli eventi di cambio dello stato attivo e, se lo stato attivo usciva dallo spazio
interattivo, veniva forzato a rientrare. Gli utenti che utilizzano tastiere o screen reader
vengono riportati allo spazio interattivo per assicurarsi che l'attività sia completata prima di
andare avanti.
Dopo inert
, non è necessario alcun blocco perché puoi bloccare o proteggere intere
sezioni della pagina o dell'app. I tentativi di clic e cambio di messa a fuoco non sono
disponibili mentre queste parti di un documento sono inerti. Si potrebbe anche pensare a
questo come a delle guardie invece di una trappola, in cui inert
non è interessato a farti
rimanere in un posto, ma a rendere indisponibili altri luoghi.
Un buon esempio è la funzione JavaScript alert()
:
Nel video precedente, nota come la pagina fosse accessibile con mouse e tastiera
fino a quando non è stato chiamato un alert()
. Una volta visualizzato il popup della finestra di dialogo di avviso, il resto
della pagina è stato bloccato o inert
. Lo stato attivo dell'utente si trova all'interno della finestra di dialogo di avviso e non può essere spostato altrove. Una volta che l'utente interagisce e completa la richiesta di funzione di avviso, la pagina torna a essere interattiva. inert
consente
agli sviluppatori di ottenere facilmente la stessa esperienza di messa a fuoco guidata.
Ecco un piccolo codice campione per mostrare come funziona:
<body>
<div class="modal">
<h2>Modal Title</h2>
<p>...<p>
<button>Save</button>
<button>Discard</button>
</div>
<main inert>
<!-- cannot be keyboard focused or clicked -->
</main>
</body>
Una finestra di dialogo è un ottimo esempio, ma inert
è utile anche per elementi come l'esperienza utente del menu laterale a scorrimento. Quando un utente estrae il menu laterale, non è
consentito che il mouse o la tastiera interagiscano con la pagina sottostante, perché è
un po' complicato per gli utenti. Quando viene visualizzato il menu laterale, la pagina
diventa inerte e gli utenti devono chiudere o navigare all'interno del menu laterale, senza
perdersi in altre parti della pagina con un menu aperto.
Risorse
Caratteri COLRv1
Prima dei caratteri COLRv1, il web aveva i caratteri OT-SVG, anch'essi in formato aperto per i caratteri con sfumature ed effetti e colori integrati. Questi potevano diventare molto grandi e, sebbene consentissero di modificare il testo, non c'era molto spazio per la personalizzazione.
Dopo i caratteri COLRv1, il web dispone di caratteri più piccoli, scalabili in formato vettoriale, riposizionabili, con sfumature e con modalità di fusione che accettano parametri per personalizzare il carattere in base al caso d'uso o per abbinarlo a un brand.

Ecco un esempio tratto dal post del blog per sviluppatori Chrome sugli emoji. Forse avrai notato che se aumenti le dimensioni del carattere di un'emoji, questa non rimane nitida. È un'immagine e non un'illustrazione vettoriale. Spesso, quando viene utilizzata un'emoji nelle applicazioni, viene sostituita con un asset di qualità superiore. Con i caratteri COLRv1, le emoji sono vettoriali e bellissime:
I caratteri icona potrebbero fare cose straordinarie con questo formato, offrendo tavolozze di colori personalizzate in due tonalità e altro ancora. Il caricamento di un carattere COLRv1 è identico a quello di qualsiasi altro file di caratteri:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
La personalizzazione del carattere COLRv1 viene eseguita con @font-palette-values
, una regola CSS
speciale per raggruppare e denominare un insieme di opzioni di personalizzazione in un bundle per
riferimento futuro. Nota come specificare un nome personalizzato proprio come una proprietà personalizzata, a partire da --
:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
Con --colorized
come alias per le personalizzazioni, l'ultimo passaggio consiste nell'applicare
la tavolozza a un elemento che utilizza la famiglia di caratteri a colori:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
.spicy {
font-family: "Bungee Spice";
font-palette: --colorized;
}

Con la crescente disponibilità di caratteri variabili e a colori, la tipografia web sta percorrendo un percorso molto promettente verso una ricca personalizzazione e un'espressione creativa.
Risorse
- Specifiche di Colrv1 su GitHub
- Chrome Developers: Colrv1 Fonts
- Video esplicativo per gli sviluppatori di BlinkOn
Unità di misura dell'area visibile
Prima delle nuove varianti dell'area visibile, il web offriva unità fisiche per facilitare l'adattamento delle aree visibili. Uno per l'altezza, la larghezza, la dimensione più piccola (vmin) e il lato più grande (vmax). Questi hanno funzionato bene per molte cose, ma i browser mobile hanno introdotto una complessità.
Sui dispositivi mobili, quando viene caricata una pagina, viene visualizzata la barra di stato con l'URL e questa
barra occupa parte dello spazio dell'area visibile. Dopo alcuni secondi e un po' di interattività, la barra di stato potrebbe scomparire per consentire all'utente un'esperienza di visualizzazione più ampia. Quando la barra scorre verso l'esterno, l'altezza dell'area visibile è cambiata e tutte le unità vh
si spostano e vengono ridimensionate man mano che le dimensioni di destinazione cambiano.
Negli anni successivi, l'unità vh
doveva decidere in modo specifico quale delle due
dimensioni della finestra di visualizzazione utilizzare, perché causava problemi di layout visivo
sui dispositivi mobili. È stato stabilito che vh
rappresenterà sempre
l'area visibile più grande.
.original-viewport-units {
height: 100vh;
width: 100vw;
--size: 100vmin;
--size: 100vmax;
}
Dopo le nuove varianti dell'area visibile, vengono rese disponibili unità di area visibile piccole, grandi e dinamiche, con l'aggiunta di equivalenti logici a quelli fisici. L'idea è
di dare a sviluppatori e designer la possibilità di scegliere l'unità che vogliono
utilizzare per il loro scenario specifico. Forse è accettabile un piccolo spostamento del layout
quando la barra di stato scompare, in modo che dvh
(altezza dinamica del viewport) possa essere
utilizzata senza problemi.
Di seguito è riportato un elenco completo di tutte le nuove opzioni per le unità viewport rese disponibili con le nuove varianti del viewport:
.new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; }
.new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; }
.new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; }
.new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
Ci auguriamo che queste funzionalità offrano a sviluppatori e designer la flessibilità necessaria per ottenere i design reattivi della finestra.
Risorse
:has()
Prima di :has()
, l'oggetto di un selettore si trovava sempre alla fine. Ad esempio, l'oggetto di questo selettore è un elemento dell'elenco: ul > li
. Gli pseudo-selettori possono modificare
il selettore, ma non cambiano il soggetto: ul > li:hover
o ul >
li:not(.selected)
.
Dopo :has()
, un soggetto più in alto nell'albero degli elementi può rimanere il soggetto
fornendo una query sui figli: ul:has(> li)
. È facile capire
perché :has()
ha ricevuto il nome comune di "selettore principale", in quanto il soggetto del
selettore è ora il genitore in questo caso.
Ecco un esempio di sintassi di base in cui la classe .parent
rimane il soggetto, ma
viene selezionata solo se un elemento secondario ha la classe .child
:
.parent:has(.child) {...}
Ecco un esempio in cui un elemento <section>
è il soggetto, ma il selettore
corrisponde solo se uno degli elementi secondari ha :focus-visible
:
section:has(*:focus-visible) {...}
Il selettore :has()
inizia a diventare un'utilità fantastica quando diventano evidenti casi d'uso più pratici. Ad esempio, al momento non è possibile selezionare i tag <a>
quando includono immagini, il che rende difficile insegnare al tag di ancoraggio come modificare i suoi stili in questo caso d'uso. È possibile con :has()
però:
a:has(> img) {...}
Questi sono tutti esempi in cui :has()
sembra solo un selettore principale.
Prendi in considerazione il caso d'uso delle immagini all'interno degli elementi <figure>
e la regolazione degli stili delle immagini se la figura ha una <figcaption>
. Nell'esempio
seguente, vengono selezionate le figure con le didascalie e poi le immagini all'interno di questo
contesto. :has()
viene utilizzato e non modifica il soggetto, in quanto il soggetto a cui ci rivolgiamo sono le immagini, non le figure:
figure:has(figcaption) img {...}
Le combinazioni sono apparentemente infinite. Combina :has()
con query
sulla quantità e regola
i layout a griglia CSS in base al numero di elementi secondari. Combina :has()
con
stati di pseudo-classe
interattivi e crea
applicazioni che rispondono in nuovi modi creativi.
La verifica del supporto è semplificata con
@supports
e
la relativa
funzione
selector()
, che verifica se il browser comprende la sintassi prima di utilizzarla:
@supports (selector(:has(works))) {
/* safe to use :has() */
}
Risorse
2022 e anni successivi
Ci sono ancora molte cose che saranno difficili da fare dopo l'implementazione di tutte queste fantastiche funzionalità nel 2022. La sezione successiva esamina alcuni dei problemi rimanenti e le soluzioni in fase di sviluppo attivo per risolverli. Queste soluzioni sono sperimentali, anche se potrebbero essere specificate o disponibili dietro i flag nei browser.
I risultati delle sezioni successive dovrebbero rassicurarti sul fatto che i problemi elencati sono oggetto di risoluzione da parte di molte persone di molte aziende, non che queste soluzioni verranno rilasciate nel 2023.
Proprietà personalizzate con tipizzazione debole
Le proprietà personalizzate CSS sono fantastiche. Consentono di memorizzare tutti i tipi di dati all'interno di una variabile denominata, che può essere estesa, calcolata, condivisa e altro ancora. Infatti, sono così flessibili che sarebbe bello averne alcuni meno flessibili.
Considera uno scenario in cui un box-shadow
utilizza proprietà personalizzate per i suoi valori:
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
Tutto funziona bene finché una delle proprietà non viene modificata in un valore che
CSS non accetta, ad esempio --x: red
. L'intera ombra viene interrotta se una delle variabili nidificate è mancante o è impostata su un tipo di valore non valido.
È qui che entra in gioco @property
: --x
può
diventare una proprietà personalizzata digitata, non più libera e flessibile, ma sicura con alcuni
limiti definiti:
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
Ora, quando box-shadow
utilizza var(--x)
e successivamente viene tentato --x: red
,
red
verrà ignorato perché non è un <length>
. Ciò significa che l'ombreggiatura continua
a funzionare, anche se a una delle sue proprietà personalizzate è stato assegnato un valore non valido.
Anziché non riuscire, torna al valore initial-value
di 0px
.
Animazione
Oltre alla sicurezza dei tipi, apre anche molte porte all'animazione. La
flessibilità della sintassi CSS rende impossibile animare alcune cose, come
i gradienti. @property
è utile in questo caso perché la proprietà CSS digitata può informare il browser dell'intento di uno sviluppatore all'interno di un'interpolazione altrimenti eccessivamente complessa. In sostanza, limita l'ambito delle possibilità in modo tale che un browser possa animare aspetti di uno stile che prima non poteva.
Considera questo esempio di demo, in cui viene utilizzato un gradiente radiale per creare una porzione di una sovrapposizione, creando un effetto di messa a fuoco. JavaScript imposta x e y del mouse quando viene premuto il tasto Alt/Opzione, quindi modifica la dimensione del fuoco a un valore più piccolo, ad esempio 25%, creando il cerchio di messa a fuoco del riflettore nella posizione del mouse:
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
}
Tuttavia, i gradienti non possono essere animati. Sono troppo flessibili e complessi per
il browser per "dedurre" semplicemente come vuoi che vengano animate. Con @property
, invece, una proprietà può essere digitata e animata in isolamento, per cui il browser può comprendere facilmente l'intento.
I videogiochi che utilizzano questo effetto di messa a fuoco animano sempre il cerchio, da un cerchio grande a un cerchio puntiforme. Ecco come utilizzare @property
con la nostra demo in modo che
il browser animi la maschera sfumata:
@property --focal-size {
syntax: '<length-percentage>';
initial-value: 100%;
inherits: false;
}
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
transition: --focal-size .3s ease;
}
Ora il browser è in grado di animare le dimensioni del gradiente perché abbiamo ridotto la superficie della modifica a una sola proprietà e abbiamo digitato il valore in modo che il browser possa interpolare in modo intelligente le lunghezze.
@property
può fare molto di più, ma questi piccoli miglioramenti possono fare una grande differenza.
Risorse
- @property specification
- @property su MDN
- @property su web.dev
- Demo della messa a fuoco dello zoom
- CSS Tricks: Exploring @property and its animating powers
Si trovava in min-width
o max-width
Prima degli intervalli delle media query, una media query CSS utilizza min-width
e max-width
per
articolare le condizioni superiori e inferiori. Potrebbe avere un aspetto simile al seguente:
@media (min-width: 320px) {
…
}
Dopo gli intervalli delle query supporti, la stessa query supporti potrebbe essere simile alla seguente:
@media (width >= 320px) {
…
}
Una query supporti CSS che utilizza sia min-width
che max-width
potrebbe avere il seguente aspetto:
@media (min-width: 320px) and (max-width: 1280px) {
…
}
Dopo gli intervalli delle query supporti, la stessa query supporti potrebbe essere simile alla seguente:
@media (320px <= width <= 1280px) {
…
}
A seconda delle tue competenze di programmazione, uno dei due ti sembrerà molto più leggibile dell'altro. Grazie alle aggiunte alle specifiche, gli sviluppatori potranno scegliere quella che preferiscono o persino utilizzarle in modo intercambiabile.
Risorse
- Specifica della sintassi dell'intervallo di query multimediali
- Sintassi dell'intervallo di query multimediali su MDN
- Plug-in PostCSS per la sintassi dell'intervallo di query multimediali
Nessuna variabile di query supporti
Prima di @custom-media
, le media query dovevano ripetersi più volte o
fare affidamento sui preprocessor per generare l'output corretto in base alle variabili statiche
durante la compilazione.
A partire da @custom-media
, CSS consente di creare alias per le query supporti e di farvi riferimento, proprio come per una proprietà personalizzata.
Assegnare un nome è molto importante: può allineare lo scopo alla sintassi, rendendo più facile condividere e utilizzare le cose nei team. Ecco alcune query personalizzate sui contenuti multimediali che seguo tra i progetti:
@custom-media --OSdark (prefers-color-scheme: dark);
@custom-media --OSlight (prefers-color-scheme: light);
@custom-media --pointer (hover) and (pointer: coarse);
@custom-media --mouse (hover) and (pointer: fine);
@custom-media --xxs-and-above (width >= 240px);
@custom-media --xxs-and-below (width <= 240px);
Ora che sono definiti, posso usarne uno in questo modo:
@media (--OSdark) {
:root {
…
}
}
Trova un elenco completo di query personalizzate per i media che utilizzo all'interno della mia libreria di proprietà personalizzate CSS Open Props.
Risorse
L'annidamento dei selettori è molto utile
Prima di @nest
, c'era molta ripetizione nei fogli di stile. È diventato
particolarmente ingombrante quando i selettori erano lunghi e ognuno aveva come target piccole
differenze. La comodità dell'annidamento è uno dei motivi più comuni per
adottare un preprocessor.
Dopo @nest
, la ripetizione non è più disponibile. Quasi tutte le funzionalità
dell'annidamento abilitato al preprocessor saranno disponibili integrate nel CSS.
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
Ciò che mi interessa di più dell'annidamento, oltre a non ripetere article
nel selettore annidato, è che il contesto di stile rimanga all'interno di un blocco di stile.
Anziché passare da un selettore e dai relativi stili a un altro selettore con stili (esempio 1), il lettore può rimanere nel contesto di un articolo e vedere i link di proprietà dell'articolo al suo interno. L'intento di relazione e stile sono
raggruppati, quindi article
sembra avere i propri stili.
La proprietà può anche essere considerata come centralizzazione. Invece di cercare in un foglio di stile gli stili pertinenti, possono essere trovati tutti nidificati insieme all'interno di un contesto. Questo funziona con le relazioni genitore-figlio, ma anche con le relazioni figlio-genitore.
Considera un componente secondario che vuole adattarsi quando si trova in un contesto principale diverso, anziché il componente principale che possiede lo stile e modifica un componente secondario:
/* parent owns this, adjusting children */
section:focus-within > article {
border: 1px solid hotpink;
}
/* with @nest becomes */
/* article owns this, adjusting itself when inside a section:focus-within */
article {
@nest section:focus-within > & {
border: 1px solid hotpink;
}
}
@nest
contribuisce a organizzare, centralizzare e gestire meglio gli stili. I componenti possono raggruppare e possedere i propri stili, anziché
distribuirli tra altri blocchi di stili. Può sembrare una piccola cosa in questi esempi, ma può avere un impatto molto grande, sia per comodità che per leggibilità.
Risorse
Definire gli stili è molto difficile
Prima di @scope
, esistevano molte strategie perché gli stili in CSS vengono applicati a cascata, ereditati
e hanno ambito globale per impostazione predefinita. Queste funzionalità di CSS sono molto utili
per molte cose, ma per siti e applicazioni complessi, con potenzialmente molti
stili diversi di componenti, lo spazio globale e la natura della cascata possono
far sembrare che gli stili perdano efficacia.
Dopo @scope
, gli stili non solo possono essere limitati a un contesto, ad esempio una
classe, ma possono anche indicare dove terminano e non continuano a
essere applicati a cascata o ereditati.
Nell'esempio seguente, l'ambito della convenzione di denominazione BEM può essere invertito nell'intento effettivo. Il selettore BEM tenta
di definire l'ambito del colore di un elemento header
in un contenitore .card
con convenzioni
di denominazione. Per completare l'obiettivo, l'intestazione deve contenere questo nome classe. Con @scope
, non sono necessarie convenzioni di denominazione per completare
lo stesso obiettivo senza contrassegnare l'elemento di intestazione:
.card__header {
color: var(--text);
}
/* with @scope becomes */
@scope (.card) {
header {
color: var(--text);
}
}
Ecco un altro esempio, meno specifico per i componenti e più incentrato sulla natura
dell'ambito globale di CSS. I temi scuro e chiaro devono coesistere all'interno di un foglio di stile, in cui
l'ordine è importante per determinare uno stile vincente. In genere, gli stili del tema scuro
vengono dopo quelli del tema chiaro, che viene impostato come predefinito
e il tema scuro come stile facoltativo. Evita la battaglia per l'ordine e l'ambito con @scope
:
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
Per completare la storia qui, @scope
consente anche di stabilire dove termina l'ambito dello stile. Questa operazione non può essere eseguita con alcuna convenzione di denominazione o preprocessor;
è speciale e può essere eseguita solo con CSS integrati nel browser. Nell'esempio
seguente, gli stili img
e .content
vengono applicati esclusivamente quando un
elemento secondario di un .media-block
è un elemento di pari livello o principale di .content
:
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
Risorse
Nessun modo CSS per un layout a griglia
Prima di CSS masonry con griglia, JavaScript era il modo migliore per ottenere un layout a griglia, poiché qualsiasi metodo CSS con colonne o flexbox avrebbe rappresentato in modo impreciso l'ordine dei contenuti.
Dopo CSS masonry con griglia, non saranno necessarie librerie JavaScript e l'ordine dei contenuti sarà corretto.

https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/
La demo precedente viene ottenuta con il seguente CSS:
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
È confortante sapere che questa strategia di layout mancante è in fase di valutazione. Inoltre, puoi provarla oggi in Firefox.
Risorse
- Specifica del layout a griglia
- Layout a griglia su MDN
- Smashing Magazine: Native CSS Masonry Layout with CSS Grid
Il CSS non può aiutare gli utenti a ridurre i dati
Prima della media query prefers-reduced-data
, JavaScript e un server potevano
modificare il proprio comportamento in base all'opzione "Risparmio dati" del sistema operativo o del browser di un utente, ma CSS non poteva.
Dopo la query multimediale prefers-reduced-data
, CSS può contribuire al miglioramento dell'esperienza utente
e svolgere il suo ruolo nel risparmio di dati.
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
Il CSS precedente viene utilizzato in questo componente
di scorrimento dei contenuti multimediali e i risparmi
possono essere enormi. A seconda delle dimensioni dell'area visibile visitata, maggiore è il risparmio
sul caricamento della pagina. Il salvataggio continua mentre gli utenti interagiscono con gli
scorrimento dei contenuti multimediali. Le immagini hanno tutte attributi loading="lazy"
e, se combinati con il CSS che nasconde completamente l'elemento, non viene mai effettuata una richiesta di rete per l'immagine.
Per i miei test, in un'area visibile di medie dimensioni sono state caricate inizialmente 40 richieste e 700 KB di risorse. Man mano che l'utente scorre la selezione dei contenuti multimediali, vengono caricati più richieste e risorse. Con CSS e la media query per la riduzione dei dati, vengono caricate 10 richieste e 172 KB di risorse. Si tratta di un risparmio di mezzo megabyte e l'utente non ha ancora scorri nessuno dei contenuti multimediali, a quel punto non vengono effettuate richieste aggiuntive.
Questa esperienza con dati ridotti offre più vantaggi del semplice risparmio di dati. Puoi vedere più titoli e non ci sono copertine che distraggono. Molti utenti navigano in modalità Risparmio dati perché pagano a megabyte di dati. È davvero bello vedere che CSS può essere d'aiuto in questo caso.
Risorse
- specifica prefers-reduced-data
- prefers-reduced-data su MDN
- prefers-reduced-data in una GUI Sfida
- Smashing Magazine: Improving Core Web Vitals, A Smashing Magazine Case Study
Le funzionalità di scorrimento controllato sono troppo limitate
Prima di queste proposte di scorrimento agganciato, scrivere il proprio JavaScript per gestire un carosello, un cursore o una galleria poteva diventare rapidamente complesso, con tutti gli osservatori e la gestione dello stato. Inoltre, se non si presta attenzione, le velocità di scorrimento naturale potrebbero essere normalizzate dallo script, rendendo l'interazione dell'utente un po' innaturale e potenzialmente goffa.
Nuove API
snapChanging()
Questo evento viene attivato non appena il browser rilascia un elemento figlio dello snap. Ciò consente all'interfaccia utente di riflettere la mancanza di uno snap figlio e lo stato di snap indeterminato dello scroller, poiché ora viene utilizzato e si fermerà in una nuova posizione.
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
Questo evento viene attivato non appena il browser si sposta su un nuovo elemento figlio e lo scorrimento si arresta. In questo modo, qualsiasi UI che dipende dal bambino agganciato viene aggiornata e riflette la connessione.
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => {
console.log('Snap changed', event.snappedTargetsList);
});
scroll-start
Lo scorrimento non inizia sempre dall'inizio. Prendi in considerazione i componenti scorrevoli in cui lo scorrimento verso sinistra o destra attiva eventi diversi oppure una barra di ricerca che al caricamento della pagina è inizialmente nascosta finché non scorri verso l'alto. Questa proprietà CSS consente agli sviluppatori di specificare che uno scorrimento deve iniziare da un punto specifico.
:root { --nav-height: 100px }
.snap-scroll-y {
scroll-start-y: var(--nav-height);
}
:snap-target
Questo selettore CSS corrisponderà agli elementi di un contenitore di scorrimento attualmente agganciati dal browser.
.card {
--shadow-distance: 5px;
box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%);
transition: box-shadow 350ms ease;
}
.card:snapped {
--shadow-distance: 30px;
}
Dopo queste proposte di scorrimento rapido, creare un cursore, un carosello o una galleria è molto più semplice, poiché il browser ora offre comodità per l'attività, eliminando gli osservatori e il codice di orchestrazione dello scorrimento a favore dell'utilizzo di API integrate.
Siamo ancora agli albori di queste funzionalità CSS e JS, ma tieni d'occhio i polyfill che possono contribuire alla loro adozione e al loro test a breve.
Risorse
Ciclo tra gli stati noti
Prima del giorno toggle()
, per lo stile e l'interazione potevano essere utilizzati solo gli stati integrati nel browser. L'input della casella di controllo, ad esempio, ha :checked
, uno
stato del browser gestito internamente per l'input che CSS può utilizzare per
modificare visivamente l'elemento.
Dopo il giorno toggle()
, è possibile creare stati personalizzati su qualsiasi elemento per consentire al CSS di modificarli
e utilizzarli per lo stile. Consente di raggruppare, pedalare, attivare/disattivare in modo mirato e altro ancora.
Nell'esempio seguente, lo stesso effetto di una riga barrata in un elenco viene ottenuto senza alcun elemento di casella di controllo:
<ul class='ingredients'>
<li>1 banana
<li>1 cup blueberries
...
</ul>
e gli stili CSS toggle()
pertinenti:
li {
toggle-root: check self;
}
li:toggle(check) {
text-decoration: line-through;
}
Se hai familiarità con le macchine a stati, potresti notare quanto si sovrappongono a toggle()
. Questa funzionalità consentirà agli sviluppatori di integrare più stati nel CSS, con la speranza di ottenere modi più chiari e semantici di orchestrare l'interazione e lo stato.
Risorse
Personalizzare gli elementi di selezione
Prima di <selectmenu>
, CSS non aveva la possibilità di personalizzare gli elementi <option>
con HTML avanzato o modificare molti aspetti della visualizzazione di un elenco di opzioni.
Ciò ha portato gli sviluppatori a caricare librerie esterne che ricreavano gran parte delle funzionalità di un <select>
, il che si è rivelato un lavoro molto impegnativo.
Dopo il giorno <selectmenu>
, gli sviluppatori possono fornire HTML avanzato per gli elementi delle opzioni e
applicare lo stile che preferiscono, rispettando comunque i requisiti di accessibilità
e fornendo HTML semantico.
Nell'esempio seguente, tratto dalla <selectmenu>
pagina
esplicativa, viene creato un nuovo menu
di selezione con alcune opzioni di base:
<selectmenu>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>
CSS può scegliere come target e applicare uno stile alle parti dell'elemento:
.my-select-menu::part(button) {
color: white;
background-color: red;
padding: 5px;
border-radius: 5px;
}
.my-select-menu::part(listbox) {
padding: 10px;
margin-top: 5px;
border: 1px solid red;
border-radius: 5px;
}
Puoi provare l'elemento <selectmenu>
su Chromium in Canary con il flag web
experiments attivato. Nel 2023 e negli anni successivi, saranno disponibili elementi del menu di selezione personalizzabili.
Risorse
Ancorare un elemento a un altro
Prima di anchor()
, le posizioni assoluta e relativa erano strategie di posizionamento
fornite agli sviluppatori per spostare gli elementi secondari all'interno di un elemento
principale.
Dopo anchor()
, gli sviluppatori possono posizionare gli elementi rispetto ad altri elementi, indipendentemente
dal fatto che siano secondari o meno. Consente inoltre agli sviluppatori di specificare il bordo rispetto al quale posizionare gli elementi e altre funzionalità per creare relazioni di posizione tra gli elementi.
La spiegazione include alcuni ottimi esempi e campioni di codice, se ti interessa saperne di più.