Ini adalah masalah yang sangat umum yang muncul karena kesalahpahaman tentang bagaimana :nth-child()
dan :nth-of-type()
bekerja. Sayangnya, saat ini belum ada solusi berbasis pemilih karena Pemilih tidak menyediakan cara untuk mencocokkan turunan ke-n yang cocok dengan pemilih arbitrer berdasarkan pola seperti ganjil, genap, atau di an+b
mana pun a != 1
dan b != 0
. Ini melampaui hanya pemilih kelas, untuk atribut selektor, negasi, dan kombinasi yang lebih kompleks dari penyeleksi sederhana.
Kelas :nth-child()
pseudo menghitung elemen di antara semua saudara kandungnya di bawah induk yang sama. Itu tidak hanya menghitung saudara kandung yang cocok dengan pemilih lainnya. Demikian pula, :nth-of-type()
pseudo-class menghitung saudara kandung yang berbagi jenis elemen yang sama, yang merujuk ke nama tag dalam HTML, dan bukan pemilih lainnya.
Ini juga berarti bahwa jika semua anak dari orang tua yang sama memiliki tipe elemen yang sama, misalnya dalam kasus badan tabel yang satu-satunya anak adalah tr
elemen atau elemen daftar yang hanya anak-anak adalah li
elemen, maka :nth-child()
dan :nth-of-type()
akan berperilaku identik, yaitu untuk setiap nilai an+b
, :nth-child(an+b)
dan :nth-of-type(an+b)
akan cocok dengan kumpulan elemen yang sama.
Faktanya, semua pemilih sederhana dalam pemilih gabungan tertentu, termasuk kelas-semu seperti :nth-child()
dan :not()
, bekerja secara independen satu sama lain, daripada melihat subset elemen yang cocok dengan selektor lainnya.
Ini juga menyiratkan bahwa tidak ada gagasan tentang urutan di antara pemilih sederhana dalam setiap pemilih gabungan 1 , yang berarti, misalnya, dua pemilih berikut ini setara:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
Diterjemahkan ke dalam bahasa Inggris, keduanya berarti:
Pilih tr
elemen apa pun yang cocok dengan semua kondisi independen berikut:
- itu adalah anak ganjil dari induknya;
- itu memiliki kelas "baris"; dan
- itu adalah turunan dari
table
elemen yang memiliki kelas "myClass".
(Anda akan melihat saya menggunakan daftar tidak berurutan di sini, hanya untuk mengarahkan intinya)
Karena saat ini tidak ada solusi CSS murni, Anda harus menggunakan skrip untuk memfilter elemen dan menerapkan gaya atau nama kelas tambahan yang sesuai. Misalnya, berikut ini adalah solusi umum menggunakan jQuery (dengan asumsi hanya ada satu grup baris yang diisi dengan tr
elemen di dalam tabel):
$('table.myClass').each(function() {
// Note that, confusingly, jQuery's filter pseudos are 0-indexed
// while CSS :nth-child() is 1-indexed
$('tr.row:even').addClass('odd');
});
Dengan CSS yang sesuai:
table.myClass tr.row.odd {
...
}
Jika Anda menggunakan alat pengujian otomatis seperti Selenium atau memproses HTML dengan alat seperti lxml, banyak dari alat ini mengizinkan XPath sebagai alternatif:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
Solusi lain yang menggunakan teknologi berbeda dibiarkan sebagai latihan bagi pembaca; ini hanyalah contoh singkat yang dibuat-buat untuk ilustrasi.
Untuk apa nilainya, ada proposal untuk ekstensi pada :nth-child()
notasi yang akan ditambahkan ke Pemilih level 4 untuk tujuan khusus memilih setiap anak ke-n yang cocok dengan pemilih tertentu. 2
Selektor yang digunakan untuk memfilter kecocokan disediakan sebagai argumen :nth-child()
, sekali lagi karena cara penyeleksi beroperasi secara independen satu sama lain dalam urutan seperti yang ditentukan oleh sintaks pemilih yang ada. Jadi dalam kasus Anda, akan terlihat seperti ini:
table.myClass tr:nth-child(odd of .row)
(Seorang pembaca yang cerdik akan segera mencatat bahwa ini seharusnya menjadi :nth-child(odd of tr.row)
gantinya, karena penyeleksi sederhana tr
dan :nth-child()
beroperasi secara independen satu sama lain juga. Ini adalah salah satu masalah dengan kelas-semu fungsional yang menerima penyeleksi, sekaleng cacing saya agak tidak terbuka di tengah jawaban ini. Sebagai gantinya saya akan pergi dengan asumsi bahwa sebagian besar situs tidak akan memiliki elemen lain selain tr
elemen sebagai saudara satu sama lain dalam badan tabel, yang akan membuat salah satu opsi setara secara fungsional.)
Tentu saja, sebagai proposal baru dalam spesifikasi baru, ini mungkin tidak akan diterapkan hingga beberapa tahun ke depan. Sementara itu, Anda harus tetap menggunakan skrip, seperti di atas.
1 Jika Anda menentukan tipe atau pemilih universal, itu harus diutamakan. Namun, ini tidak mengubah cara kerja penyeleksi pada dasarnya; itu tidak lebih dari sebuah permainan kata-kata sintaksis.
2 Ini pada awalnya diusulkan sebagai :nth-match()
, namun karena masih menghitung elemen relatif hanya untuk saudara kandungnya, dan tidak untuk setiap elemen lain yang cocok dengan pemilih yang diberikan, sejak 2014 telah digunakan kembali sebagai perpanjangan dari yang sudah ada :nth-child()
.