Ini adalah salah satu contoh paling terkenal dari penulis yang salah mengerti bagaimana cara :first-child
kerjanya. Diperkenalkan dalam CSS2 , :first-child
pseudo-class mewakili anak pertama dari induknya . Itu dia. Ada kesalahpahaman yang sangat umum bahwa ia mengambil elemen anak mana saja yang pertama kali cocok dengan kondisi yang ditentukan oleh pemilih pemilih gabungan. Karena cara penyeleksi bekerja (lihat di sini untuk penjelasan), itu tidak benar.
Selectors level 3 memperkenalkan :first-of-type
pseudo-class , yang mewakili elemen pertama di antara saudara kandung dari tipe elemennya. Jawaban ini menjelaskan, dengan ilustrasi, perbedaan antara :first-child
dan :first-of-type
. Namun, seperti halnya :first-child
, itu tidak melihat kondisi atau atribut lainnya. Dalam HTML, tipe elemen diwakili oleh nama tag. Dalam pertanyaan, tipe itu adalahp
.
Sayangnya, tidak ada :first-of-class
kelas pseudo serupa untuk mencocokkan elemen anak pertama dari kelas yang diberikan. Salah satu solusi yang Lea Verou dan saya buat untuk ini (meskipun sepenuhnya independen) adalah dengan menerapkan gaya yang Anda inginkan untuk semua elemen Anda dengan kelas itu:
/*
* Select all .red children of .home, including the first one,
* and give them a border.
*/
.home > .red {
border: 1px solid red;
}
... lalu "batalkan" gaya untuk elemen dengan kelas yang datang setelah yang pertama , menggunakan kombinator saudara umum~
dalam aturan utama:
/*
* Select all but the first .red child of .home,
* and remove the border from the previous rule.
*/
.home > .red ~ .red {
border: none;
}
Sekarang hanya elemen pertama dengan class="red"
akan memiliki perbatasan.
Berikut ilustrasi tentang bagaimana aturan diterapkan:
<div class="home">
<span>blah</span> <!-- [1] -->
<p class="red">first</p> <!-- [2] -->
<p class="red">second</p> <!-- [3] -->
<p class="red">third</p> <!-- [3] -->
<p class="red">fourth</p> <!-- [3] -->
</div>
Tidak ada aturan yang diterapkan; tidak ada batas yang diberikan.
Elemen ini tidak memiliki kelas red
, jadi ini dilewati.
Hanya aturan pertama yang diterapkan; perbatasan merah diberikan.
Elemen ini memiliki kelas red
, tetapi tidak didahului oleh elemen apa pun dengan kelas red
di induknya. Jadi aturan kedua tidak diterapkan, hanya yang pertama, dan elemen menjaga perbatasannya.
Kedua aturan tersebut diterapkan; tidak ada batas yang diberikan.
Elemen ini memiliki kelas red
. Itu juga didahului oleh setidaknya satu elemen lain dengan kelas red
. Dengan demikian kedua aturan tersebut diterapkan, dan border
deklarasi kedua mengesampingkan yang pertama, dengan demikian "membatalkan", jadi untuk berbicara.
Sebagai bonus, meskipun diperkenalkan di Selectors 3, combinator saudara kandung sebenarnya cukup didukung oleh IE7 dan yang lebih baru, tidak seperti :first-of-type
dan :nth-of-type()
yang hanya didukung oleh IE9 dan seterusnya. Jika Anda membutuhkan dukungan browser yang bagus, Anda beruntung.
Faktanya, fakta bahwa combinator saudara adalah satu-satunya komponen penting dalam teknik ini, dan memiliki dukungan browser yang luar biasa, membuat teknik ini sangat fleksibel - Anda dapat mengadaptasinya untuk memfilter elemen dengan hal lain, selain pemilih kelas:
Anda dapat menggunakan ini untuk bekerja di :first-of-type
dalam IE7 dan IE8, dengan hanya menyediakan pemilih jenis daripada pemilih kelas (sekali lagi, lebih lanjut tentang penggunaannya yang salah di bagian selanjutnya):
article > p {
/* Apply styles to article > p:first-of-type, which may or may not be :first-child */
}
article > p ~ p {
/* Undo the above styles for every subsequent article > p */
}
Anda dapat memfilter berdasarkan pemilih atribut atau pemilih sederhana lainnya alih-alih kelas.
Anda juga dapat menggabungkan teknik pengesampingan ini dengan elemen semu meskipun elemen semu secara teknis bukan penyeleksi sederhana.
Perhatikan bahwa agar ini berfungsi, Anda harus tahu terlebih dahulu apa gaya default untuk elemen saudara Anda yang lain sehingga Anda dapat mengganti aturan pertama. Selain itu, karena ini melibatkan aturan utama dalam CSS, Anda tidak dapat mencapai hal yang sama dengan pemilih tunggal untuk digunakan dengan API Pemilih , atau pencari CSS Selenium .
Perlu disebutkan bahwa Penyeleksi 4 memperkenalkan ekstensi untuk :nth-child()
notasi (awalnya merupakan kelas pseudo yang sama sekali baru :nth-match()
), yang akan memungkinkan Anda untuk menggunakan sesuatu seperti :nth-child(1 of .red)
sebagai pengganti hipotetis.red:first-of-class
. Menjadi proposal yang relatif baru, belum ada implementasi interoperable yang cukup untuk dapat digunakan di lokasi produksi. Semoga ini akan segera berubah. Sementara itu, solusi yang saya sarankan harus bekerja untuk sebagian besar kasus.
Ingatlah bahwa jawaban ini mengasumsikan bahwa pertanyaannya adalah mencari setiap elemen anak pertama yang memiliki kelas tertentu. Tidak ada kelas pseudo atau bahkan solusi CSS generik untuk kecocokan n dari pemilih kompleks di seluruh dokumen - apakah solusi ada sangat tergantung pada struktur dokumen. jQuery menyediakan :eq()
, :first
, :last
dan lebih untuk tujuan ini, tapi catatan lagi bahwa mereka berfungsi sangat berbeda dari :nth-child()
et al . Menggunakan Selectors API, Anda dapat menggunakan document.querySelector()
untuk mendapatkan kecocokan pertama:
var first = document.querySelector('.home > .red');
Atau gunakan document.querySelectorAll()
dengan pengindeks untuk memilih kecocokan spesifik:
var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc
Meskipun .red:nth-of-type(1)
solusi dalam jawaban yang diterima asli oleh Philip Daubmeier berfungsi (yang semula ditulis oleh Martyn tetapi dihapus sejak itu), itu tidak berperilaku seperti yang Anda harapkan.
Misalnya, jika Anda hanya ingin memilih p
markup asli Anda:
<p class="red"></p>
<div class="red"></div>
... maka Anda tidak dapat menggunakan .red:first-of-type
(setara dengan .red:nth-of-type(1)
), karena setiap elemen adalah yang pertama (dan satu-satunya) dari tipenya ( p
dan div
masing - masing), sehingga keduanya akan dicocokkan oleh pemilih.
Ketika elemen pertama dari kelas tertentu juga merupakan yang pertama dari jenisnya , kelas pseudo akan bekerja, tetapi ini hanya terjadi secara kebetulan . Perilaku ini ditunjukkan dalam jawaban Philip. Saat Anda menempel pada elemen dengan tipe yang sama sebelum elemen ini, pemilih akan gagal. Mengambil markup yang diperbarui:
<div class="home">
<span>blah</span>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
Menerapkan aturan dengan .red:first-of-type
akan berhasil, tetapi begitu Anda menambahkan yang lain p
tanpa kelas:
<div class="home">
<span>blah</span>
<p>dummy</p>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
... pemilih akan segera gagal, karena .red
elemen pertama sekarang adalah elemen kedua p
.