ניתוח מעמיק יותר של NG: פיצול בלוקים של LayoutNG

Morten Stenshorne
Morten Stenshorne

חסימה של מקטע: תיבה ברמת הבלוק של CSS (כמו קטע או פסקה) גורמת לפיצול של תיבה ברמת הבלוק של CSS (כמו קטע או פסקה) למספר מקטעים, אם היא לא מתאימה כשלם בתוך מאגר של מקטעים אחד, שנקרא פרגמנטציה. פרגמנטציה היא לא רכיב, אלא מייצגת עמודה בפריסה מרובת עמודות או דף במדיה עם דפים.

כדי לקרות פיצול, התוכן צריך להיות בתוך הקשר של פרגמנטציה. הקשר של פרגמנטציה מוגדר בדרך כלל על ידי מאגר מרובה-עמודות (התוכן מחולק לעמודות) או בזמן ההדפסה (התוכן מפוצל לדפים). ייתכן שיהיה צורך לפצל פסקה ארוכה עם הרבה שורות לכמה מקטעים, כך שהשורות הראשונות ימוקמו במקטע הראשון, והשורות הנותרות יוצבו במקטעים הבאים.

פסקת טקסט המחולקת לשתי עמודות.
בדוגמה הזו, פסקה פוצלה לשתי עמודות באמצעות פריסה של עמודות מרובות. כל עמודה היא פרגמנטציה, שמייצגת מקטע מהתהליך המפוצל.

פרגמנטציה של בלוקים מקבילה לסוג ידוע אחר של פרגמנטציה: מקטע שורות, שנקרא גם 'שבירת שורה'. כל רכיב מוטבע שמכיל יותר ממילה אחת (כל צומת טקסט, כל רכיב <a> וכן הלאה), שמאפשר מעברי שורה, יפוצל למספר מקטעים. כל מקטע מוצב בתיבת שורה אחרת. תיבת שורה היא הפיצול המוטבע שוות-ערך לפרגמנטציה של עמודות ודפים.

פרגמנטציה של בלוק LayoutNG

LayoutNGBlockFragmentation הוא לשכתוב של מנוע המקטעים עבור LayoutNG, שנשלח בשלב הראשון ב-Chrome 102. מבחינת מבני נתונים, התכונה החליפה מספר מבני נתונים מהתקופה שלפני NG בקטעי NG שמיוצגים ישירות בעץ המקטעים.

לדוגמה, אנחנו תומכים עכשיו בערך'מניעה' בנכסי CSS מסוג 'הפסקה לפני' ו 'הפסקה אחרי' של מאפייני CSS, שמאפשרים למחברים להימנע מהפסקות שמופיעות מיד אחרי הכותרת. לרוב, הדבר מוזר כשהדבר האחרון בדף הוא כותרת, ואילו תוכן הקטע מתחיל בדף הבא. עדיף לעשות הפסקות לפני הכותרת.

דוגמה ליישור כותרת.
איור 1. בדוגמה הראשונה מוצגת כותרת בתחתית הדף, ובשנייה מוצגת הכותרת בראש הדף הבא עם התוכן המשויך אליו.

Chrome תומך גם בגלישת מקטעים, כך שתוכן מונוליתי (שאמור להיות בלתי שבר) לא יתחלק לעמודות מרובות, ואפקטים של צבע כמו צלליות וטרנספורמציות יוחלו בצורה נכונה.

חסימת המקטעים ב-LayoutNG הושלמה

פרגמנטציה של ליבה (קונטיינרים חסומים, כולל פריסת קווים, מספר ממשי (float) ומיקום 'מחוץ לזרימה') נשלחת ב-Chrome 102. חלוקה למקטעי רשת ו-Flex נשלחו ב-Chrome 103, והמקטעים בטבלה נשלחו בגרסה 106 של Chrome. לבסוף, הדפסה נשלחת ב-Chrome 108. פיצול בלוקים היה התכונה האחרונה שהסתמכה על המנוע הקודם לביצוע הפריסה.

החל מגרסה 108 של Chrome, המנוע מהדור הקודם לא משמש יותר לביצוע פריסה.

בנוסף, מבני הנתונים של LayoutNG תומכים בציור ובבדיקת היטים, אבל אנחנו מסתמכים על כמה מבני נתונים מדור קודם לממשקי API של JavaScript שקוראים פרטי פריסה, כמו offsetLeft ו-offsetTop.

פריסה של כל המידע ב-NG תאפשר להטמיע ולשלוח תכונות חדשות שיש להן רק הטמעות LayoutNG (ולא מקבילה של מנוע חיפוש), כמו שאילתות קונטיינר של CSS, מיקום עוגן, MathML ופריסה מותאמת אישית (Houdini). עבור שאילתות לגבי קונטיינרים, שלחנו את ההזמנה קצת מראש, עם אזהרה למפתחים על כך שההדפסה עדיין לא נתמכת.

ב-2019 שלחנו את החלק הראשון של LayoutNG כלוך לפריסת בלוקים של קונטיינרים, פריסה מוטבעת, מודעות צפות ומיקום 'מחוץ לזרימה', אבל לא הייתה תמיכה ב-גמיש, ברשת או בטבלאות, ולא הייתה שום תמיכה בפיצול בלוקים. נחזור להשתמש במנוע הפריסה הישן ליצירת לוחות גמישים, רשת, טבלאות וכל מה שקשור לפיצול בלוקים. זה היה נכון גם במקרה של בלוקים, אלמנטים מוטבעים, 'צפים' ורכיבים לא רציפים בתוך תוכן מקוטע – כפי שאפשר לראות, שדרוג של מנוע פריסה מורכב כזה הוא ריקוד עדין מאוד.

כמו כן, עד אמצע 2019, רוב הפונקציונליות העיקרית של פריסת המקטע של בלוק LayoutNG כבר הוטמעה (מאחורי דגל). אז למה לקח כל כך הרבה זמן לשלוח אותו? התשובה הקצרה היא: המקטעים צריכים להתקיים בו-זמנית עם חלקים שונים של המערכת מדור קודם, ולא ניתן להסיר או לשדרג אותם עד שכל יחסי התלות ישודרגו.

אינטראקציה עם מנוע מדור קודם

מבני נתונים מדור קודם עדיין אחראים על ממשקי API של JavaScript שקוראים פרטי פריסה, לכן אנחנו צריכים לכתוב חזרה נתונים למנוע מהדור הקודם באופן שהוא יוכל להבין. הפעולות האלה כוללות עדכון תקין של מבני הנתונים מרובי העמודות הקודמים, כמו LayoutMultiColumnFlowThread.

זיהוי וטיפול בחלופות מדור קודם

נאלצנו לחזור למנוע הפריסה מהדור הקודם כשהייתה בתוך התוכן תוכן שעדיין לא ניתן היה לטפל בו על ידי פיצול בלוקים של LayoutNG. בזמן הפיצול של בלוק LayoutNG של ליבת המשלוח, שכלל גמישות, רשת, טבלאות וכל מה מודפס. התהליך הזה היה מסובך במיוחד, כי היינו צריכים לזהות את הצורך בחלופה מדור קודם לפני יצירת אובייקטים בעץ הפריסה. לדוגמה, היינו צריכים לזהות לפני שידענו אם יש ישות אב של קונטיינר מרובה עמודות, ולפני שידענו אילו צומתי DOM יהפכו להקשר עיצוב או לא. מדובר בבעיה של תרנגולת וביצה שאין לה פתרון מושלם, אבל כל עוד ההתנהגות השגויה היחידה שלה היא תוצאות חיוביות מוטעות (חזרה לגרסה הקודמת כשבאמת אין צורך), זה בסדר, כי באגים בהתנהגות הפריסה הזו הם קיימים שכבר יש ל-Chromium ולא חדשים.

טיול רגלי בעץ

ציור מראש הוא פעולה שאנחנו עושים אחרי הפריסה, אבל לפני ציור. האתגר העיקרי הוא שאנחנו עדיין צריכים ללכת על עץ האובייקטים בפריסה, אבל עכשיו יש לנו קטעי 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 יש מקום ל-5 שורות בכל עמודה (כי הגובה שלו הוא 100 פיקסלים וגובה השורה הוא 20 פיקסלים), כך שאפשר לכלול את כל התוכן #firstchild בעמודה הראשונה. עם זאת, באחות שלו #secondchild יש הפסקה לפני:a קריאה, כלומר התוכן רוצה שלא תתרחש הפסקה ביניהם. מכיוון שהערך של widows הוא 2, אנחנו צריכים להעביר 2 שורות של #firstchild לעמודה השנייה, כדי להיענות לכל הבקשות למניעת הפסקות. Chromium הוא מנוע הדפדפן הראשון שתומך באופן מלא בשילוב התכונות הזה.

הסבר על פרגמנטציה של NG

המנוע של פריסת NG פורס בדרך כלל את המסמך על ידי חציית העומק של עץ תיבת ה-CSS. כשכל הצאצאים של צומת ממוקמים, ניתן להשלים את פריסת הצומת על ידי יצירת NGPhysicalFragment וחזרה לאלגוריתם של פריסת ההורה. האלגוריתם הזה מוסיף את המקטע לרשימת המקטעים הצאצאים שלו, וכשכל הצאצאים יושלמו, הוא יוצר לעצמו מקטע עם כל המקטעים הצאצאים שלו. בשיטה הזו הוא יוצר עץ מקטעים עבור המסמך כולו. עם זאת, זוהי פישוט יתר: לדוגמה, רכיבים שממוקמים מחוץ לזרימה יצטרכו להופיע בבועות מהמקום שבו הם קיימים בעץ ה-DOM עד לבלוק שמכיל אותם, לפני שניתן יהיה לפרוס אותם. אני מתעלם מהפרטים המתקדמים האלה כדי לשמור על פשטות.

יחד עם תיבת ה-CSS עצמה, LayoutNG מספקת מרחב אילוצים באלגוריתם הפריסה. כך לאלגוריתם ניתן מידע כמו השטח הזמין לפריסה, האם נוצר הקשר עיצוב חדש וכן תוצאות של כיווץ שולי הביניים מהתוכן הקודם. מרחב האילוצים יודע גם את גודל הבלוק הנינוח של המקטע, ואת הבלוק הנוכחי שמיסט אליו. כאן המערכת מציינת איפה אפשר לקרוס.

כשמעורבת חלוקה לבלוקים, הפריסה של הצאצאים צריכה לעצור בהפסקה. הסיבות לקריסה יכולות להיות שנגמר המקום בדף או בעמודה, או אילוץ של הפסקה. לאחר מכן אנחנו מפיקים מקטעים עבור הצמתים שביקרנו בהם, ומחזירים את כל התוכן עד לרמה הבסיסית (root) של הקשר המקטעים (מאגר ה-multi-col, או במקרה של הדפסה, השורש של המסמך). לאחר מכן, בשורש ההקשר של המקטעים, אנחנו מכינים את המקטע החדש, יורדים לעץ שוב וממשיכים מהמקום שבו עצרנו לפני ההפסקה.

מבנה הנתונים החיוני לאספקת האמצעים לחידוש הפריסה אחרי ההפסקה נקרא NGBlockBreakToken. הוא מכיל את כל המידע שדרוש כדי להמשיך את הפריסה בצורה נכונה במקטע הבא. NGBlockBreakToken משויך לצומת ויוצר עץ NGBlockBreakToken, כך שכל צומת שצריך להפעיל אותו מיוצג. NGBlockBreakToken מצורף ל-NGPhysicalBoxFragment שנוצר לצורך צמתים שפורצים פנימה. אסימוני ההפסקה מופצים להורים, ויוצרים עץ של אסימוני הפסקה. אם עלינו לפרוץ לפני צומת (במקום בתוכו), לא יופק מקטע, אבל צומת ההורה עדיין צריך ליצור אסימון שבר 'לפני' עבור הצומת, כדי שנוכל להתחיל לפרוס אותו כשנגיע לאותו המיקום בעץ הצמתים במקטע הבא.

שברים נוספים מתווספים כאשר נגמר לנו המקום הפרגמנטציה (הפסקה לא מאולצת) או כשנשלחת בקשה להפסקה מאולצת.

במפרט יש כללים לגבי הפסקות אופטימליות ולא כפויות, והוספת הפסקה בדיוק במקום שבו נגמר המקום. לא תמיד כדאי לעשות את זה בצורה הנכונה. לדוגמה, יש כמה מאפייני CSS כמו break-before שמשפיעים על בחירת המיקום של ההפסקה.

במהלך הפריסה, כדי להטמיע בצורה נכונה את הקטע במפרט של הפסקות לא מאולצות, אנחנו צריכים לעקוב אחר נקודות עצירה (breakpoint) שעשויות להיות טובות. המשמעות של הרשומה הזו היא שאנחנו יכולים לחזור ולהשתמש בנקודת ההפסקה האחרונה הטובה ביותר שנמצאה, אם ייגמר לנו המקום בשלב שבו נפר את בקשות ההימנעות מההפסקה (לדוגמה, break-before:avoid או orphans:7). לכל נקודת עצירה אפשרית ניתן ניקוד, החל מ'עשה זאת כמוצא אחרון בלבד' ועד 'מקום מושלם להפסקה', עם כמה ערכים ביניהם. אם לשבור את הדירוג של המיקום הוא 'מושלם', המשמעות היא שלא תהיה הפרה של כללי הפרה אם נשבר שם (ואם נקבל ניקוד כזה בדיוק ברגע שנגמר לנו המקום, אין צורך לחפש משהו טוב יותר). אם הציון הוא "האתר האחרון", נקודת העצירה היא אפילו לא ערך חוקי, אך עדיין ייתכן שנשבר שם אם לא נמצא משהו טוב יותר, כדי למנוע גלישת מידע.

נקודות עצירה תקפות בדרך כלל מתרחשות רק בין אחים (תיבות סימון או בלוקים), ולא, למשל, בין הורה לבין הצאצא הראשון שלו (נקודות עצירה (breakpoint) מסוג class C הן חריגות, אבל אין צורך לדון בהן כאן). יש נקודת עצירה (breakpoint) חוקית, למשל לפני בלוק אח עם break-before:aנייד, אבל היא נמצאת במקום בין 'מושלם' ל'אחרון'.

במהלך הפריסה, אנחנו עוקבים אחרי נקודת העצירה (breakpoint) הטובה ביותר שנמצאה עד כה במבנה שנקרא NGEarlyBreak. הפסקה מוקדמת היא נקודת עצירה אפשרית לפני או בתוך צומת של בלוק, או לפני קו (קו קונטיינר של בלוקים או קו גמיש). יכול להיות שניצור שרשרת או נתיב של אובייקטים מסוג NGEAP, במקרה שנקודת העצירה הטובה ביותר נמצאת במיקום עמוק בתוך משהו שעברנו עליו מוקדם יותר כשנגמר המקום. לדוגמה:

במקרה הזה, נפח האחסון נגמר ממש לפני #second, אבל האירוע כולל את הביטוי 'breakbefore:aprevent' שמקבל את ציון מיקום ההפסקה 'הימנעות מהפסקה ברצף'. בשלב הזה יש לנו שרשרת NG שמוגדרת מראש ב-#outer > בתוך #middle > בתוך #inner > לפני 'שורה 3', עם המילה 'מושלמת', ולכן אנחנו מעדיפים להתנתק ממנה. אז אנחנו צריכים להחזיר ולהפעיל מחדש את הפריסה מתחילת החלק #outer (והפעם מעבירים את ה-NGEAP שמצאנו), כדי שנוכל להפסיק את הפעולה לפני "שורה 3" ב- #inner. (אנו מבצעים הפסקות לפני "שורה 3", כך שארבעת השורות הנותרים יסתיימו בקטע הבא, וכדי לכבד את widows:4).

האלגוריתם תוכנן כך שיעבור תמיד בנקודת העצירה (breakpoint) הטובה ביותר – כפי שמוגדר במפרט – על ידי שחרור הכללים בסדר הנכון, אם לא ניתן לעמוד בכולם. שימו לב שאנחנו צריכים לבצע את הפריסה מחדש פעם אחת בלבד בכל תהליך פרגמנטציה. עד שנעבור למודל הפריסה השני, מיקום ההפסקה הטוב ביותר כבר הועבר לאלגוריתמים של הפריסה. זהו מיקום ההפסקה שהתגלה באישור הפריסה הראשון, וסופק כחלק מפלט הפריסה בסיבוב הזה. במינוי הפריסה השני, אנחנו לא פורסים עד שייגמר לנו המקום — למעשה לא צפוי שיגמר לנו מקום (זו באמת שגיאה), מפני שסיפקנו מקום מתוק (כמו שהיה זמין) כדי להוסיף הפסקה מוקדמת כדי למנוע הפרה מיותרת של כללים. אז פשוט נשיק את הנקודה הזו ונקטע.

בהערה הזו, לפעמים עלינו להפר חלק מבקשות ההימנעות מההפסקה, אם הדבר עוזר למנוע הצפה של מקטעי נתונים. למשל:

כאן נגמר נפח האחסון ממש לפני #second, אבל יש בו 'break before:aprevent'. זה מתורגם ל"הימנעות מהפרת מדיניות", בדיוק כמו הדוגמה האחרונה. יש לנו גם NGEAP עם "יתומים ואלמנים מפרים" (בתוך #first > לפני "שורה 2"), שעדיין לא מושלם אבל עדיף על "הימנעות מהפסקה ברצף". אז נבטל לפני "שורה 2", תוך הפרה של בקשת היתומים / האלמנים. המפרט מטפל בנושא זה בקטע 4.4. מעברי אכיפה ללא אכיפה: בהגדרה הזו נקבע מאילו כללי פגיעה המערכת תתעלם קודם, אם אין לנו מספיק נקודות עצירה (breakpoint) כדי למנוע חריגה מקטעי.

סיכום

המטרה הפונקציונלית של פרויקט פרגמנטציה של בלוק LayoutNG הייתה לספק הטמעה שתומכת בארכיטקטורת LayoutNG של כל מה שנתמך על ידי המנוע הקודם, ועם כמה שפחות אפשרויות, חוץ מתיקוני באגים. היוצא מן הכלל העיקרי הוא תמיכה טובה יותר במניעת הפסקות (break-before:avoid, למשל), כי זהו חלק מרכזי במנוע המקטעים, כך שהוא צריך להיות בו מלכתחילה, כי אם מוסיפים אותו מאוחר יותר זה יוביל לשכתוב נוסף.

עכשיו, אחרי שפיצול בלוק LayoutNG הסתיים, אנחנו יכולים להתחיל לעבוד על הוספת פונקציונליות חדשה, כגון תמיכה בגדלים מעורבים של דפים בזמן הדפסה, @page תיבות שוליים בעת הדפסה, box-decoration-break:clone ועוד. וכמו ב-LayoutNG בדרך כלל, אנחנו צופים ששיעור הבאגים ונטל התחזוקה של המערכת החדשה יהיו נמוכים יותר באופן משמעותי לאורך זמן.

אישורים