นี่เป็นปัญหาทั่วไปที่เกิดขึ้นเนื่องจากความเข้าใจผิดเกี่ยวกับวิธีการ:nth-child()
และการ:nth-of-type()
ทำงาน แต่น่าเสียดายที่มีอยู่ในปัจจุบันไม่มีการแก้ปัญหาเลือกตามเป็นยังเพราะ Selectors ไม่ได้ให้วิธีการเพื่อให้ตรงกับเด็กที่ n ที่ตรงกับตัวเลือกพลขึ้นอยู่กับรูปแบบเช่นเลขคี่, เลขหรือเป็นan+b
ที่และa != 1
b != 0
สิ่งนี้ครอบคลุมมากกว่าตัวเลือกคลาสเท่านั้นไปจนถึงตัวเลือกแอตทริบิวต์การปฏิเสธและการรวมกันของตัวเลือกแบบง่าย
:nth-child()
หลอกชั้นนับองค์ประกอบในหมู่ทั้งหมดของพี่น้องของพวกเขาอยู่ภายใต้การปกครองเดียวกัน ไม่นับเฉพาะพี่น้องที่ตรงกับตัวเลือกที่เหลือ ในทำนองเดียวกัน:nth-of-type()
คลาสหลอกจะนับพี่น้องที่แชร์ประเภทองค์ประกอบเดียวกันซึ่งอ้างถึงชื่อแท็กใน HTML ไม่ใช่ส่วนที่เหลือของตัวเลือก
นอกจากนี้ยังหมายความว่าหากลูกทั้งหมดของพ่อแม่เดียวกันเป็นประเภทองค์ประกอบเดียวกันตัวอย่างเช่นในกรณีของเนื้อตารางที่มีลูกคนเดียวเป็นtr
องค์ประกอบหรือองค์ประกอบรายการที่มีลูกคนเดียวเท่านั้นที่เป็นli
องค์ประกอบ:nth-child()
และ:nth-of-type()
จะทำงานเหมือนกันกล่าวคือ สำหรับค่าของทุกan+b
, :nth-child(an+b)
และ:nth-of-type(an+b)
จะตรงกับชุดเดียวกันขององค์ประกอบ
ในความเป็นจริงตัวเลือกอย่างง่ายทั้งหมดในตัวเลือกสารประกอบที่กำหนดรวมถึงคลาสหลอกเช่น:nth-child()
และ:not()
ทำงานเป็นอิสระจากกันแทนที่จะมองไปที่ชุดย่อยขององค์ประกอบที่จับคู่โดยส่วนที่เหลือของตัวเลือก
นอกจากนี้ยังบอกเป็นนัยว่าไม่มีความคิดของลำดับระหว่างตัวเลือกอย่างง่ายภายในตัวเลือกสารประกอบ1 แต่ละตัวซึ่งหมายความว่าตัวอย่างเช่นตัวเลือกสองตัวต่อไปนี้เทียบเท่ากัน:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
แปลเป็นภาษาอังกฤษทั้งคู่หมายถึง:
เลือกtr
องค์ประกอบใด ๆที่ตรงกับเงื่อนไขอิสระทั้งหมดต่อไปนี้:
- เป็นลูกที่มีเลขคี่ของพ่อแม่
- มันมีคลาส "row"; และ
- มันเป็นลูกหลานของ
table
องค์ประกอบที่มีคลาส "myClass"
(คุณจะสังเกตเห็นการใช้รายการที่ไม่เรียงลำดับที่นี่เพียงเพื่อขับรถกลับบ้าน)
เนื่องจากขณะนี้ยังไม่มีโซลูชัน CSS ที่แท้จริงคุณจะต้องใช้สคริปต์เพื่อกรององค์ประกอบและใช้สไตล์หรือชื่อคลาสเพิ่มเติมตามนั้น ตัวอย่างเช่นต่อไปนี้เป็นวิธีแก้ปัญหาทั่วไปโดยใช้ jQuery (สมมติว่ามีกลุ่มแถวเดียวที่เติมtr
องค์ประกอบภายในตาราง):
$('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');
});
ด้วย CSS ที่สอดคล้องกัน:
table.myClass tr.row.odd {
...
}
หากคุณใช้เครื่องมือทดสอบอัตโนมัติเช่น Selenium หรือการประมวลผล HTML ด้วยเครื่องมือเช่น lxml เครื่องมือเหล่านี้จำนวนมากอนุญาตให้ใช้ XPath เป็นทางเลือก:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
วิธีแก้ปัญหาอื่น ๆ ที่ใช้เทคโนโลยีที่แตกต่างกันถือเป็นแนวทางปฏิบัติสำหรับผู้อ่าน นี่เป็นเพียงตัวอย่างสั้น ๆ ที่จัดทำขึ้นเพื่อเป็นภาพประกอบ
สิ่งที่คุ้มค่ามีข้อเสนอสำหรับส่วนขยายของ:nth-child()
สัญกรณ์ที่จะเพิ่มไปยังตัวเลือกระดับ 4 เพื่อวัตถุประสงค์เฉพาะในการเลือกลูกที่ n ทุกตัวที่ตรงกับตัวเลือกที่กำหนด 2
ตัวเลือกที่จะกรองการจับคู่ถูกจัดให้เป็นอาร์กิวเมนต์:nth-child()
อีกครั้งเนื่องจากวิธีที่ตัวเลือกทำงานเป็นอิสระจากกันในลำดับตามที่กำหนดโดยไวยากรณ์ตัวเลือกที่มีอยู่ ดังนั้นในกรณีของคุณจะมีลักษณะดังนี้:
table.myClass tr:nth-child(odd of .row)
(ผู้อ่านที่ชาญฉลาดจะทราบทันทีว่าสิ่งนี้ควรเป็น:nth-child(odd of tr.row)
แทนเนื่องจากตัวเลือกที่เรียบง่ายtr
และ:nth-child()
ทำงานเป็นอิสระจากกันเช่นกันนี่เป็นหนึ่งในปัญหาเกี่ยวกับคลาสหลอกที่ใช้งานได้ซึ่งยอมรับตัวเลือกซึ่งเป็นเวิร์ม ไม่เปิดตรงกลางของคำตอบนี้ แต่ฉันจะใช้สมมติฐานว่าไซต์ส่วนใหญ่จะไม่มีองค์ประกอบอื่นใดนอกจากtr
องค์ประกอบที่เป็นพี่น้องของกันและกันในเนื้อหาตารางซึ่งจะทำให้ตัวเลือกใดตัวเลือกหนึ่งเทียบเท่ากันได้)
แน่นอนว่าเป็นข้อเสนอใหม่เอี่ยมในข้อกำหนดใหม่ล่าสุดอาจจะไม่เห็นการนำไปใช้จนกว่าจะถึงเวลาอีกไม่กี่ปีข้างหน้า ในระหว่างนี้คุณจะต้องใช้สคริปต์ดังที่กล่าวมาข้างต้น
1 หากคุณระบุประเภทหรือตัวเลือกสากลต้องมาก่อน อย่างไรก็ตามสิ่งนี้ไม่ได้เปลี่ยนแปลงวิธีการทำงานของตัวเลือกโดยพื้นฐาน มันไม่มีอะไรมากไปกว่าการเล่นโวหาร
2 สิ่งนี้ถูกเสนอในตอนแรก:nth-match()
เนื่องจากยังคงนับองค์ประกอบที่สัมพันธ์กับพี่น้องเท่านั้นและไม่รวมถึงองค์ประกอบอื่น ๆ ที่ตรงกับตัวเลือกที่กำหนดตั้งแต่ปี 2014 ได้ถูกนำกลับมาใช้ใหม่เป็นส่วนขยายที่มีอยู่:nth-child()
แทน