Porównaj & PorównajCaption

Z atrybutem lang można powiązać tylko jeden język. Oznacza to, że atrybut <html> może mieć tylko jeden język, nawet jeśli na stronie jest ich więcej. Ustaw lang jako język główny strony.

Nie
<html lang="ar,en,fr,pt">...</html>
Wiele języków nie jest obsługiwanych.
Tak
<html lang="ar">...</html>
Ustaw tylko język główny strony. W tym przypadku jest to język arabski.

Podobnie jak w przypadku przycisków, nazwy dostępnych linków pochodzą głównie z ich tekstu. Podczas tworzenia linku warto umieścić w nim najbardziej istotny fragment tekstu, zamiast słów wypełniających, takich jak „Tutaj” czy „Więcej informacji”.

Niewystarczająco szczegółowe
Check out our guide to web performance <a href="/guide">here</a>.
Przydatne treści
Check out <a href="/guide">our guide to web performance</a>.

Sprawdzanie, czy animacja powoduje wyświetlenie układu

Animacja, która przesuwa element za pomocą czegoś innego niż transform, będzie prawdopodobnie działać wolno. W tym przykładzie uzyskałem ten sam efekt wizualny, animując elementy topleft za pomocą elementu transform.

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

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
Tak
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     transform: translate(calc(90vw - 200px), calc(90vh - 160px));
  }
}

Możesz to przetestować w 2 przykładach Glitcha poniżej i zbadać wydajność za pomocą Narzędzi deweloperskich.

Przy użyciu tego samego znacznika możemy zastąpić: padding-top: 56.25% przez aspect-ratio: 16 / 9, ustawiając aspect-ratio na określony współczynnik width / height.

Używanie atrybutu padding-top
.container {
  width: 100%;
  padding-top: 56.25%;
}
Korzystanie z formatu obrazu
.container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Użycie aspect-ratio zamiast padding-top jest znacznie bardziej przejrzyste i nie wymaga przebudowy właściwości padding, aby robić coś poza jej zwykłym zakresem.

Tak, używam reduce do łańcucha obietnic. Jestem tak smart. To jednak bardzo sprytny kod, z którego lepiej zrezygnować.

Jednak podczas konwertowania powyższego kodu na funkcję asynchroniczną łatwo jest użyć zbyt sekwencyjnego podejścia:

Nie zalecane – zbyt sekwencyjne
async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
Wygląda to znacznie lepiej, ale drugie pobieranie rozpocznie się dopiero po zakończeniu pierwszego, i tak dalej. Jest to znacznie wolniejsze niż przykład z obietnic, który wykonuje pobieranie w drodze równoległej. Na szczęście istnieje idealny kompromis.
Zalecane – ładne i równoległe
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);
  }
}
W tym przykładzie adresy URL są pobierane i czytane równolegle, ale element „smart” reduce został zastąpiony standardowym, nudnym, czytelnym pętlą for.

Pisanie właściwości niestandardowych Houdini

Oto przykład ustawienia właściwości niestandardowej (np. zmiennej CSS) z składnią (typem), wartością początkową (zastępczą) i wartością logiczną dziedziczenia (czy ma dziedziczyć wartość z elementu nadrzędnego, czy nie). Obecnie można to zrobić za pomocą funkcji CSS.registerProperty() w JavaScript, ale w Chromium 85 i nowszych wersjach obsługiwana będzie też składnia @property w plikach CSS:

Oddzielny plik JavaScript (Chromium 78)
CSS.registerProperty({
  name: '--colorPrimary',
  syntax: '',
  initialValue: 'magenta',
  inherits: false
});
Dołączony do pliku CSS (Chromium 85)
@property --colorPrimary {
  syntax: '';
  initial-value: magenta;
  inherits: false;
}

Teraz możesz uzyskać dostęp do właściwości --colorPrimary, tak jak do dowolnej innej właściwości niestandardowej usługi porównywania cen, za pomocą funkcji var(--colorPrimary). Różnica polega na tym, że --colorPrimary nie jest odczytywany tylko jako ciąg znaków. Zawiera dane.

CSS backdrop-filter stosuje co najmniej 1 efekt do elementu, który jest półprzezroczysty lub przezroczysty. Aby to zrozumieć, spójrz na poniższe obrazy.

Brak przezroczystości pierwszego planu
Trójkąt nałożony na okrąg. Okrąg nie jest widoczny przez trójkąt.
.frosty-glass-pane {
  backdrop-filter: blur(2px);
}
Przezroczystość pierwszego planu
Trójkąt nałożony na okrąg. Trójkąt jest półprzezroczysty, dzięki czemu przez niego widać okrąg.
.frosty-glass-pane {
  opacity: .9;
  backdrop-filter: blur(2px);
}

Obraz po lewej stronie pokazuje, jak renderowane byłyby nakładające się elementy, gdyby backdrop-filter nie było używane lub nie było obsługiwane. Obraz po prawej stronie zawiera efekt rozmycia za pomocą narzędzia backdrop-filter. Zwróć uwagę, że oprócz backdrop-filter używa ona także backdrop-filter.opacity Bez opacity nie można byłoby zastosować rozmycie. Nie trzeba chyba dodawać, że jeśli parametr opacity ma wartość 1 (pełna przezroczystość), tło nie będzie miało żadnego wpływu.

W odróżnieniu od zdarzenia unload zdarzenie beforeunload może być jednak używane w uzasadnionych celach. Możesz to zrobić na przykład wtedy, gdy chcesz ostrzec użytkownika, że po opuszczeniu strony utraci niezapisane zmiany. W takim przypadku zalecamy dodawanie odbiorców beforeunload tylko wtedy, gdy użytkownik ma niezapisana zmiany, a następnie usuwanie ich natychmiast po zapisaniu niezapisanych zmian.

Nie
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
Kod powyżej bezwarunkowo dodaje słuchacza beforeunload.
Tak
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);
});
Powyższy kod dodaje tylko listenera beforeunload, gdy jest to potrzebne (i usuwa go, gdy nie jest potrzebny).

Zminimalizuj wykorzystanie Cache-Control: no-store

Cache-Control: no-store to nagłówek HTTP, który serwery internetowe mogą ustawiać w odpowiedziach, aby poinformować przeglądarkę, że nie powinna przechowywać odpowiedzi w żadnym pamięci podręcznej HTTP. Należy go używać w przypadku zasobów zawierających poufne informacje o użytkownikach, np. stron wymagających logowania.

Element fieldset, który zawiera każdą grupę danych wejściowych (.fieldset-item), używa elementu gap: 1px do tworzenia cienkich linii oddzielających elementy. Nie ma trudnego rozwiązania dotyczącego granicy.

Wypełniona luka
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Trik z obramowaniem
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Zawijanie do siatki

Najbardziej skomplikowanym układem okazał się makroukład, czyli układ logiczny w systemie <main><form>.

dane wejściowe
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
etykieta
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

Element fieldset, który zawiera każdą grupę danych wejściowych (.fieldset-item), używa elementu gap: 1px do tworzenia cienkich linii oddzielających elementy. Nie ma trudnego rozwiązania dotyczącego granicy.

Wypełniona luka
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Trik z ramką
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Układ kart <header>

Kolejny układ jest prawie taki sam: do tworzenia układu pionowego używam elementu flex.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

Element .snap-indicator powinien przesuwać się poziomo wraz z grupą linków, a ta opcja układu nagłówka pomaga w tym zadaniu. Nie ma tu elementów z pozycji bezwzględnej.

Delikatne dostosowanie to strategia polegająca na prawdziwym wyśrodkowywaniu tylko. Jest ona łagodna i delikatna, ponieważ w przeciwieństwie do place-content: center podczas wyśrodkowywania nie zmienia się rozmiarów pudełek z zabawkami. Wszystkie elementy są ułożone w stosie, wyśrodkowane i oddalone od siebie w jak najbardziej delikatny sposób.

.gentle-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1ch;
}
Zalety
  • Obsługuje tylko wyrównywanie, kierowanie i dystrybucję.
  • Edycje i utrzymanie w jednym miejscu
  • Przerwa zapewnia równe odstępy między n dziećmi
Wady
  • Najwięcej wierszy kodu

Doskonale nadają się zarówno do układów makro, jak i mikro.

Wykorzystanie

gap może mieć dowolną wartość length lub percentage w CSS.

.gap-example {
  display: grid;
  gap: 10px;
  gap: 2ch;
  gap: 5%;
  gap: 1em;
  gap: 3vmax;
}


Odstęp może mieć długość 1, która będzie używana zarówno w wierszu, jak i kolumnie.

Skróty
.grid {
  display: grid;
  gap: 10px;
}
Ustaw jednocześnie wiersze i kolumny razem
Rozwinięto
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 10px;
}


Przerwa może mieć 2 długości, które będą używane w wierszu i kolumnie.

Skróty
.grid {
  display: grid;
  gap: 10px 5%;
}
Ustaw jednocześnie wiersze i kolumny osobno
Rozwinięto
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 5%;
}