Confronta e compareCaption

È 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.

Cosa non fare
<html lang="ar,en,fr,pt">...</html>
Non sono supportate più lingue.
Cosa fare
<html lang="ar">...</html>
Imposta solo la lingua principale della pagina. In questo caso, la lingua è l'arabo.

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ù".

Non sufficientemente descrittiva
Check out our guide to web performance <a href="/guide">here</a>.
Contenuti utili.
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.

Cosa non fare
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
Cosa fare
.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.

Utilizzo della spaziatura interna
.container {
  width: 100%;
  padding-top: 56.25%;
}
Utilizzo delle proporzioni
.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:

Opzione sconsigliata: troppo sequenziale
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.
Consigliato - interessante e parallelo
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:

File JavaScript separato (Chromium 78)
CSS.registerProperty({
  name: '--colorPrimary',
  syntax: '',
  initialValue: 'magenta',
  inherits: false
});
Incluso nel file CSS (Chromium 85)
@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.

Nessuna trasparenza in primo piano
Un triangolo sovrapposto a un cerchio. Il cerchio non è visibile attraverso il triangolo.
.frosty-glass-pane {
  backdrop-filter: blur(2px);
}
Trasparenza primo piano
Un triangolo sovrapposto a un cerchio. Il triangolo è traslucido e consente di vedere il cerchio attraverso di esso.
.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.

Cosa non fare
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.
Cosa fare
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.

Spazio vuoto
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Trucco dei bordi
.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
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
etichetta
<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.

Spazio vuoto
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Trucco dei bordi
.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.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
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;
}
Vantaggi
  • 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
Svantaggi
  • 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.

Sintesi
.grid {
  display: grid;
  gap: 10px;
}
Imposta insieme righe e colonne
Nodo espanso
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 10px;
}


L'intervallo può essere superato di 2 lunghezze, che verranno utilizzate per riga e colonna.

Sintesi
.grid {
  display: grid;
  gap: 10px 5%;
}
Imposta righe e colonne separatamente contemporaneamente
Nodo espanso
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 5%;
}