البحث العميق في RenderingNG: تجزئة كتلة LayoutNG

Morten Stenshorne
Morten Stenshorne

يعمل حظر التقسيم على تقسيم مربّع على مستوى حظر CSS (مثل قسم أو فقرة) إلى أجزاء متعددة عندما لا يكون كاملاً في حاوية جزء واحدة، ويُسمّى مقسّم. لا يعتبر التجزئة عنصرًا، ولكنه يمثل عمودًا بتنسيق متعدد الأعمدة، أو صفحة في وسائط مقسّمة إلى صفحات.

ولكي يحدث التجزئة، يجب أن يكون المحتوى ضمن سياق التجزئة. غالبًا ما يتم إنشاء سياق التجزئة من خلال حاوية متعددة الأعمدة (ينقسم المحتوى إلى أعمدة) أو عند الطباعة (يتم تقسيم المحتوى إلى صفحات). قد يلزم تقسيم فقرة طويلة تحتوي على العديد من الأسطر إلى أجزاء متعددة، بحيث يتم وضع الأسطر الأولى في الجزء الأول وتوضع الأسطر المتبقية في الأجزاء اللاحقة.

فقرة نصية مقسّمة إلى عمودين.
في هذا المثال، تم تقسيم فقرة إلى عمودين باستخدام تنسيق متعدد الأعمدة. ويمثّل كل عمود جزءًا من التدفق المجزأ.

تتشابه تجزئة الكتلة مع نوع آخر معروف من التجزئة: تجزئة الأسطر، أو ما يُعرف باسم "كسر الأسطر". يمكن تقسيم أي عنصر مضمّن يتكون من أكثر من كلمة واحدة (أي عقدة نصية وأي عنصر <a> وما إلى ذلك) ويسمح باستخدام فواصل الأسطر إلى أجزاء متعددة. يتم وضع كل جزء في مربع سطر مختلف. مربّع السطر هو التقسيم المضمّن المكافئة لأداة التقسيم للأعمدة والصفحات.

تجزئة حظر LayoutNG

LayoutNGBlockFragmentation هو إعادة كتابة لمحرك التجزئة لـ LayoutNG، والذي تم شحنه في البداية في Chrome 102. وفي ما يتعلق بُنى البيانات، تم استبدال هياكل البيانات المتعددة قبل NG بأجزاء NG التي يتم تمثيلها مباشرةً في شجرة التجزئة.

على سبيل المثال، نتيح الآن استخدام قيمة "التجنب" لسمتَي CSS "break-before" و"break-after"، ما يسمح للمؤلفين بتجنُّب الفواصل بعد العنوان مباشرةً. غالبًا ما يبدو الأمر محرجًا عندما يكون آخر شيء على الصفحة هو العنوان، بينما يبدأ محتوى القسم من الصفحة التالية. من الأفضل الفواصل الإعلانية قبل العنوان.

مثال على محاذاة العنوان
الشكل 1. يعرض المثال الأول عنوانًا في أسفل الصفحة، بينما يعرض المثال الثاني المحتوى المرتبط بها في أعلى الصفحة التالية.

يتيح Chrome أيضًا تجاوز سعة التجزئة، بحيث لا يتم تقسيم المحتوى المتجانس (من المفترض أن يكون غير قابل للكسر) إلى أعمدة متعددة، ويتم تطبيق تأثيرات الطلاء، مثل الظلال والتحويل، بشكل صحيح.

اكتملت الآن عملية حظر التقسيم في LayoutNG

التقسيم الأساسي (حاويات الحظر، بما في ذلك تنسيق الأسطر، والقيم العائمة، وتحديد الموضع خارج التدفق) التي يتم شحنها في Chrome 102 شحن التقسيم المرن والشبكة في الإصدار 103 من Chrome، وتقسيم الجداول إلى شرائح في Chrome 106. وأخيرًا، يتم شحن الطباعة في Chrome 108. كانت ميزة تقسيم الحظر هي الميزة الأخيرة التي اعتمدت على المحرك القديم لتنفيذ التنسيق.

بدايةً من الإصدار 108 من Chrome، لم يعُد المحرّك القديم يُستخدم لتنفيذ عمليات التنسيق.

بالإضافة إلى ذلك، تتيح بُنى البيانات في LayoutNG الرسم واختبار النتائج، لكننا نعتمد على بعض بُنى البيانات القديمة لواجهات برمجة تطبيقات JavaScript التي تقرأ معلومات التنسيق، مثل offsetLeft وoffsetTop.

يتيح التخطيط لكل شيء باستخدام NG إمكانية تنفيذ وطرح ميزات جديدة لها عمليات تنفيذ LayoutNG فقط (وليست نظيره في محرك البحث القديم)، مثل طلبات بحث حاوية CSS وتحديد موضع الارتساء وMathML والتنسيق المخصص (Houdini). وبالنسبة إلى الطلبات المتعلّقة بالحاويات، تم شحنها مسبقًا قليلاً، مع تحذير مطوّري البرامج بأنّ الطباعة لم تكن متاحة حتى الآن.

لقد شحننا الجزء الأول من LayoutNG في عام 2019، والذي كان يتألّف من التنسيق المعتاد لحاويات الكتل، والتنسيق المضمّن، والإعلانات العائمة، وتحديد الموضع خارج التدفق، ولكن لا يتيح استخدام التنسيق المرن أو الشبكة أو الجداول، ولا يتيح على الإطلاق تقسيم الكتل. سنعود مرة أخرى إلى استخدام محرك التنسيق القديم للمرونة والشبكة والجداول بالإضافة إلى أي شيء يتضمن حظر التقسيم. كان ذلك صحيحًا حتى بالنسبة إلى عناصر الكتلة والمضمَّنة والعائمة وخارج التدفق داخل المحتوى المجزأ - كما ترى، فإن ترقية محرك التخطيط المعقد في مكانه يُعد رقصة دقيقة للغاية.

علاوة على ذلك، وبحلول منتصف عام 2019، كانت معظم الوظائف الأساسية لتخطيط تجزئة الكتل في LayoutNG قد نُفذت بالفعل (خلف العلامة). إذًا، لماذا استغرق شحنها وقتًا طويلاً؟ الإجابة المختصرة هي: يجب أن يعمل التقسيم بشكل صحيح مع أجزاء قديمة مختلفة من النظام، والتي لا يمكن إزالتها أو ترقيتها حتى تتم ترقية جميع التبعيات.

تفاعل المحرِّك القديم

ولا تزال بُنى البيانات القديمة مسؤولة عن واجهات برمجة تطبيقات JavaScript التي تقرأ معلومات التنسيق، لذا نحتاج إلى إعادة إرسال البيانات إلى المحرّك القديم بطريقة يفهمها. يشمل ذلك تعديل بنى البيانات القديمة المتعددة الأعمدة، مثل LayoutMultiColumnFlowThread، بشكل صحيح.

رصد عمليات الاستبدال القديمة للمحرّك ومعالجتها

كان علينا الرجوع إلى محرك التنسيق القديم عندما كان هناك محتوى داخله لا يمكن معالجته بعد من خلال تجزئة حظر LayoutNG. عند تنفيذ عملية تقسيم كتلة LayoutNG الأساسية، كانت الشبكة تشمل المرونة والشبكة والجداول وأي محتوى مطبوع. كان ذلك معقدًا بشكل خاص لأنّنا أردنا رصد الحاجة إلى إجراء احتياطي قديم قبل إنشاء العناصر في شجرة التنسيق. على سبيل المثال، كان علينا رصد ذلك قبل أن نعرف ما إذا كان هناك كيان أصل لحاوية متعددة الأعمدة، وقبل أن نتمكّن من معرفة عُقد DOM التي ستصبح سياق تنسيق أم لا. إنها مشكلة متعلقة بالدجاج والبيضة ليس لها حل مثالي، ولكن ما دام السلوك السيئ الوحيد هو الموجبة الخاطئة (الرجوع إلى الإرث القديم عندما لا يكون هناك حاجة في الواقع)، فلا بأس، لأن أي أخطاء في سلوك التخطيط هذا هي أخطاء من قبل، وليست أخطاء جديدة.

تجربة مشي قبل الطلاء

الرسم المسبق هو برنامج نجريه بعد التنسيق، ولكن قبل الرسم. التحدي الرئيسي هو أننا ما زلنا بحاجة إلى رسم شجرة كائن التخطيط، ولكن لدينا أجزاء NG الآن، فكيف نتعامل مع ذلك؟ ونحن نستخدم كائن التخطيط وأشجار أجزاء NG في نفس الوقت! وهذا أمر معقد للغاية، لأن التخطيط بين الشجرتين ليس تافهًا.

على الرغم من أن بنية شجرة كائن التنسيق تشبه إلى حد كبير بنية شجرة نموذج العناصر في المستند (DOM)، فإن شجرة الجزء هي مخرج للتنسيق، وليس مدخلاً له. بصرف النظر عن تأثير أي تجزئة، بما في ذلك التجزئة المضمَّنة (أجزاء الأسطر) وتقسيم الحظر (أجزاء العمود أو الصفحة)، تحتوي شجرة الأجزاء أيضًا على علاقة مباشرة وفرعية بين جزء كامل وعناصر DOM التابعة التي تحتوي على هذا الجزء كقطعة مضمّنة. على سبيل المثال، في شجرة الجزء، يكون الجزء الذي يتم إنشاؤه بواسطة عنصر في موضع ثابت جزءًا تابعًا مباشرًا لجزء الكتلة الذي يحتوي عليه، حتى إذا كانت هناك عُقد أخرى في سلسلة الأصل بين العنصر التابع الموضع خارج التدفق والقطعة التي تحتوي عليه.

وقد يزداد الأمر تعقيدًا في حال وجود عنصر خارج المسار داخل التقسيم، لأنّ الأجزاء خارج التدفق تصبح عناصر ثانوية مباشرة للجزء المجزأ (وليست عنصرًا ثانويًا لما تعتقد خدمة CSS أنّه الجزء الذي يتضمّنه). كانت هذه مشكلة كان يجب حلها من أجل العمل المشترك مع المحرك القديم. في المستقبل، ينبغي أن نتمكن من تبسيط هذا الرمز، لأن LayoutNG مصمم لدعم جميع أوضاع التخطيط الحديثة بمرونة.

مشكلات محرك التقسيم القديم

ولا يحتوي المحرك القديم، الذي تم تصميمه في عصر سابق على الويب، على مفهوم التجزئة، حتى إذا كان التجزئة موجودًا من الناحية التقنية في ذلك الوقت أيضًا (بهدف إتاحة الطباعة). كان دعم التجزئة مجرد شيء تم تثبيته في الأعلى (الطباعة) أو تعديله (متعدد الأعمدة).

عند وضع محتوى قابل للتجزئة، يضع المحرك القديم كل شيء في شريط طويل يكون عرضه بحجم مضمّن للعمود أو الصفحة، ويكون ارتفاعه طويلاً بالقدر اللازم لاحتواء المحتوى. لا يتم عرض هذا الشريط الطويل على الصفحة - يمكنك اعتباره على أنه يتم عرضه لصفحة افتراضية تتم إعادة ترتيبها للعرض النهائي. ويتشابه ذلك من الناحية النظرية مع طباعة مقالة صحيفة ورقية كاملة في عمود واحد، ثم استخدام المقص لقصها إلى عدة أجزاء كخطوة ثانية. (في الماضي، كانت بعض الصحف تستخدم في الواقع أساليب مشابهة لذلك!)

يتتبع المحرك القديم حدود عمود أو صفحة وهمية في الشريط. ويسمح ذلك لها بدفع المحتوى الذي لا يتخطى الحدود إلى الصفحة أو العمود التالي. على سبيل المثال، إذا كان النصف العلوي من الخط فقط مناسبًا لما يعتقده المحرّك بأنّه الصفحة الحالية، سيتم إدراج "دعامة مقسَّمة على صفحات" لدفعها إلى الموضع الذي يفترض فيه المحرّك أنّ الجزء العلوي من الصفحة التالية هو الجزء. وبعد ذلك، تحدث معظم عمليات التقسيم الفعلية ("القص باستخدام المقص وموضعها") بعد إتمام التخطيط أثناء عملية الرسم كله وتقليمه. وقد أدى ذلك إلى تعذّر تنفيذ بعض الأمور في الأساس، مثل تطبيق التحويلات وتحديد الموضع النسبي بعد التقسيم (وهذا ما تتطلبه المواصفات). بالإضافة إلى ذلك، على الرغم من أنّ تقسيم الجداول في المحرّك القديم متاح بعض الشيء، فإنّه لا يتيح تقسيم الجدول المرن أو الشبكة على الإطلاق.

في ما يلي توضيح لكيفية تمثيل تخطيط من ثلاثة أعمدة داخليًا في المحرك القديم، قبل استخدام المقص والموضع والغراء (لدينا ارتفاع محدد بحيث لا يتناسب سوى أربعة أسطر، ولكن هناك مساحة زائدة في الجزء السفلي):

التمثيل الداخلي كعمود واحد مع دعامات التقسيم على صفحات حيث ينقسم المحتوى، والتمثيل على الشاشة كثلاثة أعمدة

نظرًا لأن محرك التخطيط القديم لا يجزئ المحتوى بالفعل أثناء التخطيط، فهناك العديد من العناصر الغريبة، مثل الموضع النسبي والتحويل الذي يتم تطبيقه بشكل غير صحيح، كما يتم اقتصاص تظليل المربع عند حواف الأعمدة.

إليك مثال على ظل النص:

لا يتعامل المحرك القديم مع هذا الأمر بشكل جيد:

ظلال نص مقتصَّة موضوعة في العمود الثاني.

هل ترى كيف يتم قص ظل النص من السطر في العمود الأول، ووضعه بدلاً من ذلك في أعلى العمود الثاني؟ هذا لأن محرك التخطيط القديم لا يفهم التجزئة.

من المفترض أن يظهر على النحو التالي:

عمودان من النص يتم عرض الظلال عليه بشكل صحيح

بعد ذلك، لنجعل الأمر أكثر تعقيدًا، باستخدام التحويلات وظل المربع. لاحظ كيف أنه في المحرك القديم، هناك اقتصاص وتجاوز عمود غير صحيح. وهذا بسبب أنه من المفترض أن يتم تطبيق التحويلات وفقًا للمواصفات كتأثير ما بعد التقسيم بعد التجزئة. يعمل كل من التجزئة LayoutNG بشكل صحيح. ويؤدي هذا إلى زيادة إمكانية التشغيل التفاعلي مع Firefox، الذي حافظ على دعم التجزئة بشكل جيد لبعض الوقت مع اجتياز معظم الاختبارات في هذا المجال أيضًا.

تم تقسيم المربعات بشكل غير صحيح عبر عمودين.

كما يواجه المحرك القديم مشاكل في المحتوى المتجانس الطويل. يكون المحتوى موحّدًا إذا لم يكن مؤهلاً لتقسيمه إلى أجزاء متعدّدة. العناصر التي تحتوي على تمرير كامل متجانسة، لأنه ليس من المنطقي للمستخدمين التمرير في منطقة غير مستطيلة. تعد مربعات الخطوط والصور أمثلة أخرى على المحتوى المتجانس. وفي ما يلي مثال لذلك:

إذا كان جزء المحتوى المتجانس طويلاً للغاية بحيث لا يناسب عمودًا ما، فسيقطعه المحرك القديم بوحشية (مما يؤدي إلى سلوك "مثير للاهتمام" للغاية عند محاولة تمرير الحاوية القابلة للتمرير):

بدلاً من السماح له بتجاوز العمود الأول (كما هو الحال مع تجزئة كتلة LayoutNG):

ALT_TEXT_HERE

يتيح المحرّك القديم استخدام الفواصل التي يتم فرضها. على سبيل المثال، ستُدرج السمة <div style="break-before:page;"> فاصل صفحة قبل علامة DIV. ومع ذلك، فهي تدعم فقط العثور على الفواصل المثلى غير المفروضة. وهو يتيح أيضًا استخدام break-inside:avoid والأرامل والأرامل، غير أنّه لا يوفّر أي مساعدة لتجنُّب الفواصل بين القطع، إذا تم طلبها عبر break-before:avoid، على سبيل المثال. اطلع على المثال التالي:

النص مقسم إلى عمودين.

هنا، يشتمل العنصر #multicol على مساحة لخمسة أسطر في كل عمود (لأنّه يبلغ 100 بكسل طوله وارتفاع السطر هو 20 بكسل)، لذلك يمكن تضمين #firstchild بالكامل في العمود الأول. في المقابل، إنّ رف "#secondchild" المختلف لديه توقُّف قبل:يتجنّب المحتوى، ما يعني أنّ المحتوى لا يريد أن تنقطع استراحة بينهما. بما أنّ قيمة widows هي 2، نحتاج إلى دفع سطرَين من #firstchild إلى العمود الثاني لتلبية جميع طلبات تجنُّب الاستراحة. Chromium هو محرك المتصفح الأول الذي يتوافق بشكل كامل مع هذه المجموعة من الميزات.

آلية عمل تجزئة NG

يعمل محرك تخطيط NG بشكل عام على تخطيط المستند من خلال اجتياز عمق شجرة مربع CSS أولاً. عندما يتم تخطيط جميع العناصر التابعة لعقدة ما، يمكن إكمال تخطيط تلك العقدة، من خلال إنتاج NGPhysicalFragment والعودة إلى خوارزمية التنسيق الرئيسية. تضيف هذه الخوارزمية الجزء إلى قائمة الأجزاء الفرعية الخاصة بها، وبمجرد إكمال جميع العناصر الثانوية، تنشئ جزءًا لنفسها يحتوي على جميع الأجزاء الفرعية بداخله. وبهذه الطريقة، يتم إنشاء شجرة تجزئة للمستند بأكمله. وهذا أسلوب في غاية التبسيط: على سبيل المثال، يجب أن تظهر العناصر التي تم تحديد موضعها خارج التدفق من حيث توجد في شجرة نموذج العناصر في المستند (DOM) إلى الكتلة التي تحتوي عليها قبل أن يمكن وضعها. أتجاهل هذه التفاصيل المتقدّمة هنا لأغراض البساطة.

بالإضافة إلى مربع CSS نفسه، يوفر LayoutNG مساحة مقيّدة لخوارزمية التخطيط. وهذا يوفر للخوارزمية معلومات مثل المساحة المتاحة للتخطيط، وما إذا كان يتم إنشاء سياق تنسيق جديد، ونتائج تصغير الهوامش المتوسطة من المحتوى السابق. تعرف مساحة القيد أيضًا حجم الكتلة المخطط للجزء المجزأ، وإزاحة الكتلة الحالية فيه. يشير هذا إلى مكان الاستراحة.

في حال تضمين تجزئة الحظر، يجب أن يتوقف تنسيق العناصر التابعة عند فاصل. وتشمل أسباب العطل نفاد المساحة في الصفحة أو العمود أو فاصل إجباري. ثم ننتج بعد ذلك أجزاءً للعُقد التي قمنا بزيارتها، ونعود إلى جذر سياق التجزئة (الحاوية متعددة الأعمدة، أو جذر المستند في حالة الطباعة). وبعد ذلك، في جذر سياق التجزئة، نستعد لأداة تجزئة جديدة، وننزل إلى الشجرة مرة أخرى، ونستأنف من حيث توقفنا قبل الفاصل.

تُعرف بنية البيانات الأساسية لتوفير وسائل استئناف التنسيق بعد الفاصل باسم NGBlockBreakToken. يحتوي على جميع المعلومات اللازمة لاستئناف التخطيط بشكل صحيح في الجزء التالي. يرتبط NGBlockBreakToken بعقدة ويشكّل شجرة NGBlockBreakToken، بحيث يتم تمثيل كل عقدة يلزم استئنافها. يتم إرفاق NGBlockBreakToken بـ NGPhysicalBoxFragment الذي تم إنشاؤه للعُقد التي تتخللها. ويتم نشر رموز الفواصل الإعلانية إلى العناصر الرئيسية لتشكيل شجرة من رموز الفواصل. إذا احتجنا إلى تقسيم قبل عقدة (بدلاً من داخلها)، فلن يتم إنشاء أي جزء، ولكن لا تزال العقدة الرئيسية بحاجة إلى إنشاء رمز مميز للفاصل "break-قبل" للعقدة، حتى نتمكن من البدء في وضعها عندما نصل إلى نفس الموضع في شجرة العقدة في الجزء التالي.

يتم إدراج الفواصل عند نفاد مساحة التجزئة (فاصلة غير إلزامية) أو عند طلب فاصل إجباري.

ثمة قواعد في ما يتعلق بمواصفات الفواصل الإعلانية غير الإجبارية على النحو الأمثل، وليس من المفيد دائمًا إدراج استراحة في المكان الذي تنفد فيه المساحة. على سبيل المثال، هناك سمات CSS مختلفة مثل break-before تؤثر في خيار تحديد موقع الفاصل.

أثناء التنسيق، لتنفيذ قسم مواصفات الفواصل غير الإلزامية بشكل صحيح، نحتاج إلى تتبّع نقاط التوقف الجيدة التي يحتمل أن تكون. يعني هذا السجلّ أنّه يمكننا الرجوع واستخدام آخر أفضل نقطة توقّف ممكنة تم العثور عليها، وذلك في حال نفاد مساحة التخزين في نقطة خالفنا فيها طلبات تجنُّب التوقّف (على سبيل المثال، break-before:avoid أو orphans:7). ويتم تحديد درجة لكل نقطة توقّف محتملة تتراوح بين "تنفيذ هذا الإجراء كحلّ أخير فقط" و"المكان المثالي للاستراحة"، مع بعض القيم بينهما. إذا كانت نتائج أحد مواقع العطل "مثالية"، فهذا يعني أنه لن يتم انتهاك أي قواعد مخالفة في حالة خرقنا لها (وإذا حصلنا على هذه النتيجة بالضبط عند النقطة التي نفذت فيها المساحة، لا داعي لإعادة النظر في ما يتعلق بشيء أفضل). وإذا كانت النتيجة هي "المنتج الأخير"، تكون نقطة التوقف ليست صالحة، ولكننا قد نقطعها إذا لم نجد أي شيء أفضل، وذلك لتجنب تجاوز الأجزاء المجزّأة.

تحدث نقاط التوقف الصالحة عمومًا بين الأشقاء (مربعات الأسطر أو الكتل)، وليس، على سبيل المثال، بين عنصر رئيسي وفرعه الأول (تُعد نقاط التوقف للفئة C استثناءً، ولكننا لسنا بحاجة إلى مناقشة تلك الأمور هنا). هناك نقطة فاصلة صالحة، على سبيل المثال، قبل الحظر التابع للكتلة باستخدام break-before:av، إلا أنّها تقع بين "مثالي" و"المنتجع الأخير".

أثناء التنسيق، نتتبّع أفضل نقطة توقّف تم العثور عليها حتى الآن في بنية تُعرف باسم NGEarlyBreak. الفاصل المبكر هو نقطة توقف محتملة قبل عقدة كتلة أو داخلها، أو قبل سطر (إما خط حاوية كتلة، أو خط مرن). قد نشكل سلسلة أو مسار لكائنات NGEarlyBreak، في حال كانت أفضل نقطة توقف في مكان ما داخل مكان مررنا فيه في وقت سابق في الوقت الذي نفد فيه المساحة. وفي ما يلي مثال لذلك:

في هذه الحالة، نفدت المساحة قبل #second مباشرةً، ولكن بها "break-before:av"، والتي تحصل على نتيجة موقع فاصل هي "تجنُّب مخالفتك للفاصل". في هذه المرحلة، لدينا سلسلة NGEarlyBreak "داخل #outer > داخل #middle > داخل #inner > قبل "السطر 3"، مع "مثالي"، لذلك نفضّل التوقف عن ذلك. لذلك نحن بحاجة إلى الرجوع وإعادة تشغيل التخطيط من بداية #outer (وهذه المرة لاجتياز NGEarlyBreak التي وجدناها)، حتى نتمكن من الفاصل قبل "السطر 3" في #inner. (يتم وضع الفاصل قبل "السطر 3"، بحيث تنتهي الأسطر الأربعة المتبقية في المُجزئ التالي، وذلك تقديرًا لـ widows:4).

تم تصميم الخوارزمية بحيث يتم دومًا التوصل إلى أفضل نقطة توقف ممكنة - كما هو موضح في المواصفات - عن طريق تجاهل القواعد بالترتيب الصحيح، إذا لم تكن جميعها مستوفاة. تجدر الإشارة إلى أنّه يجب إعادة التنسيق مرة واحدة فقط في كل مسار تقسيم. وبحلول الوقت الذي نكون فيه في ممر التنسيق الثاني، يكون أفضل موقع للفاصل قد تم تمريره بالفعل إلى خوارزميات التخطيط، وهو موقع الفاصل الذي تم اكتشافه في ممر التنسيق الأول، وتم تقديمه كجزء من إخراج التخطيط في تلك الجولة. في التصميم الثاني، لا ننضب حتى تنفد المساحة - في الواقع ليس من المتوقع أن تنفد المساحة (سيكون ذلك في الواقع خطأ)، لأننا حصلنا على مكان رائع للغاية (ولكنه كان ممتعًا بقدر ما كان متاحًا) لإدخال استراحة مبكرة، لتجنب انتهاك أي قواعد مخالفة بدون داعٍ. إذًا، نتطرق إلى هذه النقطة، ونتوقف.

في هذه الملاحظة، نحتاج أحيانًا إلى انتهاك بعض طلبات تجنُّب الفاصل، إذا كان ذلك يساعد في تجنُّب تجاوز الحد المجزأ. مثلاً:

هنا، نفدت المساحة قبل #second مباشرةً، ولكن تحتوي على "break-before:av". ويُترجم ذلك إلى "تجنُّب انتهاك الفاصل الإعلاني"، تمامًا كالمثال الأخير. لدينا أيضًا حدث NGEarlyBreak الذي يتضمّن العبارة "محتوى ينتهك حقوق الأيتام والأرامل" (داخل #first > قبل "السطر 2")، وهو لا يزال غير مثالي، ولكنه أفضل من "تجنُّب الفاصل الإعلاني الذي ينتهك السياسات". لذا سننقطع قبل "السطر 2"، من خلال انتهاك طلب الأيتام / الأرامل. تتعامل المواصفات مع هذا في 4.4. الفواصل غير الإجبارية: تحدّد فيها القواعد المخالفة التي يتم تجاهلها أولاً إذا لم تكن لدينا نقاط فاصلة كافية لتجنُّب تجاوز العنصر المجزأ.

الخلاصة

كان الهدف الوظيفي من مشروع تجزئة الكتل البرمجية في LayoutNG هو توفير تنفيذ كل العناصر التي يدعمها المحرك القديم في بنية LayoutNG، وبأقل قدر ممكن، باستثناء إصلاحات الأخطاء. والاستثناء الرئيسي هو إتاحة ميزة تجنّب الأعطال بشكل أفضل (مثل break-before:avoid) لأنّها جزء أساسي من محرّك التقسيم، لذا يجب أن يبقى معروضًا من البداية، لأنّ إضافته لاحقًا ستؤدّي إلى إعادة كتابة أخرى.

الآن بعد أن اكتملت عملية تقسيم أجزاء كتلة LayoutNG، يمكننا بدء العمل على إضافة وظائف جديدة، مثل إتاحة أحجام مختلطة للصفحات عند الطباعة، و@page مربّعات الهوامش عند الطباعة، وbox-decoration-break:clone والمزيد. وكما هو الحال مع LayoutNG بشكل عام، نتوقع أن ينخفض معدل الأخطاء وعبء الصيانة للنظام الجديد بشكل كبير بمرور الوقت.

شكر وتقدير