Tutorial CSS / Kombinator dan Kelas Semu CSS

Kombinator memilih elemen berdasarkan hubungan mereka dalam struktur HTML, sedangkan kelas semu memilih kondisi atau status struktural. Selektor anak berbeda dari selektor keturunan, dan :first-child merujuk pada elemen anak pertama, bukan elemen pertama dari tipe tertentu.

Baca hubungan induk, anak, keturunan, dan saudara

Dalam struktur berikut, section adalah induk dari h2, paragraf A, div, dan paragraf C. Paragraf B adalah anak dari div, yang merupakan keturunan dari section. A dan C adalah saudara karena mereka memiliki induk yang sama, tetapi A dan B bukan saudara karena mereka memiliki induk yang berbeda. Struktur HTML lebih penting daripada apakah terlihat berdekatan di layar.

<section class="garden">
  <h2>Visitor Information</h2>
  <p>A: Operating hours</p>
  <div>
    <p>B: Greenhouse Guide</p>
  </div>
  <p>C: What you need</p>
</section>
section.garden
├─ h2
├─ p  ← A
├─ div
│  └─ p  ← B
└─ p  ← C
notasi hubungan selektor Paragraf dipilih Paragraf tidak dipilih
spasi: keturunan .garden p A, B, C p di luar section ini
>: anak langsung .garden > p A, C B berada di dalam div, sehingga bukan anak langsung section
+: saudara berikutnya h2 + p A B memiliki induk yang berbeda dan ada div sebelum C.
~: saudara setelahnya h2 ~ p A, C B memiliki induk yang berbeda dari h2.

Sebuah kombinator biasanya menargetkan elemen di sebelah kanannya. h2 + p menata p yang langsung mengikuti h2 sebagai saudara. Node teks spasi dari indentasi atau pemisah baris tidak mengganggu hubungan elemen-saudara ini. Untuk detail lebih lanjut, lihat Selektor CSS Dasar: Tipe, Kelas, ID, dan Atribut.

Bandingkan selektor keturunan dan anak

.garden p { color: #087f5b; }
.garden > p { border-left: 4px solid #087f5b; padding-left: 12px; }

Aturan pertama membuat semua p di garden berwarna hijau. Itu mencakup B meskipun ada div di tengah. Aturan kedua menambahkan border kiri dan padding kiri hanya untuk anak langsung A dan C. Karena color dan border-left adalah properti yang berbeda, A dan C bisa memiliki keduanya, hijau dan border.

Selektor keturunan cocok untuk styling paragraf bersama di seluruh section. Selektor anak langsung bisa mengecualikan paragraf di dalam kartu bersarang. Perubahan struktur mempengaruhi kecocokan ini; hindari rangkaian kombinator anak yang tidak perlu yang membuat stylesheet bergantung pada kedalaman yang kaku. Lihat MDN: Kombinator.

Bandingkan saudara berikutnya dan saudara-saudara selanjutnya

h2 + p { background-color: #fff4cc; }
h2 ~ p { font-style: italic; }

Aturan pertama memberikan paragraf A, elemen saudara berikutnya dari heading, latar belakang berwarna kuning. Yang kedua membuat A dan C miring karena keduanya adalah saudara p berikutnya dari h2. B memiliki induk yang berbeda dan oleh karena itu tidak cocok. Tidak ada kombinator saudara yang memilih saudara sebelumnya.

Jika Anda menyisipkan <div>Additional notice</div> antara h2 dan A, latar belakang kuning akan hilang karena A tidak lagi menjadi saudara langsung. Namun, kondisi bahwa ia mengikuti h2 dalam induk yang sama tetap berlaku, jadi kemiringan tetap ada. Melihat perbedaan ini akan menyelamatkan Anda dari harus menghafal + dan ~ sebagai "selektor serupa."

Pilih status dan posisi dengan kelas semu

a:hover { background-color: #fff4cc; }
a:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }
.plants li:first-child { font-weight: bold; }
.plants li:nth-child(odd) { background-color: #e9f7ef; }

:hover memilih elemen saat penunjuk diarahkan ke atasnya. :focus-visible memilih keadaan di mana browser menentukan bahwa tampilan fokus diperlukan, dan berguna untuk memeriksa saat berpindah melalui tab menggunakan keyboard. :focus memilih keadaan fokus itu sendiri, sehingga makna keduanya tidak sepenuhnya sama. Contoh ini menentukan garis luar tambahan tanpa menghapus indikator fokus default. Anda dapat terus berlatih bagaimana membedakan warna dan fokus berdasarkan keadaan pada tautan nyata di Status Tautan CSS dan Fokus Keyboard yang Terlihat.

Saat Anda mengarahkan mouse ke tautan, latar belakang berubah menjadi kuning, dan ketika Anda menavigasi ke tautan menggunakan tab, garis tepi biru muncul. Di lingkungan layar sentuh, efek hover tidak selalu bisa dialami oleh pengguna. Biarkan informasi penting, seperti jam operasional atau nama tautan, tetap terbaca secara default.

:first-child memilih jika itu adalah elemen anak pertama dari induknya. :nth-child(odd) memilih kasus di mana urutan elemen anak adalah ganjil, seperti 1, 3, atau 5. Daftar tanaman dalam contoh lengkap di bawah hanya memiliki elemen li, sehingga poin mint nomor 1 menjadi tebal dan membuat latar belakang untuk item 1 dan 3. Jika Anda menggunakan even alih-alih odd, nomor 2 dan 4 menjadi target.

p:first-child berarti “elemen p yang merupakan anak pertama dari induknya,” bukan “p pertama.” Anak pertama dari section dalam contoh ini adalah h2, jadi .garden > p:first-child tidak cocok dengan paragraf manapun. nth-child menghitung semua elemen saudara, bukan hanya elemen dengan tag yang sama. Gunakan kondisi seperti nth-of-type ketika Anda membutuhkan posisi dalam satu jenis elemen. Referensi kelas semu MDN menjelaskan kondisi posisi dan status ini.

Jalankan contoh lengkap

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Small Garden</title>
  <style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
    .garden p { color: #087f5b; }
    .garden > p { border-left: 4px solid #087f5b; padding-left: 12px; }
    h2 + p { background-color: #fff4cc; }
    h2 ~ p { font-style: italic; }
    .plants li:first-child { font-weight: bold; }
    .plants li:nth-child(odd) { background-color: #e9f7ef; }
    a:hover { background-color: #fff4cc; }
    a:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }
  </style>
</head>
<body>
<h1>Small Garden</h1>
  <section class="garden">
    <h2>Visitor Information</h2>
    <p>A: We open at 9am every day.</p>
    <div>
      <p>B: Please observe quietly in the greenhouse.</p>
    </div>
    <p>C: Bring a water bottle and comfortable shoes.</p>
  </section>
  <ul class="plants">
    <li>1: Mint</li>
    <li>2: Basil</li>
    <li>3: Rosemary</li>
    <li>4: Time</li>
  </ul>
  <a href="#contact">Go to the contact section</a>
  <h2 id="contact">Contact</h2>
  <p>Ask at the information desk.</p>
</body>
</html>

Saat Anda menyimpan dan menjalankan, A·B·C berwarna hijau, dan hanya A·C yang memiliki border kiri. A memiliki latar belakang kuning, dan A·C memiliki teks miring. Daftar tanaman memiliki item pertama yang dicetak tebal dan item bernomor ganjil memiliki latar belakang terang. Periksa link menggunakan mouse dan keyboard secara berturut-turut. Huruf A~C di depan paragraf adalah huruf yang ditulis langsung dalam teks untuk membandingkan hasil seleksi.

Ubah struktur dan uji setiap kondisi

  1. Tambahkan satu div di antara h2 dan A. Pastikan hanya latar belakang A yang hilang, sementara teks miring dan border tetap ada. Setelah berlatih, hapus div yang ditambahkan.
  2. Jadikan B sebagai anak langsung dari section dengan hanya menghapus tag div yang mengelilingi paragraf B. Pastikan B juga memiliki border kiri dan miring. Hanya A yang masih benar dalam kondisi +. Setelah konfirmasi, kembalikan div tersebut.
  3. Ganti :nth-child(odd) dengan :nth-child(even). Periksa bahwa latar belakang daftar berpindah dari angka 1 dan 3 ke angka 2 dan 4, dan huruf tebal untuk first-child masih tetap pada angka 1.
  4. Singkirkan mouse Anda, klik di dalam halaman dan tekan tab ke tautan. Pastikan garis fokus terlihat dan Anda dapat pindah ke bagian kontak dengan menekan Enter. Jika bilah alamat browser memiliki fokus, ia kembali ke halaman terlebih dahulu.

Harap periksa setiap kondisi secara terpisah. Mengubah hanya nilai warna untuk memperluas jangkauan seleksi atau menambahkan hover pada masalah fokus keyboard tidak akan menyelesaikan penyebabnya. Di alat pengembang, Anda dapat membandingkan dengan kemampuan untuk memaksa keadaan agar aktif, tetapi pada akhirnya, lebih baik memeriksa hasil yang terlihat oleh pengguna melalui pergerakan tab dan pergerakan mouse yang sebenarnya.