เหตุใดเบราว์เซอร์จึงตรงกับตัวเลือก CSS จากขวาไปซ้าย


560

CSS Selectors ถูกจับคู่โดยเครื่องมือเบราว์เซอร์จากขวาไปซ้าย ดังนั้นพวกเขาจึงหาเด็ก ๆ ก่อนจากนั้นตรวจสอบผู้ปกครองเพื่อดูว่าตรงกับส่วนที่เหลือของกฎหรือไม่

  1. ทำไมนี้
  2. มันเป็นเพียงเพราะสเป็คบอกว่า?
  3. มันจะมีผลต่อเค้าโครงท้ายที่สุดหรือไม่หากประเมินจากซ้ายไปขวา

สำหรับฉันวิธีที่ง่ายที่สุดที่จะทำคือใช้ตัวเลือกที่มีจำนวนองค์ประกอบน้อยที่สุด ดังนั้น IDs เป็นอันดับแรก (เนื่องจากควรคืนค่า 1 องค์ประกอบเท่านั้น) จากนั้นอาจคลาสหรือองค์ประกอบที่มีจำนวนโหนดน้อยที่สุด - เช่นอาจมีเพียงหนึ่งช่วงบนหน้าดังนั้นไปที่โหนดนั้นโดยตรงด้วยกฎใด ๆ ที่อ้างอิงช่วง

นี่คือลิงค์บางส่วนที่สำรองข้อมูลการอ้างสิทธิ์ของฉัน

  1. http://code.google.com/speed/page-speed/docs/rendering.html
  2. https://developer.mozilla.org/en/Writing_Efficient_CSS

ดูเหมือนว่าจะทำเช่นนี้เพื่อหลีกเลี่ยงการดูเด็กทุกคนของพ่อแม่ (ซึ่งอาจเป็นจำนวนมาก) มากกว่าพ่อแม่ทุกคนของเด็กที่จะต้องเป็นหนึ่ง แม้ว่า DOM จะลึกมันก็จะดูที่หนึ่งโหนดต่อระดับแทนที่จะเป็นหลาย ๆ ในการจับคู่ RTL ง่ายกว่าหรือเร็วกว่าในการประเมิน CSS selectors LTR หรือ RTL


5
3. ไม่ - ไม่ว่าคุณจะอ่านอย่างไรตัวเลือกจะจับคู่ชุดองค์ประกอบเดียวกันเสมอ
Šime Vidas

39
สำหรับสิ่งที่คุ้มค่าเบราว์เซอร์ไม่สามารถสันนิษฐานได้ว่า ID ของคุณไม่เหมือนใคร คุณสามารถใช้ id = "foo" เดียวกันทั่ว DOM ของคุณและ#fooตัวเลือกจะต้องตรงกับโหนดเหล่านั้นทั้งหมด jQuery มีตัวเลือกในการบอกว่า $ ("# foo") จะส่งคืนองค์ประกอบเดียวเสมอเพราะพวกเขากำลังกำหนด API ของตัวเองด้วยกฎของตัวเอง แต่เบราว์เซอร์จำเป็นต้องใช้ CSS และ CSS บอกว่าจะจับคู่ทุกอย่างในเอกสารด้วย ID ที่กำหนด
Boris Zbarsky

4
@Quentin ใน ID เอกสาร "ที่ไม่เป็นไปตามข้อกำหนด" (เป็น HTML) อาจไม่ซ้ำกันและในเอกสาร CSS นั้นต้องการการจับคู่องค์ประกอบทั้งหมดกับ ID นั้น CSS นั้นไม่มีข้อกำหนดเชิงบรรทัดฐานเกี่ยวกับ ID ที่ไม่ซ้ำใคร ข้อความที่คุณอ้างถึงนั้นเป็นข้อมูล
Boris Zbarsky

5
@ Boris Zbarsky สิ่งที่ jQuery ขึ้นอยู่กับเส้นทางของรหัสภายใน jQuery ในบางกรณี jQuery ใช้ NodeSelector API (ดั้งเดิมquerySelectorAll) ในกรณีอื่น ๆ จะใช้ Sizzle Sizzle ไม่ตรงกับหลาย ID แต่ QSA ทำ (AYK) เส้นทางที่ถ่ายนั้นขึ้นอยู่กับตัวเลือกบริบทและเบราว์เซอร์และเวอร์ชันของมัน Query API ของ jQuery ใช้สิ่งที่ฉันเรียกว่า "Native First, Dual Approach" ฉันเขียนบทความเกี่ยวกับเรื่องนั้น แต่มันลง แม้ว่าคุณอาจพบที่นี่: fortybelow.ca/hosted/dhtmlkitchen/JavaScript-Query-Engines.html
Garrett

5
ฉันไม่แน่ใจด้วยซ้ำว่าใคร แต่คุณสองคนสามารถคิดได้ว่าเกิดอะไรขึ้นกับบทสนทนาอันยาวนานนี้ เรามีการแชทสำหรับการอภิปรายเพิ่มเติมเหล่านี้ สิ่งที่คุณต้องการเก็บไว้รอบ ๆ ควรใส่ลงในคำถามหรือคำตอบโดยเฉพาะอย่างยิ่งหากเป็นการชี้แจงข้อมูล Stack Overflow ไม่สามารถจัดการกับการสนทนาในความคิดเห็นได้ดี
George Stocker

คำตอบ:


824

โปรดจำไว้ว่าเมื่อเบราว์เซอร์ทำการจับคู่ตัวเลือกมันจะมีองค์ประกอบหนึ่ง (อันที่มันพยายามกำหนดรูปแบบ) และกฎทั้งหมดของคุณและตัวเลือกของพวกเขาและต้องการค้นหากฎที่ตรงกับองค์ประกอบ สิ่งนี้แตกต่างจากสิ่ง jQuery ทั่วไปที่คุณมีเพียงตัวเลือกเดียวและคุณต้องการค้นหาองค์ประกอบทั้งหมดที่ตรงกับตัวเลือกนั้น

หากคุณมีตัวเลือกเพียงหนึ่งตัวและมีเพียงองค์ประกอบเดียวเท่านั้นที่จะเปรียบเทียบกับตัวเลือกนั้นจากซ้ายไปขวาจะเหมาะสมกว่าในบางกรณี แต่นั่นไม่ใช่สถานการณ์ของเบราว์เซอร์ เบราว์เซอร์พยายามแสดง Gmail หรืออะไรก็ตามและมีกฎ<span>ที่พยายามจัดรูปแบบและกฎ 10,000 ข้อที่ Gmail กำหนดไว้ในสไตล์ชีทของมัน (ฉันไม่ได้สร้างหมายเลขนั้น)

โดยเฉพาะอย่างยิ่งในสถานการณ์เบราว์เซอร์กำลังมองหาตัวเลือกส่วนใหญ่ที่พิจารณาว่าไม่ตรงกับองค์ประกอบที่เป็นปัญหา ดังนั้นปัญหาจะกลายเป็นหนึ่งในการตัดสินใจว่าตัวเลือกไม่ตรงกันอย่างเร็วที่สุด หากต้องใช้งานเพิ่มเล็กน้อยในกรณีที่ตรงกับที่คุณยังคงชนะเนื่องจากงานทั้งหมดที่คุณบันทึกในกรณีที่ไม่ตรงกัน

หากคุณเริ่มต้นด้วยการจับคู่ส่วนขวาสุดของตัวเลือกกับองค์ประกอบของคุณโอกาสที่มันจะไม่ตรงกันและคุณทำเสร็จแล้ว ถ้ามันตรงกันคุณต้องทำงานให้มากขึ้น แต่จะได้สัดส่วนตามความลึกของต้นไม้ซึ่งไม่ใหญ่มากในกรณีส่วนใหญ่

ในทางกลับกันถ้าคุณเริ่มต้นโดยจับคู่ส่วนซ้ายสุดของตัวเลือก ... คุณจับคู่กับอะไร คุณต้องเริ่มเดิน DOM โดยมองหาโหนดที่อาจเข้าคู่กัน เพิ่งค้นพบว่าไม่มีอะไรที่ตรงกับส่วนทางซ้ายสุดอาจใช้เวลาสักครู่

เบราว์เซอร์จึงตรงกันจากด้านขวา มันให้จุดเริ่มต้นที่ชัดเจนและช่วยให้คุณกำจัดตัวเลือกผู้สมัครส่วนใหญ่ได้อย่างรวดเร็ว คุณสามารถดูข้อมูลบางอย่างได้ที่http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665 (แม้ว่าสัญกรณ์จะสับสน) แต่ผลลัพธ์ก็คือสำหรับ Gmail โดยเฉพาะ สองปีที่แล้ว 70% ของคู่ (กฎองค์ประกอบ) คุณสามารถตัดสินใจได้ว่ากฎไม่ตรงกันหลังจากเพียงตรวจสอบส่วนของแท็ก / คลาส / รหัสของตัวเลือกที่เหมาะสมที่สุดสำหรับกฎ หมายเลขที่สอดคล้องกันสำหรับชุดทดสอบประสิทธิภาพ pageload ของ Mozilla คือ 72% ดังนั้นจึงควรพยายามกำจัด 2/3 ของกฎเหล่านั้นทั้งหมดให้เร็วที่สุดเท่าที่จะทำได้และกังวลเกี่ยวกับการจับคู่ที่เหลือเพียง 1/3 เท่านั้น

โปรดทราบว่ามีเบราว์เซอร์การเพิ่มประสิทธิภาพอื่น ๆ ได้ทำไปแล้วเพื่อหลีกเลี่ยงการพยายามจับคู่กฎที่ไม่ตรงกัน ตัวอย่างเช่นหากตัวเลือกที่ถูกต้องที่สุดมี ID และ id นั้นไม่ตรงกับ ID ขององค์ประกอบดังนั้นจะไม่มีความพยายามที่จะจับคู่ตัวเลือกนั้นกับองค์ประกอบนั้นใน Gecko: ชุดของ "selectors with IDs" ที่พยายาม มาจากการค้นหา hashtable บน ID ขององค์ประกอบ ดังนั้นนี่คือ 70% ของกฎที่มีโอกาสที่ดีในการจับคู่ที่ยังไม่ตรงกันหลังจากพิจารณาเพียงแท็ก / คลาส / id ของตัวเลือกที่ถูกต้องที่สุด


5
ในฐานะโบนัสเล็ก ๆ น้อย ๆ มันทำให้รู้สึกมากกว่าที่จะอ่าน RTL มากกว่า LTR แม้เป็นภาษาอังกฤษ ตัวอย่าง: stackoverflow.com/questions/3851635/css-combinator-precedence/ …
BoltClock

6
โปรดทราบว่าการจับคู่ RTL ใช้เฉพาะทั่วcombinators ไม่เจาะลึกลงไปถึงระดับตัวเลือกอย่างง่าย นั่นคือเบราว์เซอร์จะใช้ตัวเลือกผสมที่ถูกต้องที่สุดหรือลำดับของตัวเลือกที่เรียบง่ายและพยายามจับคู่ให้เป็นอะตอม จากนั้นหากมีการจับคู่กันมันจะติดตาม combinator ไปทางซ้ายไปยังตัวเลือกสารประกอบถัดไปและตรวจสอบองค์ประกอบในตำแหน่งนั้นและอื่น ๆ ไม่มีหลักฐานว่าเบราว์เซอร์อ่านแต่ละส่วนของตัวเลือกคำสั่งผสม RTL; อันที่จริงย่อหน้าสุดท้ายแสดงให้เห็นอย่างชัดเจน (การตรวจสอบ id มาก่อนเสมอ)
BoltClock

5
ที่จริงแล้วเมื่อคุณจับคู่ตัวเลือกอย่างน้อยก็ใน Gecko ชื่อแท็กเนมและเนมสเปซจะมาก่อน รหัส (เช่นเดียวกับชื่อแท็กและชื่อคลาส) นั้นได้รับการพิจารณาในขั้นตอนการกรองล่วงหน้าที่กำจัดกฎส่วนใหญ่โดยไม่พยายามจับคู่ตัวเลือกจริงๆ
Boris Zbarsky

สิ่งนี้อาจช่วยได้ขึ้นอยู่กับการปรับแต่ง UA ให้เหมาะสม แต่จะไม่ช่วยขั้นตอนการกรองล่วงหน้าใน Gecko I ที่อธิบายไว้ข้างต้น มีขั้นตอนการกรองขั้นที่สองที่ใช้กับ ID และคลาสที่ใช้สำหรับผู้รวบรวมผู้สืบทอดเท่านั้นที่อาจช่วยได้
Boris Zbarsky

@Benito Ciaro: ไม่ต้องพูดถึงปัญหาเฉพาะเช่นกัน
BoltClock

33

การแยกวิเคราะห์จากขวาไปซ้ายเรียกว่าการแยกวิเคราะห์จากล่างขึ้นบนมีประสิทธิภาพสำหรับเบราว์เซอร์

พิจารณาสิ่งต่อไปนี้:

#menu ul li a { color: #00f; }

เบราว์เซอร์การตรวจสอบครั้งแรกaแล้วliจากนั้นแล้วul#menu

นี่เป็นเพราะเมื่อเบราว์เซอร์ทำการสแกนหน้าเว็บมันเพียงแค่ต้องดูองค์ประกอบ / โหนดปัจจุบันและโหนด / องค์ประกอบก่อนหน้าทั้งหมดที่สแกนไว้

สิ่งที่ควรทราบคือเบราว์เซอร์เริ่มประมวลผลทันทีที่ได้รับแท็ก / โหนดที่สมบูรณ์และไม่จำเป็นต้องรอให้ทั้งหน้ายกเว้นเมื่อพบสคริปต์ในกรณีนี้มันหยุดชั่วคราวและดำเนินการสคริปต์เสร็จแล้ว ไปข้างหน้า

ถ้ามันใช้วิธีอื่นมันจะไม่มีประสิทธิภาพเพราะเบราว์เซอร์พบองค์ประกอบที่ถูกสแกนในการตรวจสอบครั้งแรก แต่ถูกบังคับให้มองผ่านเอกสารต่อไปสำหรับตัวเลือกเพิ่มเติมทั้งหมด สำหรับเบราว์เซอร์นี้ต้องมีทั้ง html และอาจต้องสแกนทั้งหน้าก่อนที่จะเริ่มการวาดภาพ css

นี่คือสิ่งที่ตรงกันข้ามกับ libs ส่วนใหญ่แยกวิเคราะห์ Dom มีการสร้างโดมและไม่จำเป็นต้องสแกนทั้งหน้าเพียงแค่ค้นหาองค์ประกอบแรกจากนั้นไปจับคู่คนอื่น ๆ ข้างใน


20

จะช่วยให้ลดหลั่นจากที่เฉพาะเจาะจงมากขึ้นไปที่เฉพาะเจาะจงน้อยลง นอกจากนี้ยังช่วยให้เกิดการลัดวงจรในแอปพลิเคชัน หากกฎที่เจาะจงมากขึ้นนำไปใช้ในทุกด้านที่กฎหลักนำไปใช้กฎหลักทั้งหมดจะถูกละเว้น หากมีบิตอื่นในพาเรนต์จะมีการนำไปใช้

หากคุณไปทางอื่นคุณจะจัดรูปแบบตามผู้ปกครองแล้วเขียนทับทุกครั้งที่เด็กมีสิ่งที่แตกต่าง ในระยะยาวนี่เป็นการทำงานมากกว่าการเพิกเฉยรายการในกฎที่ได้รับการดูแลอยู่แล้ว


11
นั่นเป็นปัญหาที่แยกต่างหาก คุณทำการเรียงซ้อนโดยเรียงลำดับกฎตามความจำเพาะแล้วจับคู่กับกฎเหล่านั้นตามลำดับที่ระบุ แต่คำถามที่นี่คือเหตุผลสำหรับกฎที่กำหนดไว้คุณจับคู่ตัวเลือกกับวิธีการเฉพาะ
Boris Zbarsky
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.