È possibile associare all'attributo lingua una sola lingua. Ciò significa che l'attributo <html>
può avere una sola lingua, anche se nella pagina sono presenti più lingue. Imposta lang
come lingua principale della pagina.
<html lang="ar,en,fr,pt">...</html>Non sono supportate più lingue.
<html lang="ar">...</html>Imposta solo la lingua principale della pagina. In questo caso, la lingua è l'arabo.
Link
Analogamente ai pulsanti, i link prendono il nome accessibile principalmente dai contenuti testuali. Un bel trucco durante la creazione di un link è quello di inserire la parte di testo più significativa nel link stesso, invece di parole intercalari come "Qui" o "Leggi di più".
Check out our guide to web performance <a href="/guide">here</a>.
Check out <a href="/guide">our guide to web performance</a>.
Controllare se un'animazione attiva il layout
Un'animazione che sposta un elemento utilizzando un elemento diverso da transform
è probabilmente lenta.
Nell'esempio seguente, ho ottenuto lo stesso risultato visivo animando top
e left
e utilizzando transform
.
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { top: calc(90vh - 160px); left: calc(90vw - 200px); } }
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { transform: translate(calc(90vw - 200px), calc(90vh - 160px)); } }
Puoi testarlo nei due esempi di Glitch seguenti ed esplorare le prestazioni con DevTools.
Con lo stesso markup, possiamo sostituire: padding-top: 56.25%
con aspect-ratio: 16 / 9
, impostando
aspect-ratio
su un rapporto specificato di width
/ height
.
.container { width: 100%; padding-top: 56.25%; }
.container { width: 100%; aspect-ratio: 16 / 9; }
L'utilizzo di aspect-ratio
invece di padding-top
è molto più chiaro e non modifica la proprietà di spaziatura interna
per eseguire operazioni al di fuori del suo ambito abituale.
Sì, esatto, sto usando reduce
per concatenare una sequenza di promesse. Sono così intelligente. Ma si tratta di una programmazione un po' così intelligente che non farei meglio.
Tuttavia, quando si converte quanto sopra in una funzione asincrona, si potrebbe avere la tentazione di passare troppo in sequenza:
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }Sembra molto più ordinato, ma il secondo recupero non inizia finché il primo recupero non è stato letto completamente e così via. Questo è molto più lento dell'esempio di promesse che esegue i recuperi in parallelo. Per fortuna c'è una via di mezzo ideale.
function markHandled(...promises) { Promise.allSettled(promises); } async function logInOrder(urls) { // fetch all the URLs in parallel const textPromises = urls.map(async (url) => { const response = await fetch(url); return response.text(); }); markHandled(...textPromises); // log them in sequence for (const textPromise of textPromises) { console.log(await textPromise); } }In questo esempio, gli URL vengono recuperati e letti in parallelo, ma il bit
reduce
"intelligente" viene sostituito con un ciclo for standard, noioso e leggibile.
Scrittura di proprietà personalizzate Houdini
Ecco un esempio di impostazione di una proprietà personalizzata (ad esempio, una variabile CSS), ma ora con una sintassi (tipo), un valore iniziale (di riserva) e un'ereditarietà booleana (eredita o meno il valore dal relativo valore principale?). Al momento per farlo è tramite CSS.registerProperty()
in JavaScript, ma in Chromium 85 e versioni successive la sintassi @property
sarà supportata nei file CSS:
CSS.registerProperty({ name: '--colorPrimary', syntax: '', initialValue: 'magenta', inherits: false });
@property --colorPrimary { syntax: ''; initial-value: magenta; inherits: false; }
Ora puoi accedere a --colorPrimary
come a qualsiasi altra proprietà personalizzata CSS, tramite
var(--colorPrimary)
. Tuttavia, qui la differenza è che --colorPrimary
non viene
letto solo come una stringa. Ha dei dati!
Il CSS backdrop-filter
applica uno o più effetti a un elemento traslucido o trasparente. Per comprendere questo concetto, considera le seguenti immagini.
![Un triangolo sovrapposto a un cerchio. Il cerchio non è visibile attraverso il triangolo.](https://web.developers.google.cn/static/examples/image/admin/LOqxvB3qqVkbZBmxMmKS.png?hl=it)
.frosty-glass-pane { backdrop-filter: blur(2px); }
![Un triangolo sovrapposto a un cerchio. Il triangolo è traslucido e consente di vedere il cerchio attraverso di esso.](https://web.developers.google.cn/static/examples/image/admin/VbyjpS6Td39E4FudeiVg.png?hl=it)
.frosty-glass-pane { opacity: .9; backdrop-filter: blur(2px); }
L'immagine a sinistra mostra come gli elementi sovrapposti verrebbero visualizzati se backdrop-filter
non fossero utilizzati o supportati. L'immagine a destra applica un effetto di sfocatura utilizzando backdrop-filter
. Tieni presente che utilizza opacity
oltre a backdrop-filter
. Senza opacity
, non ci sarebbe nulla a cui applicare la sfocatura. È quasi inutile dire che se opacity
è impostato su 1
(completamente opaco) non ci sarà alcun effetto sullo sfondo.
A differenza dell'evento unload
, tuttavia, esistono utilizzi legittimi di
beforeunload
. Ad esempio, se vuoi avvisare l'utente che ha
modifiche non salvate, perderà se lascia la pagina. In questo caso, ti consigliamo di aggiungere i listener beforeunload
solo quando un utente ha modifiche non salvate e di rimuoverli immediatamente dopo il salvataggio delle modifiche non salvate.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });Il codice riportato sopra aggiunge un listener
beforeunload
incondizionatamente.
function beforeUnloadListener(event) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; }; // A function that invokes a callback when the page has unsaved changes. onPageHasUnsavedChanges(() => { window.addEventListener('beforeunload', beforeUnloadListener); }); // A function that invokes a callback when the page's unsaved changes are resolved. onAllChangesSaved(() => { window.removeEventListener('beforeunload', beforeUnloadListener); });Il codice riportato sopra aggiunge il listener
beforeunload
solo quando è necessario (e
lo rimuove quando non è necessario).
Riduci al minimo l'utilizzo di Cache-Control: no-store
Cache-Control: no-store
è un'intestazione HTTP che i server web possono impostare su risposte che indicano al browser di non memorizzare la risposta in nessuna cache HTTP. Deve essere utilizzato per le risorse contenenti informazioni sensibili sull'utente, ad esempio le pagine protette da login.
L'elemento fieldset
, che contiene ogni gruppo di input (.fieldset-item
), utilizza gap: 1px
per
creare i bordi sottili tra gli elementi. Nessuna complicata soluzione per i bordi.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Aggregazione a griglia naturale
Il layout più complesso è stato quello della macro, il sistema di layout logico tra <main>
e <form>
.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
L'elemento fieldset
, che contiene ogni gruppo di input (.fieldset-item
), utilizza gap: 1px
per
creare i bordi sottili tra gli elementi. Nessuna complicata soluzione per i bordi.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Layout schede <header>
Il layout successivo è praticamente lo stesso: uso Flex per creare l'ordinamento verticale.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
L'elemento .snap-indicator
deve spostarsi orizzontalmente con il gruppo di link e questo layout di intestazione consente di impostare questa fase. Non ci sono elementi con posizione assoluta qui.
Gentle Flex è una strategia più vera per l'unica centratura. È morbido e delicato perché, a differenza di place-content: center
, le dimensioni della scatola dei bambini non vengono modificate durante la centratura. Gli elementi vengono impilati, centrati e distanziati nel modo più delicato possibile.
.gentle-flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1ch;
}
- Gestisce solo allineamento, direzione e distribuzione
- Le modifiche e la manutenzione sono tutte in un unico posto
- Il divario garantisce la stessa spaziatura tra n figli
- La maggior parte delle righe di codice
Ideale per layout macro e micro.
Utilizzo
gap
accetta qualsiasi length o percentuale CSS come valore.
.gap-example {
display: grid;
gap: 10px;
gap: 2ch;
gap: 5%;
gap: 1em;
gap: 3vmax;
}
L'intervallo può essere superato di 1 lunghezza, che verrà utilizzata sia per la riga che per la colonna.
.grid { display: grid; gap: 10px; }Imposta insieme righe e colonne
.grid { display: grid; row-gap: 10px; column-gap: 10px; }
L'intervallo può essere superato di 2 lunghezze, che verranno utilizzate per riga e colonna.
.grid { display: grid; gap: 10px 5%; }Imposta righe e colonne separatamente contemporaneamente
.grid { display: grid; row-gap: 10px; column-gap: 5%; }