Porównaj & PorównajCaption

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

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

Podobnie jak przyciski, nazwa linku pochodzi głównie z tekstu. Przy tworzeniu linku warto umieścić w nim najistotniejszy fragment tekstu, zamiast używać takich słów jak „tutaj” czy „Czytaj więcej”.

Za mało opisowe
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 uruchamia układ

Animacja, która porusza element za pomocą funkcji innego niż transform, prawdopodobnie będzie wolna. W poniższym przykładzie taki sam efekt daje animowanie elementów top i left oraz 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 przetestować ten mechanizm w 2 przykładach Usterek i sprawdzić wydajność za pomocą Narzędzi deweloperskich.

Tymi samymi znacznikami możemy zastąpić: padding-top: 56.25% elementem aspect-ratio: 16 / 9, ustawiając aspect-ratio z określonym współczynnikiem width / height.

Korzystanie z dopełnienia na górze
.container {
  width: 100%;
  padding-top: 56.25%;
}
Korzystanie ze współczynnika proporcji
.container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Użycie właściwości aspect-ratio zamiast padding-top jest znacznie bardziej przejrzyste i nie powoduje modernizacji właściwości dopełnienia na potrzeby wykraczające poza zwykły zakres.

Zgadza się. Używam funkcji reduce do łączenia sekwencji obietnic. Jestem takim mądrym. Jednak bez takiego kodowania radzisz sobie z bardzo inteligentnym kodowaniem.

Jednak podczas konwertowania powyższych funkcji na funkcję asynchroniczną można chcieć wykonać zbyt sekwencyjną czynność:

Niezalecane – zbyt sekwencyjne
async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
Wygląda znacznie lepiej, ale drugie pobieranie nie rozpocznie się, dopóki pierwsze nie zostanie w pełni odczytane itd. Trwa to znacznie wolniej niż w przykładzie obiecującym, który wykonuje pobieranie równoległe. Na szczęście istnieje idealny środek pośredni.
Zalecane – prawidłowe 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 odczytywane równolegle, ale „inteligentny” bit reduce został zastąpiony standardowym, nudnym i czytelnym elementem pętli.

Zapisywanie właściwości niestandardowych Houdini

Oto przykład ustawienia właściwości niestandardowej (np. zmiennej CSS), ale ze składnią (typ), wartością początkową (zastępczą) i wartością logiczną dziedziczenia (dziedziczenie wartości z elementu nadrzędnego czy nie). Obecnie można to zrobić za pomocą metody CSS.registerProperty() w JavaScript, ale w Chromium w wersji 85 i nowszych pliki CSS będą obsługiwać składnię @property:

Oddzielny plik JavaScript (Chromium 78)
CSS.registerProperty({
  name: '--colorPrimary',
  syntax: '',
  initialValue: 'magenta',
  inherits: false
});
Uwzględnione w pliku CSS (Chromium 85)
@property --colorPrimary {
  syntax: '';
  initial-value: magenta;
  inherits: false;
}

Teraz możesz uzyskać dostęp do właściwości --colorPrimary w usłudze var(--colorPrimary), tak jak do każdej innej właściwości niestandardowej CSS. Różnica polega jednak na tym, że element --colorPrimary nie jest tylko odczytywany jako ciąg znaków. Mamy dane!

CSS backdrop-filter stosuje co najmniej 1 efekt do elementu, który jest pół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 widoczne w trójkącie.
.frosty-glass-pane {
  backdrop-filter: blur(2px);
}
Przejrzystość na pierwszym planie
Trójkąt nałożony na okrąg. Trójkąt jest półprzezroczysty, przez co można przez niego dostrzec okrąg.
.frosty-glass-pane {
  opacity: .9;
  backdrop-filter: blur(2px);
}

Obraz po lewej stronie pokazuje, jak zostałyby wyrenderowane nakładające się elementy, gdyby elementy backdrop-filter nie były używane ani obsługiwane. Na obrazie po prawej stronie zastosowano efekt rozmycia za pomocą funkcji backdrop-filter. Zwróć uwagę, że oprócz backdrop-filter używa ona opacity. Bez opacity nie można byłoby zamazywać. Jeśli zasada opacity ma ustawienie 1 (pełne nieprzezroczystość), nie będzie to miało żadnego wpływu na tło.

Istnieją jednak dozwolone przypadki użycia właściwości beforeunload (w przeciwieństwie do zdarzenia unload). Jeśli na przykład chcesz ostrzec użytkownika, że ma niezapisane zmiany, utraci on dostęp, jeśli opuści stronę. W takim przypadku zalecamy dodanie detektorów beforeunload tylko wtedy, gdy użytkownik ma niezapisane zmiany, a potem usunięcie 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?';
  }
});
Powyższy kod bezwarunkowo dodaje odbiornik 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);
});
Kod powyżej dodaje odbiornik beforeunload tylko wtedy, gdy jest potrzebny (i usuwa go, gdy jest niepotrzebny).

Ogranicz korzystanie z Cache-Control: no-store

Cache-Control: no-store to nagłówek HTTP, który serwery WWW mogą ustawiać w odpowiedziach, informuje przeglądarkę, że ma nie zapisywać odpowiedzi w żadnej pamięci podręcznej HTTP. Tego formatu należy używać w przypadku zasobów zawierających poufne dane użytkownika, np. stron wymagających logowania.

Element fieldset, który zawiera każdą grupę danych wejściowych (.fieldset-item), używa właściwości gap: 1px do tworzenia linii obramowania między elementami. Brak trudnego rozwiązania granicznego!

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

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Sztuczka na granicy
.grid {
  display: grid;

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

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

Naturalne zawijanie siatki

Najbardziej złożonym układem był układ makro, czyli układ logiczny między <main> a <form>.

dane wejściowe
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
label
<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 właściwości gap: 1px do tworzenia linii obramowania między elementami. Brak trudnego rozwiązania granicznego!

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

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Sztuczka na granicy
.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>

Następny układ jest prawie taki sam: do tworzenia kolejności pionowej używam elastycznego.

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 przemieszczać się wraz z grupą linków w poziomie. Ten układ nagłówka pomaga w ustawieniu tej sceny. Brak elementów w pozycji bezwzględnej.

Gentle Flex to bardziej prawdziwa strategia ukierunkowana tylko na wyśrodkowanie. Jest miękki i delikatny, ponieważ w przeciwieństwie do place-content: center rozmiar pudełka dla dzieci nie zmienia się podczas wyśrodkowania. Wszystkie elementy są ułożone w stos, wyśrodkowane i rozmieszczone tak delikatnie, jak to możliwe.

.gentle-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1ch;
}
Zalety
  • Obsługa tylko wyrównywania, kierunku i rozkładu
  • Zmiany i konserwacja w jednym miejscu
  • Luka gwarantuje równe odstępy między n dzieci
Wady
  • Większość wierszy kodu

Świetnie sprawdza się w przypadku układów makro i mikro.

Wykorzystanie

gap akceptuje dowolną długość lub percentage CSS jako wartość.

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


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

Skrót klawiaturowy
.grid {
  display: grid;
  gap: 10px;
}
Ustawianie razy jednocześnie wierszy i kolumn
Rozwinięto
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 10px;
}


Luki można przekazywać na 2 różne długości, które będą używane w przypadku wiersza i kolumny.

Skrót klawiaturowy
.grid {
  display: grid;
  gap: 10px 5%;
}
Ustawiaj wiersze i kolumny oddzielnie naraz
Rozwinięto
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 5%;
}