นี่เป็นหนึ่งในตัวอย่างที่รู้จักกันดีที่สุดของผู้เขียนที่เข้าใจผิดว่า:first-child
ทำงานอย่างไร นำมาใช้ใน CSS2ที่:first-child
หลอกชั้นหมายถึงเด็กแรกของแม่ แค่นั้นแหละ. มีความเข้าใจผิดที่พบบ่อยมากว่าจะเลือกองค์ประกอบลูกใดก็ตามที่เป็นคนแรกที่ตรงกับเงื่อนไขที่ระบุโดยส่วนที่เหลือของตัวเลือกสารประกอบ เนื่องจากวิธีการทำงานของตัวเลือก (ดูคำอธิบายที่นี่ ) นั่นไม่จริง
Selectors ระดับ 3 แนะนำ:first-of-type
pseudo-classซึ่งแสดงถึงองค์ประกอบแรกในหมู่พี่น้องของประเภทองค์ประกอบ คำตอบนี้อธิบายด้วยภาพประกอบ, ความแตกต่างระหว่างและ:first-child
:first-of-type
อย่างไรก็ตามเช่นเดียวกับ:first-child
มันจะไม่ดูเงื่อนไขหรือคุณลักษณะอื่นใด ใน HTML ประเภทองค์ประกอบจะถูกแทนด้วยชื่อแท็ก p
ในคำถามประเภทที่เป็น
น่าเสียดายที่ไม่มี:first-of-class
คลาสเทียมที่คล้ายกันสำหรับการจับคู่องค์ประกอบลูกแรกของคลาสที่กำหนด วิธีแก้ปัญหาหนึ่งที่Lea Verouและฉันคิดขึ้นมาสำหรับสิ่งนี้ (แม้ว่าจะเป็นอิสระโดยสิ้นเชิง) คือการใช้สไตล์ที่คุณต้องการกับองค์ประกอบทั้งหมดของคุณด้วยคลาสนั้น:
/*
* Select all .red children of .home, including the first one,
* and give them a border.
*/
.home > .red {
border: 1px solid red;
}
... จากนั้น "เลิกทำ" สไตล์สำหรับองค์ประกอบที่มีคลาสที่ตามหลังมาเป็นอันดับแรกโดยใช้combinator พี่น้องทั่วไป~
ในกฎที่สำคัญ:
/*
* Select all but the first .red child of .home,
* and remove the border from the previous rule.
*/
.home > .red ~ .red {
border: none;
}
ตอนนี้มีเพียงองค์ประกอบแรกที่class="red"
มีเส้นขอบ
นี่คือภาพประกอบของวิธีการใช้กฎ:
<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>
ไม่มีการใช้กฎ ไม่มีการแสดงเส้นขอบ
องค์ประกอบนี้ไม่มีคลาสred
ดังนั้นจึงข้ามไป
จะใช้กฎข้อแรกเท่านั้น ขอบสีแดงจะแสดงผล
องค์ประกอบนี้มีคลาสred
แต่ไม่ได้นำหน้าด้วยองค์ประกอบใด ๆ กับคลาสred
ในพาเรนต์ ดังนั้นกฎข้อที่สองจะไม่ถูกนำไปใช้เพียงกฎข้อแรกเท่านั้นและองค์ประกอบจะรักษาเส้นขอบไว้
กฎทั้งสองจะถูกนำไปใช้; ไม่มีการแสดงเส้นขอบ องค์ประกอบนี้มีชั้นเรียน
red
นอกจากนี้ยังนำหน้าด้วยองค์ประกอบอื่น ๆ red
อย่างน้อยหนึ่งกับชั้นเรียน ดังนั้นกฎทั้งสองจะถูกนำไปใช้และการborder
ประกาศครั้งที่สองจะแทนที่กฎแรกดังนั้นจึง "เลิกทำ" ดังนั้นจึงจะต้องพูด
เป็นโบนัส, แม้ว่ามันจะถูกนำมาใช้ใน Selectors 3, Combinator พี่น้องทั่วไปเป็นจริงสวยดีได้รับการสนับสนุนโดย IE7 และใหม่กว่าไม่เหมือน:first-of-type
และ:nth-of-type()
ซึ่งได้รับการสนับสนุนโดยเฉพาะ IE9 เป็นต้นไป หากคุณต้องการการสนับสนุนเบราว์เซอร์ที่ดีแสดงว่าคุณโชคดี
ในความเป็นจริงความจริงที่ว่าพี่น้อง combinator เป็นองค์ประกอบสำคัญเพียงอย่างเดียวในเทคนิคนี้และมีการสนับสนุนเบราว์เซอร์ที่น่าทึ่งทำให้เทคนิคนี้มีความหลากหลายมาก - คุณสามารถปรับใช้สำหรับการกรององค์ประกอบโดยสิ่งอื่นนอกเหนือจากตัวเลือกชั้นเรียน:
คุณสามารถใช้วิธีนี้เพื่อแก้ไขปัญหา:first-of-type
ใน IE7 และ IE8 เพียงแค่จัดหาตัวเลือกประเภทแทนตัวเลือกคลาส (อีกครั้งการใช้งานที่ไม่ถูกต้องเพิ่มเติมในส่วนต่อไป):
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 */
}
คุณสามารถกรองตามselectors attributeหรือ selector ง่าย ๆ อื่น ๆ แทน class
คุณยังสามารถรวมเทคนิคการเอาชนะนี้เข้ากับองค์ประกอบแบบหลอกแม้ว่าองค์ประกอบแบบหลอกจะไม่ใช่ตัวเลือกง่ายๆ
โปรดทราบว่าเพื่อให้สิ่งนี้ใช้งานได้คุณจะต้องรู้ล่วงหน้าว่าสไตล์เริ่มต้นจะเป็นอย่างไรสำหรับองค์ประกอบพี่น้องอื่น ๆ ของคุณเพื่อให้คุณสามารถแทนที่กฎข้อแรก นอกจากนี้เนื่องจากสิ่งนี้เกี่ยวข้องกับกฎการเอาชนะใน CSS คุณจึงไม่สามารถทำสิ่งเดียวกันกับตัวเลือกเดียวสำหรับใช้กับSelectors APIหรือตัวระบุตำแหน่งของซีลีเนียม
มันมูลค่าการกล่าวขวัญว่า Selectors 4 เปิดตัวส่วนขยายไปยัง:nth-child()
สัญกรณ์ ( แต่เดิมใหม่ทั้งหมดหลอกชั้นเรียกว่า:nth-match()
) ซึ่งจะช่วยให้คุณสามารถใช้สิ่งที่ต้องการแทนการสมมุติ:nth-child(1 of .red)
.red:first-of-class
เป็นข้อเสนอที่ค่อนข้างเร็ว ๆ นี้มีการใช้งานร่วมกันไม่เพียงพอที่จะใช้งานได้ในไซต์การผลิต หวังว่าจะมีการเปลี่ยนแปลงในไม่ช้า ในระหว่างนี้การแก้ไขปัญหาที่ฉันแนะนำควรได้ผลในกรณีส่วนใหญ่
โปรดทราบว่าคำตอบนี้สันนิษฐานว่าคำถามนั้นกำลังมองหาองค์ประกอบย่อยของเด็กทุกคนที่มีชั้นเรียนที่กำหนด ไม่มีคลาสเทียมหรือแม้แต่ CSS ทั่วไปสำหรับการจับคู่ที่ซับซ้อนของตัวเลือกที่ซับซ้อนในเอกสารทั้งหมด - การแก้ปัญหานั้นขึ้นอยู่กับโครงสร้างของเอกสารเป็นอย่างมาก jQuery ให้:eq()
, :first
, :last
และอื่น ๆ เพื่อการนี้ แต่ทราบอีกครั้งว่าพวกเขาทำงานแตกต่างกันมากจาก:nth-child()
et al, การใช้ Selectors API คุณสามารถใช้document.querySelector()
เพื่อรับคู่แรก:
var first = document.querySelector('.home > .red');
หรือใช้document.querySelectorAll()
กับตัวสร้างดัชนีเพื่อเลือกการจับคู่เฉพาะ:
var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc
แม้ว่า.red:nth-of-type(1)
วิธีการแก้ปัญหาในคำตอบดั้งเดิมที่ได้รับการยอมรับโดยPhilip Daubmeierทำงานได้ (ซึ่งเดิมเขียนโดยMartynแต่ถูกลบตั้งแต่นั้น) แต่ก็ไม่ได้ทำงานตามที่คุณคาดหวัง
ตัวอย่างเช่นหากคุณต้องการเลือกเฉพาะp
ในมาร์กอัปดั้งเดิมของคุณ:
<p class="red"></p>
<div class="red"></div>
... จากนั้นคุณไม่สามารถใช้.red:first-of-type
(เทียบเท่า.red:nth-of-type(1)
) เพราะแต่ละองค์ประกอบเป็นหนึ่ง (และเท่านั้น) หนึ่งในประเภทของมัน ( p
และdiv
ตามลำดับ) ดังนั้นทั้งสองจะถูกจับคู่โดยตัวเลือก
เมื่อองค์ประกอบแรกของคลาสหนึ่งเป็นประเภทแรกคลาสหลอกจะทำงานได้ แต่สิ่งนี้เกิดขึ้นโดยบังเอิญเท่านั้น พฤติกรรมนี้แสดงให้เห็นในคำตอบของฟิลิป เมื่อคุณติดกับองค์ประกอบประเภทเดียวกันก่อนองค์ประกอบนี้ตัวเลือกจะล้มเหลว การอัปเดตมาร์กอัป:
<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>
การใช้กฎด้วย.red:first-of-type
จะใช้งานได้ แต่เมื่อคุณเพิ่มกฎอื่นp
โดยไม่มีคลาส:
<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>
... ตัวเลือกจะล้มเหลวทันทีเนื่องจาก.red
องค์ประกอบแรกตอนนี้เป็นองค์ประกอบที่สอง p