Bandingkan & BandingkanTeks

Atribut lang hanya dapat memiliki satu bahasa yang terkait dengannya. Artinya, atribut <html> hanya dapat memiliki satu bahasa, meskipun ada beberapa bahasa di halaman. Tetapkan lang ke bahasa utama halaman.

Larangan
<html lang="ar,en,fr,pt">...</html>
Beberapa bahasa tidak didukung.
Anjuran
<html lang="ar">...</html>
Tetapkan hanya bahasa utama halaman. Dalam hal ini, bahasanya adalah Arab.

Serupa dengan tombol, link terutama mendapatkan nama yang dapat diakses dari konten teksnya. Trik yang bagus saat membuat link adalah menempatkan bagian teks yang paling bermakna ke dalam link itu sendiri, bukan kata pengisi seperti "Di sini" atau "Baca Selengkapnya".

Tidak cukup deskriptif
Check out our guide to web performance <a href="/guide">here</a>.
Konten yang bermanfaat!
Check out <a href="/guide">our guide to web performance</a>.

Memeriksa apakah animasi memicu tata letak

Animasi yang memindahkan elemen menggunakan sesuatu selain transform, cenderung lambat. Dalam contoh berikut, saya telah mencapai hasil visual yang sama dengan menganimasikan top dan left, serta menggunakan transform.

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

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

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

Anda dapat mengujinya dalam dua contoh Glitch berikut, dan menjelajahi performa menggunakan DevTools.

Dengan markup yang sama, kita dapat mengganti: padding-top: 56.25% dengan aspect-ratio: 16 / 9, menetapkan aspect-ratio ke rasio width / height yang ditentukan.

Menggunakan padding-top
.container {
  width: 100%;
  padding-top: 56.25%;
}
Menggunakan rasio aspek
.container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Menggunakan aspect-ratio, bukan padding-top, jauh lebih jelas, dan tidak merombak properti padding untuk melakukan sesuatu di luar cakupan biasanya.

Ya, benar, saya menggunakan reduce untuk merangkai urutan promise. Saya sangat pintar. Namun, ini adalah pengkodean sangat cerdas yang sebaiknya tidak Anda gunakan.

Namun, saat mengonversi kode di atas menjadi fungsi asinkron, Anda mungkin tergoda untuk melakukannya terlalu berurutan:

Tidak direkomendasikan - terlalu sekuensial
async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
Terlihat jauh lebih rapi, tetapi pengambilan kedua saya tidak dimulai sampai pengambilan pertama saya telah dibaca sepenuhnya, dan seterusnya. Ini jauh lebih lambat dibandingkan contoh promise yang melakukan pengambilan secara paralel. Untungnya ada jalan tengah yang ideal.
Direkomendasikan - bagus dan paralel
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);
  }
}
Dalam contoh ini, URL diambil dan dibaca secara paralel, tetapi bit reduce "cerdas" diganti dengan for-loop standar, membosankan, dan dapat dibaca.

Menulis properti kustom Houdini

Berikut adalah contoh penetapan properti kustom (misalnya: variabel CSS), tetapi sekarang dengan sintaksis (jenis), nilai awal (fallback), dan boolean pewarisan (apakah properti mewarisi nilai dari induknya atau tidak?). Cara saat ini untuk melakukannya adalah melalui CSS.registerProperty() di JavaScript, tetapi di Chromium 85 dan yang lebih baru, sintaksis @property akan didukung di file CSS Anda:

File JavaScript terpisah (Chromium 78)
CSS.registerProperty({
  name: '--colorPrimary',
  syntax: '',
  initialValue: 'magenta',
  inherits: false
});
Disertakan dalam file CSS (Chromium 85)
@property --colorPrimary {
  syntax: '';
  initial-value: magenta;
  inherits: false;
}

Sekarang Anda dapat mengakses --colorPrimary seperti properti kustom CSS lainnya, melalui var(--colorPrimary). Namun, perbedaannya di sini adalah --colorPrimary tidak hanya dibaca sebagai string. Datanya ada!

backdrop-filter CSS menerapkan satu atau beberapa efek ke elemen yang buram atau transparan. Untuk memahaminya, perhatikan gambar di bawah.

Tidak ada transparansi latar depan
Segitiga yang tumpang-tindih pada lingkaran. Lingkaran tidak dapat dilihat melalui segitiga.
.frosty-glass-pane {
  backdrop-filter: blur(2px);
}
Transparansi latar depan
Segitiga yang tumpang-tindih pada lingkaran. Segitiga bersifat transparan, sehingga lingkaran dapat terlihat melaluinya.
.frosty-glass-pane {
  opacity: .9;
  backdrop-filter: blur(2px);
}

Gambar di sebelah kiri menunjukkan cara elemen yang tumpang-tindih akan dirender jika backdrop-filter tidak digunakan atau didukung. Gambar di sebelah kanan menerapkan efek pemburaman menggunakan backdrop-filter. Perhatikan bahwa kode ini menggunakan opacity selain backdrop-filter. Tanpa opacity, tidak akan ada yang akan menerapkan pemburaman. Hampir tidak perlu dikatakan bahwa jika opacity disetel ke 1 (sepenuhnya buram), tidak akan ada efek pada latar belakang.

Namun, tidak seperti peristiwa unload, ada penggunaan yang sah untuk beforeunload. Misalnya, saat Anda ingin memperingatkan pengguna bahwa mereka memiliki perubahan yang belum disimpan dan akan hilang jika mereka keluar dari halaman. Dalam hal ini, sebaiknya Anda hanya menambahkan pemroses beforeunload saat pengguna memiliki perubahan yang belum disimpan, lalu segera menghapusnya setelah perubahan yang belum disimpan disimpan.

Larangan
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
Kode di atas menambahkan pemroses beforeunload tanpa syarat.
Anjuran
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);
});
Kode di atas hanya menambahkan pemroses beforeunload jika diperlukan (dan menghapusnya jika tidak diperlukan).

Meminimalkan penggunaan Cache-Control: no-store

Cache-Control: no-store adalah header HTTP yang dapat ditetapkan server web pada respons yang menginstruksikan browser untuk tidak menyimpan respons dalam cache HTTP apa pun. Ini harus digunakan untuk resource yang berisi informasi pengguna sensitif, misalnya halaman di balik login.

Elemen fieldset, yang berisi setiap grup input (.fieldset-item), menggunakan gap: 1px untuk membuat batas garis rambut di antara elemen. Tidak ada solusi batas yang rumit.

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

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

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

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

Penggabungan petak alami

Tata letak yang paling kompleks akhirnya menjadi tata letak makro, sistem tata letak logis antara <main> dan <form>.

input
<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>

Elemen fieldset, yang berisi setiap grup input (.fieldset-item), menggunakan gap: 1px untuk membuat batas garis rambut di antara elemen. Tidak ada solusi batas yang rumit.

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

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

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

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

Tata letak <header> tab

Tata letak berikutnya hampir sama: Saya menggunakan flex untuk membuat pengurutan vertikal.

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

.snap-indicator harus bergerak secara horizontal dengan grup link, dan tata letak header ini membantu menyiapkan tahap tersebut. Tidak ada elemen yang diposisikan secara mutlak di sini.

Gentle Flex adalah strategi khusus pemusatan yang lebih akurat. Hal ini lembut dan halus, karena tidak seperti place-content: center, tidak ada ukuran kotak turunan yang diubah selama pemusatan. Semua item ditumpuk, dipusatkan, dan diberi spasi sehalus mungkin.

.gentle-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1ch;
}
Kelebihan
  • Hanya menangani perataan, arah, dan distribusi
  • Pengeditan dan pemeliharaan semuanya ada di satu tempat
  • Gap menjamin spasi yang sama di antara turunan n
Kekurangan
  • Sebagian besar baris kode

Cocok untuk tata letak makro dan mikro.

Penggunaan

gap menerima panjang atau persentase CSS sebagai nilai.

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


Gap dapat diteruskan 1 panjang, yang akan digunakan untuk baris dan kolom.

Singkatan
.grid {
  display: grid;
  gap: 10px;
}
Menetapkan baris dan kolom bersama-sama sekaligus
Diperluas
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 10px;
}


Gap dapat meneruskan 2 panjang, yang akan digunakan untuk baris dan kolom.

Singkatan
.grid {
  display: grid;
  gap: 10px 5%;
}
Menetapkan baris dan kolom secara terpisah sekaligus
Diperluas
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 5%;
}