เจาะลึก RenderingNG: การกระจายตัวของบล็อก LayoutNG

Morten Stenshorne
Morten Stenshorne

การกระจาย Fragment ของการบล็อกจะแยกช่องระดับบล็อก CSS (เช่น ส่วนหรือย่อหน้า) ออกเป็นส่วนย่อยหลายๆ ส่วนเมื่อไม่ได้อยู่ภายในคอนเทนเนอร์ Fragment เดียว เรียกว่า ส่วนย่อย Fragmenter ไม่ใช่องค์ประกอบ แต่แสดงคอลัมน์ในเลย์เอาต์แบบหลายคอลัมน์ หรือหน้าในสื่อที่มีการแบ่งหน้า

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

ย่อหน้าข้อความที่แบ่งออกเป็น 2 คอลัมน์
ในตัวอย่างนี้ ย่อหน้าแบ่งเป็น 2 คอลัมน์โดยใช้เลย์เอาต์หลายคอลัมน์ แต่ละคอลัมน์คือส่วนย่อยแสดงส่วนย่อยของโฟลว์ที่กระจัดกระจาย

การกระจาย Fragment ของการบล็อกคล้ายกับการกระจายตัวของอีกประเภทที่รู้จักกันดี นั่นคือ การกระจายตัวของเส้น หรือเรียกอีกอย่างว่า "การขึ้นบรรทัดใหม่" องค์ประกอบแบบแทรกในบรรทัดที่ประกอบด้วยคำมากกว่า 1 คำ (โหนดข้อความใดก็ตาม องค์ประกอบ <a> และอื่นๆ) และอนุญาตให้ขึ้นบรรทัดใหม่ อาจแบ่งออกเป็นส่วนย่อยหลายๆ ส่วน ส่วนย่อยแต่ละรายการจะวางอยู่ในช่องบรรทัดที่แตกต่างกัน กล่องเส้นบรรทัดคือการกระจาย Fragment แบบอินไลน์ ซึ่งเทียบเท่ากับแฟรกเมนต์สำหรับคอลัมน์และหน้า

การกระจายตัวของบล็อก LayoutNG

LayoutNGBlockFragmentation เป็นการเขียนระบบ Fragmentation ใหม่สําหรับ LayoutNG ซึ่งเริ่มจัดส่งใน Chrome 102 ตั้งแต่แรก ในแง่ของโครงสร้างข้อมูล โครงสร้างข้อมูลจะแทนที่โครงสร้างข้อมูลก่อน NG หลายรายการด้วยส่วนย่อย NG ที่แสดงในแผนผังส่วนย่อยโดยตรง

ตัวอย่างเช่น ตอนนี้เรารองรับค่า "avoid" สำหรับพร็อพเพอร์ตี้ CSS "break-before" และ "break-after" ซึ่งช่วยให้ผู้เขียนหลีกเลี่ยงการหยุดพักได้ทันทีหลังส่วนหัว บ่อยครั้งที่มักจะดูไม่ปกติเมื่อสิ่งสุดท้ายในหน้าเป็นส่วนหัว ในขณะที่เนื้อหาของส่วนจะเริ่มต้นในหน้าถัดไป ขอแนะนำให้คุณแยกก่อนส่วนหัว

ตัวอย่างการปรับแนวส่วนหัว
รูปที่ 1 ตัวอย่างที่ 1 แสดงส่วนหัวที่ด้านล่างของหน้า ส่วนที่สองแสดงส่วนหัวที่ด้านบนของหน้าถัดไปซึ่งมีเนื้อหาที่เกี่ยวข้อง

นอกจากนี้ Chrome ยังรองรับการแยกส่วนเนื้อหาแบบแยกส่วนเพื่อไม่ให้เนื้อหาโมโนลิธ (ควรไม่แตก) ออกเป็นหลายคอลัมน์ และใช้เอฟเฟกต์สี เช่น เงาและการเปลี่ยนรูปแบบได้อย่างถูกต้อง

บล็อกการกระจาย Fragment ใน LayoutNG เสร็จสมบูรณ์แล้ว

การกระจาย Fragment หลัก (บล็อกคอนเทนเนอร์ รวมถึงเลย์เอาต์แบบเส้น จำนวนลอยตัว และการวางตำแหน่งที่ไม่ลื่นไหล) ที่จัดส่งใน Chrome 102 Flex และ Fragment ตารางกริดจัดส่งใน Chrome 103 ส่วนตาราง Fragment จัดส่งใน Chrome 106 สุดท้าย การพิมพ์จัดส่งใน Chrome 108 การกระจาย Fragment ของการบล็อกเป็นฟีเจอร์สุดท้ายที่อาศัยเครื่องมือเดิมในการสร้างเลย์เอาต์

ตั้งแต่ Chrome 108 เป็นต้นไป จะไม่มีการใช้งานเครื่องมือเดิมเพื่อทำเลย์เอาต์อีกต่อไป

นอกจากนี้ โครงสร้างข้อมูล LayoutNG ยังสนับสนุนการลงสีและการทดสอบ Hit แต่เราอาศัยโครงสร้างข้อมูลเดิมบางส่วนสำหรับ JavaScript API ที่อ่านข้อมูลเลย์เอาต์ เช่น offsetLeft และ offsetTop

การวางแผนทุกอย่างด้วย NG จะช่วยให้สามารถใช้และจัดส่งฟีเจอร์ใหม่ๆ ที่มีเพียงการใช้งาน LayoutNG เท่านั้น (และไม่มีเครื่องมือคู่กับเครื่องมือแบบเดิม) เช่น การค้นหาคอนเทนเนอร์ CSS, การจัดตำแหน่ง Anchor, MathML และเลย์เอาต์ที่กำหนดเอง (Houdini) สำหรับการค้นหาคอนเทนเนอร์ เราได้จัดส่งล่วงหน้าไปเล็กน้อย พร้อมเตือนนักพัฒนาซอฟต์แวร์ว่าการพิมพ์ยังไม่ได้รับการสนับสนุน

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

นอกจากนี้ ในช่วงกลางปี 2019 ก็มีการติดตั้งใช้งานฟังก์ชันหลักส่วนใหญ่ของเลย์เอาต์การบล็อกแบบ Fragment ของ LayoutNG แล้ว (มีแฟล็ก) เหตุใดการจัดส่งจึงใช้เวลานานมาก คำตอบสั้นๆ ก็คือ: การกระจาย Fragment จะต้องอยู่ร่วมกับส่วนเดิมต่างๆ ของระบบอย่างถูกต้อง ซึ่งจะนำออกหรืออัปเกรดไม่ได้จนกว่าจะอัปเกรดทรัพยากร Dependency ทั้งหมด

การโต้ตอบกับเครื่องมือแบบเดิม

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

การตรวจหาและการจัดการเครื่องมือสำรองระบบเดิม

เราต้องถอยกลับไปใช้เครื่องมือเลย์เอาต์เดิมเมื่อมีเนื้อหาภายในที่ยังไม่สามารถจัดการด้วยการกระจายตัวของบล็อก LayoutNG ได้ ณ เวลาที่ทำการจัดส่ง Fragment หลัก ของบล็อก LayoutNG ซึ่งรวมถึง Flex, ตารางกริด, ตาราง และทุกอย่างที่พิมพ์ ซึ่งเป็นเรื่องที่ยุ่งยากมาก เนื่องจากเราจำเป็นต้องตรวจจับความจำเป็นในการใช้วิดีโอสำรองแบบเดิมก่อนที่จะสร้างออบเจ็กต์ในโครงสร้างแผนผัง ตัวอย่างเช่น เราต้องตรวจสอบก่อนจึงจะรู้ว่ามีระดับบนของคอนเทนเนอร์หลายคอลัมน์หรือไม่ และก่อนจะรู้ว่าโหนด DOM ใดจะกลายเป็นบริบทการจัดรูปแบบหรือไม่ มันเป็นปัญหาแบบไก่กับไข่ที่ไม่มีวิธีแก้ปัญหาที่สมบูรณ์แบบ แต่หากแค่ลักษณะการทำงานที่ไม่ถูกต้องเพียงอย่างเดียวคือข้อสันนิษฐานที่ผิดพลาด (เปลี่ยนเป็นแบบเดิมเมื่อไม่จำเป็นจริงๆ) ก็ไม่เป็นไร เพราะข้อบกพร่องใดๆ ในลักษณะการทำงานของเลย์เอาต์นั้นเป็นข้อบกพร่องของ Chromium อยู่แล้ว ไม่ใช่ข้อบกพร่องใหม่

ทางเดินก่อนระบายสีต้นไม้

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

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

ยังอาจซับซ้อนมากขึ้นอีกเมื่อมีองค์ประกอบที่อยู่ในตำแหน่งที่ไม่จัดตำแหน่งภายในการกระจาย Fragment เพราะจะทำให้ Fragment ที่ไม่อยู่ในทิศทางจะกลายเป็นย่อยโดยตรงของ Fragainer (และไม่ใช่ย่อยที่ CSS คิดว่าเป็นบล็อกภายใน) นี่เป็นปัญหาที่ต้องได้รับการแก้ไขเพื่อให้ใช้งานร่วมกับเครื่องมือเดิมได้ ในอนาคตเราน่าจะทำให้โค้ดนี้ใช้งานง่ายขึ้นได้ เพราะ LayoutNG ออกแบบมาให้รองรับโหมดเลย์เอาต์สมัยใหม่ทั้งหมดได้อย่างยืดหยุ่น

ปัญหาเกี่ยวกับเครื่องมือ Fragment เดิม

เครื่องมือดั้งเดิมที่ได้รับการออกแบบในยุคก่อนของเว็บนั้นแทบไม่มีแนวคิดของการกระจาย Fragment เลย แม้ว่าในทางเทคนิคจะมีการแบ่งส่วนย่อยๆ อยู่แล้วก็ตาม (เพื่อรองรับการพิมพ์) การรองรับ Fragmentation เป็นเพียงสิ่งที่ได้รับการปักหมุดไว้ด้านบน (แบบพิมพ์) หรือปรับปรุงใหม่ (หลายคอลัมน์)

เมื่อจัดเลย์เอาต์เนื้อหาที่แยกเป็นแฟรกเมนต์ เครื่องมือแบบเดิมจะวางทุกอย่างเป็นแถบสูงซึ่งมีความกว้างเท่ากับขนาดอินไลน์ของคอลัมน์หรือหน้าเว็บ และความสูงสูงเท่าที่ควรในการใส่เนื้อหาไว้ แถบแนวตั้งนี้ไม่ได้แสดงในหน้าเว็บ ลองให้คิดว่าเป็นการแสดงผลไปยังหน้าเสมือนที่จัดเรียงใหม่สำหรับการแสดงผลสุดท้าย แนวคิดนี้คล้ายกับการพิมพ์บทความในหนังสือพิมพ์ที่เป็นกระดาษทั้งบทความลงในคอลัมน์เดียว แล้วใช้กรรไกรตัดให้เป็นขั้นตอนต่างๆ ในขั้นตอนที่ 2 (เมื่อก่อนนั้น หนังสือพิมพ์บางฉบับใช้เทคนิคที่คล้ายกันนี้กันอยู่)

เครื่องมือแบบเดิมจะติดตามขอบเขตหน้าในจินตนาการหรือคอลัมน์ในแถบดังกล่าว ซึ่งช่วยให้สามารถสะกิดเนื้อหาที่ไม่พอดีเกินขอบเขตลงในหน้าหรือคอลัมน์ถัดไป ตัวอย่างเช่น หากมีเพียงครึ่งบนของเส้นที่จะพอดีกับสิ่งที่โปรแกรมคิดว่าเป็นหน้าปัจจุบัน จะแทรก "การวางโครงเรื่องการแบ่งหน้า" เพื่อดันลงไปในตำแหน่งที่เครื่องมือสันนิษฐานว่าอยู่ด้านบนสุดของหน้าเว็บถัดไป จากนั้น กระบวนการทำงานจริงส่วนใหญ่ ("การตัดด้วยกรรไกรและการวางตำแหน่ง") จะเกิดขึ้นหลังจากการแปลระหว่างการแบ่งหน้าและการวาดภาพ โดยการตัดแบ่งหน้าออกเป็นส่วนสูงและตัดแต่งตามแนวสูง (การตัดด้วยกรรไกรและการวางตำแหน่ง) ซึ่งทำให้มีบางอย่างที่เป็นไปไม่ได้จริงๆ เช่น การใช้การเปลี่ยนรูปแบบและการวางตำแหน่งแบบสัมพัทธ์หลังการแตกส่วนย่อย (ซึ่งเป็นสิ่งที่ข้อกำหนดเฉพาะต้องการ) นอกจากนี้ แม้ว่าระบบจะรองรับการกระจายตัวของตารางในเครื่องมือเดิม แต่ก็ไม่รองรับการกระจายตัวของตารางกริดหรือตารางกริดเลย

ต่อไปนี้คือภาพประกอบแสดงวิธีแสดงเลย์เอาต์ 3 คอลัมน์ภายในเครื่องมือแบบเดิมก่อนใช้กรรไกร ตำแหน่ง และกาว (เราได้กำหนดความสูงไว้เพื่อให้พอดีเพียง 4 เส้น แต่มีพื้นที่เหลืออยู่ด้านล่าง)

การนำเสนอภายในในรูปแบบคอลัมน์เดียวโดยมีโครงสร้าการแบ่งหน้าซึ่งมีเนื้อหาคั่น และนำเสนอบนหน้าจอเป็น 3 คอลัมน์

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

นี่คือตัวอย่างที่มีเงาข้อความ

เครื่องมือเดิมจัดการเรื่องนี้ได้ไม่ดีนัก:

เงาข้อความที่ถูกตัดทิ้งไว้ในคอลัมน์ที่ 2

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

ซึ่งควรมีลักษณะดังนี้

ข้อความ 2 คอลัมน์ที่มีเงาแสดงอย่างถูกต้อง

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

กล่องแบ่งไม่ถูกต้องใน 2 คอลัมน์

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

หากเนื้อหาโมโนลิธสูงเกินไปที่จะใส่ไว้ภายในคอลัมน์ เครื่องมือแบบเดิมจะตัดส่วนนั้นอย่างไม่เหมาะสม (ทำให้มีลักษณะ "น่าสนใจ" มากเมื่อพยายามเลื่อนคอนเทนเนอร์ที่เลื่อนได้)

แทนที่จะปล่อยให้เกินคอลัมน์แรก (แบบที่มีการกระจายตัวของบล็อก LayoutNG)

ALT_TEXT_HERE

เครื่องมือแบบเดิมรองรับการบังคับช่วงพัก ตัวอย่างเช่น <div style="break-before:page;"> จะแทรกตัวแบ่งหน้าก่อน DIV อย่างไรก็ตาม มีเพียงการรองรับที่จำกัดในการหาช่วงพักที่ไม่ได้บังคับใช้ที่ดีที่สุด รองรับ break-inside:avoid และเด็กกำพร้าและแม่ม่าย แต่จะไม่มีการรองรับการเว้นระยะห่างระหว่างการบล็อก เช่น กรณีที่ขอผ่าน break-before:avoid ลองดูตัวอย่างนี้

ข้อความแบ่งออกเป็น 2 คอลัมน์

ตรงนี้ องค์ประกอบ #multicol มีที่ว่าง 5 บรรทัดในแต่ละคอลัมน์ (เพราะสูง 100 พิกเซล และความสูงบรรทัดเท่ากับ 20 พิกเซล) ดังนั้น #firstchild ทั้งหมดจึงอาจพอดีในคอลัมน์แรก อย่างไรก็ตาม #secondchild ข้างเคียงได้มี break-before:หลีกเลี่ยง ซึ่งหมายความว่าเนื้อหาไม่ต้องการให้มีช่วงพักระหว่างทั้งสองรายการ เนื่องจากค่าของ widows คือ 2 เราจึงจำเป็นต้องพุช #firstchild จำนวน 2 บรรทัดไปยังคอลัมน์ที่ 2 เพื่อให้เป็นไปตามคำขอหลีกเลี่ยงช่วงพักโฆษณาทั้งหมด Chromium เป็นเครื่องมือเบราว์เซอร์แรกที่รองรับการผสมผสานฟีเจอร์นี้อย่างเต็มรูปแบบ

วิธีการทำงานของการกระจาย NG

โดยทั่วไปเครื่องมือเลย์เอาต์ NG จะจัดวางเอกสารโดยข้ามผ่านแผนผังกล่อง CSS ก่อน เมื่อวางตำแหน่งสืบทอดทั้งหมดของโหนดหนึ่งแล้ว การจัดวางของโหนดนั้นจะเสร็จสมบูรณ์โดยการสร้าง NGPhysicalFragment และกลับไปยังอัลกอริทึมเลย์เอาต์หลัก อัลกอริทึมดังกล่าวจะเพิ่มส่วนย่อยลงในรายการส่วนย่อยย่อย และเมื่อส่วนย่อยทั้งหมดเสร็จสมบูรณ์แล้ว ก็จะสร้างส่วนย่อยขึ้นมาเองโดยมีส่วนย่อยทั้งหมดอยู่ภายใน ด้วยวิธีนี้ จะเป็นการสร้างแผนผังส่วนย่อยสำหรับทั้งเอกสาร แต่วิธีนี้ทำให้เข้าใจยากขึ้น แต่ตัวอย่างเช่น องค์ประกอบที่อยู่ในตำแหน่งที่ไม่มีการเคลื่อนไหวจะต้องแสดงเป็นบับเบิลจากตําแหน่งที่มีอยู่ในโครงสร้าง DOM ไปยังบล็อกที่มีอยู่ก่อนที่จะนําองค์ประกอบไปวางได้ เราไม่ได้มองข้ามรายละเอียดขั้นสูงนี้ เพื่อความเรียบง่าย

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

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

โครงสร้างข้อมูลสำคัญในการให้บริการเลย์เอาต์ต่อหลังจากช่วงพักเรียกว่า NGBlockBreakToken ซึ่งจะมีข้อมูลทั้งหมดที่จําเป็นในการทำให้เลย์เอาต์กลับมาทํางานอีกครั้งได้อย่างถูกต้องใน Fragmentainer ถัดไป NGBlockBreakToken เชื่อมโยงกับโหนด และกลายเป็นทรี NGBlockBreakToken เพื่อที่ว่าแต่ละโหนดที่จำเป็นต้องทำงานต่อ NGBlockBreakToken แนบอยู่กับ NGPhysicalBoxFragment ที่สร้างขึ้นสำหรับโหนดที่เสียหายภายใน โทเค็นของช่วงพักโฆษณาจะเผยแพร่ไปยังผู้เผยแพร่โฆษณาหลัก โดยสร้างเป็นโทเค็นของช่วงพักโฆษณา ถ้าเราต้องแบ่งก่อนโหนด (แทนที่จะอยู่ภายใน) จะไม่มีการสร้างแฟรกเมนต์ แต่โหนดหลักยังคงต้องสร้างโทเค็นการแตก "break-before" ของโหนด เพื่อให้เราเริ่มวางโหนดได้เมื่อเราไปถึงตำแหน่งเดียวกันในโหนดทรีในแฟรกเมนต์ถัดไป

ระบบจะแทรกช่วงพักเมื่อเราไม่มีพื้นที่ Fragmenter (ช่วงพักที่ไม่ได้บังคับใช้) หรือเมื่อมีการขอช่วงพักแบบบังคับ

มีกฎต่างๆ ในข้อกำหนดสำหรับช่วงพักโฆษณาที่เหมาะสมซึ่งไม่ได้กำหนดให้มีช่วงพักและการแทรกตัวแบ่งอย่างตรงที่การไม่มีพื้นที่เพียงพอเสมอไป ตัวอย่างเช่น มีพร็อพเพอร์ตี้ CSS ที่หลากหลาย เช่น break-before ที่ส่งผลต่อการเลือกตำแหน่งของช่วงพักโฆษณา

ระหว่างการจัดวาง เราจำเป็นต้องติดตามเบรกพอยท์ที่อาจจะดีเพื่อให้สามารถใช้ส่วนข้อมูลจำเพาะของช่วงพักโฆษณาอย่างถูกต้อง บันทึกนี้หมายความว่าเราสามารถย้อนกลับไปใช้เบรกพอยท์ที่ดีที่สุดล่าสุดที่พบได้ หากเราไม่มีพื้นที่ในจุดที่เราอาจละเมิดคำขอหลีกเลี่ยงจุดพัก (เช่น break-before:avoid หรือ orphans:7) เบรกพอยท์แต่ละจุดที่เป็นไปได้จะได้รับคะแนนตั้งแต่ "วิธีนี้เป็นทางเลือกสุดท้ายเท่านั้น" ไปจนถึง "สถานที่เหมาะเจาะ" โดยมีค่าระหว่างกลาง หากคะแนนสถานที่พักเป็น "สมบูรณ์แบบ" หมายความว่าไม่มีการละเมิดกฎใดๆ หากเราทำคะแนน ณ จุดนั้น (และถ้าเราได้คะแนนตรงนี้ถึงพื้นที่ที่เต็ม ก็ไม่จำเป็นต้องมองย้อนกลับไปหาสิ่งที่ดีกว่า) ถ้าคะแนนเป็น "last-resort" เบรกพอยท์ก็ไม่ใช่ค่าที่ถูกต้อง แต่เราอาจแบ่งได้เป็นจุดนี้หากไม่พบอะไรที่ดีกว่านี้ เพื่อหลีกเลี่ยงส่วนที่เกินจากส่วนย่อย

โดยทั่วไปแล้ว เบรกพอยท์ที่ถูกต้องจะเกิดขึ้นระหว่างพี่น้อง (กล่องบรรทัดหรือบล็อก) เท่านั้น ไม่ใช่ระหว่างระดับบนสุดและย่อยแรก (เบรกพอยท์คลาส C เป็นข้อยกเว้น แต่เราไม่จำเป็นต้องพูดถึงเบรกพอยท์เหล่านั้นที่นี่) ตัวอย่างเช่น มีเบรกพอยท์ที่ถูกต้องก่อนพี่น้องบล็อกที่มี break-before:avoid แต่อยู่ระหว่าง "สมบูรณ์แบบ" กับ "last-resort"

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

ในกรณีนี้ พื้นที่เก็บข้อมูลจะเต็มก่อนวันที่ #second แต่ช่อง "break-before:avoid" ได้ซึ่งจะได้รับคะแนนตำแหน่งหยุดพักเป็น "การหลีกเลี่ยงช่วงพักโฆษณา" ณ จุดนี้ เรามีห่วงโซ่ NGEarlyBreak ของ "ภายใน #outer > ภายใน #middle > ภายใน #inner > ก่อน "บรรทัดที่ 3"' และมีคำว่า "สมบูรณ์แบบ" ดังนั้นเราจะแบ่งกันเฉพาะจุดนี้ เราจึงต้องย้อนกลับและเรียกใช้งานเลย์เอาต์ใหม่ตั้งแต่ต้นของ #outer (และคราวนี้ผ่าน NGEarlyBreak ที่เราพบ) เพื่อให้เราแยกออกก่อน "บรรทัดที่ 3" ใน #inner (เราจะแบ่งก่อน "บรรทัดที่ 3" เพื่อให้อีก 4 บรรทัดที่เหลือได้อยู่ในส่วนย่อยถัดไป และเพื่อเป็นเกียรติแก่ widows:4)

อัลกอริทึมได้รับการออกแบบมาให้อยู่ในจุดพักที่ดีที่สุดเท่าที่จะเป็นไปได้เสมอ ตามที่ระบุไว้ในข้อกำหนด โดยละทิ้งกฎในลำดับที่ถูกต้องหากไม่เป็นไปตามเงื่อนไขทั้งหมด โปรดทราบว่าเราต้องวางเลย์เอาต์ใหม่ไม่เกิน 1 ครั้งต่อขั้นตอนการกระจาย Fragment เมื่อถึงเวลาที่เราอยู่ในช่วงผ่านของเลย์เอาต์ที่สอง ตำแหน่งช่วงพักที่ดีที่สุดจะส่งไปยังอัลกอริทึมของเลย์เอาต์แล้ว ซึ่งเป็นตำแหน่งช่วงพักที่ค้นพบในการผ่านเลย์เอาต์แรก ซึ่งเป็นส่วนหนึ่งของเอาต์พุตของเลย์เอาต์ในรอบนั้น ในเลย์เอาต์ลำดับที่ 2 เราจะไม่จัดตำแหน่งจนกว่าจะเต็มพื้นที่ ซึ่งอันที่จริงแล้วเราไม่คาดว่าจะใช้พื้นที่หมด (ซึ่งจริงๆ แล้วอาจเป็นข้อผิดพลาด) เนื่องจากเราได้ให้สถานที่สำหรับแทรกช่วงพักก่อนเวลาอันควร เพื่อหลีกเลี่ยงการละเมิดกฎที่ผิดโดยไม่จำเป็น เราเลยกำหนดจุดนั้นไว้

โปรดทราบว่าบางครั้งเราจำเป็นต้องละเมิดข้อกำหนดของการหลีกเลี่ยงช่วงพักในกรณีที่ช่วยหลีกเลี่ยงการเกิดส่วนเกิน เช่น

ตรงนี้พื้นที่เก็บข้อมูลเต็มก่อนถึง #second แต่กลับมี "break-before:avoid" ซึ่งจะแปลเป็น "ละเมิดการเลี่ยงช่วงพัก" เหมือนตัวอย่างสุดท้าย นอกจากนี้เรายังมี NGEarlyBreak ที่มี "การละเมิดเด็กกำพร้าและแม่ม่าย" (ภายใน #first > ก่อน "บรรทัดที่ 2") ซึ่งยังไม่สมบูรณ์แบบ แต่ก็ดีกว่า "ละเมิดการเลี่ยงช่วงพัก" ดังนั้นเราจะหยุดพักก่อน "บรรทัดที่ 2" ซึ่งละเมิดนโยบายคำขอของเด็กกำพร้า / แม่ม่าย ข้อกำหนดเฉพาะสำหรับคุณสมบัตินี้ใน 4.4 เบรกพอยท์ที่ไม่ได้บังคับใช้ ซึ่งระบุกฎการละเมิดที่จะถูกละเว้นก่อนหากเรามีเบรกพอยท์ไม่เพียงพอที่จะหลีกเลี่ยงการเกิดส่วนเกิน

บทสรุป

เป้าหมายการทำงานของโปรเจ็กต์การกระจายตัวของบล็อก LayoutNG คือการให้บริการสนับสนุนสถาปัตยกรรมของ LayoutNG ในทุกๆ สิ่งที่เครื่องมือแบบเดิมรองรับ และเพื่อให้ความช่วยเหลือน้อยที่สุดเท่าที่จะทำได้ นอกเหนือจากการแก้ไขข้อบกพร่อง ข้อยกเว้นหลักคือการรองรับการหลีกเลี่ยงเบรกที่ดีกว่า (เช่น break-before:avoid) เนื่องจากนี่เป็นส่วนหลักของเครื่องมือ Fragment จึงควรอยู่ในแพลตฟอร์มนี้ตั้งแต่เริ่มต้น เนื่องจากการเพิ่มในภายหลังจะหมายถึงการเขียนซ้ำอีก

ตอนนี้การแบ่งส่วนบล็อก LayoutNG เสร็จสมบูรณ์แล้ว เราสามารถเริ่มเพิ่มฟังก์ชันใหม่ๆ เช่น การรองรับขนาดหน้าผสมเมื่อพิมพ์, @page ช่องขอบเมื่อพิมพ์, box-decoration-break:clone และอื่นๆ และเช่นเดียวกับ LayoutNG โดยทั่วไป เราคาดหวังว่าอัตราข้อบกพร่องและภาระในการบำรุงรักษาระบบใหม่จะลดลงอย่างมากเมื่อเวลาผ่านไป

กิตติกรรมประกาศ

  • Una Kravets สำหรับ "ภาพหน้าจอทำมือ" สวยๆ
  • Chris Harrelson สำหรับการพิสูจน์อักษร ความคิดเห็น และข้อเสนอแนะ
  • ขอความคิดเห็นและคำแนะนำจาก Philip Jägenstedt
  • Rachel Andrew สำหรับการแก้ไขและรูปตัวอย่างแบบหลายคอลัมน์แรก