रेंडर करने के लिए, डीप-डाइव की सुविधा: LayoutNG ब्लॉक फ़्रैगमेंटेशन

Morten Stenshorne
Morten Stenshorne

ब्लॉक फ़्रैगमेंटेशन, सीएसएस ब्लॉक-लेवल बॉक्स (जैसे, सेक्शन या पैराग्राफ़) को कई फ़्रैगमेंट में बांटता है. ऐसा तब होता है, जब वह एक फ़्रैगमेंट कंटेनर में पूरा फ़िट न हो. इस कंटेनर को फ़्रैगमेंटर कहा जाता है. फ़्रैगमेंटर कोई एलिमेंट नहीं होता, लेकिन कई कॉलम वाले लेआउट में कॉलम या पेज वाले मीडिया में किसी पेज को दिखाता है.

फ़्रैगमेंटेशन होने के लिए, कॉन्टेंट को फ़्रैगमेंटेशन कॉन्टेक्स्ट में होना चाहिए. फ़्रैगमेंटेशन कॉन्टेक्स्ट, आम तौर पर कई कॉलम वाले कंटेनर (कॉन्टेंट को कॉलम में बांटा जाता है) या प्रिंट करते समय (कॉन्टेंट को पेजों में बांटा जाता है) सेट किया जाता है. कई लाइनों वाले लंबे पैराग्राफ़ को कई हिस्सों में बांटना पड़ सकता है, ताकि पहली लाइनों को पहले फ़्रैगमेंट में रखा जा सके और बाकी लाइनों को बाद के हिस्सों में रखा जा सके.

टेक्स्ट का एक पैराग्राफ़, जिसे दो कॉलम में बांटा गया है.
इस उदाहरण में, कई कॉलम वाले लेआउट का इस्तेमाल करके, पैराग्राफ़ को दो कॉलम में बांटा गया है. हर कॉलम एक फ़्रैगमेंटर है, जो फ़्रैगमेंट फ़्लो के एक हिस्से को दिखाता है.

ब्लॉक फ़्रैगमेंटेशन, फ़्रैगमेंटेशन के एक अन्य टाइप से मिलता-जुलता है: लाइन फ़्रैगमेंटेशन, जिसे "लाइन ब्रेकिंग" भी कहा जाता है. किसी भी इनलाइन एलिमेंट को कई फ़्रैगमेंट में बांटा जा सकता है. ऐसा तब किया जा सकता है, जब उसमें एक से ज़्यादा शब्द (कोई भी टेक्स्ट नोड, कोई भी <a> एलिमेंट वगैरह) हों और लाइन ब्रेक की सुविधा हो. हर फ़्रैगमेंट को एक अलग लाइन बॉक्स में रखा जाता है. लाइन बॉक्स, कॉलम और पेजों के लिए फ़्रैगमेंटर के बराबर इनलाइन फ़्रैगमेंटेशन है.

LayoutNG ब्लॉक फ़्रैगमेंटेशन

LayoutNGBlockFragmentation, LayoutNG के लिए फ़्रैगमेंटेशन इंजन को फिर से लिखा गया है. इसे पहली बार Chrome 102 में लॉन्च किया गया था. डेटा स्ट्रक्चर के मामले में, यह एनजी से पहले के कई डेटा स्ट्रक्चर को एनजी फ़्रैगमेंट से बदल देता है. ये फ़्रैगमेंट सीधे फ़्रैगमेंट ट्री में दिखते हैं.

उदाहरण के लिए, अब हम 'ब्रेक-पहले' और 'ब्रेक-बाद' सीएसएस प्रॉपर्टी के लिए 'इससे बचें' वैल्यू का इस्तेमाल करते हैं. इससे लेखकों को हेडर के ठीक बाद ब्रेक से बचने की सुविधा मिलती है. जब किसी पेज पर आखिरी चीज़ हेडर होती है और सेक्शन का कॉन्टेंट अगले पेज पर शुरू होता है, तो अक्सर यह अजीब लगता है. हेडर से पहले ब्रेक लगाना बेहतर होता है.

हेडिंग के अलाइनमेंट का उदाहरण.
पहली इमेज. पहले उदाहरण में, पेज पर सबसे नीचे एक हेडिंग दिखाया गया है. दूसरे उदाहरण में, शीर्षक को अगले पेज पर सबसे ऊपर दिखाया गया है. साथ ही, उसमें उससे जुड़ा कॉन्टेंट दिखाया गया है.

Chrome, फ़्रैगमेंटेशन ओवरफ़्लो की सुविधा भी देता है, ताकि मोनोलिथिक (जिसे तोड़ा नहीं जा सकता) कॉन्टेंट को कई कॉलम में न काटा जाए. साथ ही, शैडो और ट्रांसफ़ॉर्म जैसे पेंट इफ़ेक्ट सही तरीके से लागू किए जा सकें.

LayoutNG में ब्लॉक फ़्रैगमेंटेशन की सुविधा अब पूरी हो गई है

Chrome 102 में शिप किया गया मुख्य फ़्रैगमेंटेशन (लाइन लेआउट, फ़्लोट, और आउट-ऑफ़-फ़्लो पोज़िशनिंग वाले ब्लॉक कंटेनर). फ़्लेक्स और ग्रिड फ़्रैगमेंटेशन की सुविधा, Chrome 103 में लॉन्च की गई थी. वहीं, टेबल फ़्रैगमेंटेशन की सुविधा, Chrome 106 में लॉन्च की गई थी. आखिर में, Chrome 108 में प्रिंटिंग की सुविधा जोड़ी गई. ब्लॉक फ़्रैगमेंटेशन, लेआउट के लिए लेगसी इंजन पर निर्भर रहने वाली आखिरी सुविधा थी.

Chrome 108 से, लेआउट बनाने के लिए लेगसी इंजन का इस्तेमाल नहीं किया जाता.

इसके अलावा, LayoutNG डेटा स्ट्रक्चर, पेंटिंग और हिट-टेस्टिंग के साथ काम करते हैं. हालांकि, हम JavaScript API के लिए कुछ लेगसी डेटा स्ट्रक्चर पर भरोसा करते हैं, जो लेआउट की जानकारी पढ़ते हैं. जैसे, offsetLeft और offsetTop.

NG के साथ सब कुछ व्यवस्थित करने से, नई सुविधाओं को लागू और शिप किया जा सकेगा. इन सुविधाओं में सिर्फ़ LayoutNG लागू होता है, न कि लेगसी इंजन का कोई दूसरा वर्शन. जैसे, सीएसएस कंटेनर क्वेरी, ऐंकर पोज़िशनिंग, MathML, और कस्टम लेआउट (Houdini). कंटेनर क्वेरी के लिए, हमने इसे कुछ समय पहले भेज दिया था. साथ ही, हमने डेवलपर को यह चेतावनी दी थी कि प्रिंट करने की सुविधा अभी काम नहीं करती है.

हमने 2019 में LayoutNG का पहला हिस्सा लॉन्च कर दिया था. इसमें सामान्य ब्लॉक कंटेनर लेआउट, इनलाइन लेआउट, फ़्लोट, और आउट-ऑफ़-फ़्लो पोज़िशनिंग शामिल थी. हालांकि, फ़्लेक्स, ग्रिड या टेबल के लिए कोई सुविधा नहीं थी. साथ ही, ब्लॉक फ़्रैगमेंटेशन की सुविधा भी नहीं थी. हम फ़्लेक्स, ग्रिड, टेबल, और ब्लॉक फ़्रैगमेंटेशन से जुड़ी किसी भी चीज़ के लिए, लेगसी लेआउट इंजन का इस्तेमाल करेंगे. यह बात, अलग-अलग हिस्सों में बंटे कॉन्टेंट में ब्लॉक, इनलाइन, फ़्लोटिंग, और आउट-ऑफ़-फ़्लो एलिमेंट के लिए भी सही थी. इनमें यह देखा जा सकता है कि इतने जटिल लेआउट इंजन को एक साथ अपग्रेड करना, एक दिलचस्प डांस है.

इसके अलावा, साल 2019 के मध्य तक, LayoutNG ब्लॉक फ़्रैगमेंटेशन लेआउट की ज़्यादातर मुख्य सुविधाएं पहले से ही लागू थीं. तो, इसे शिप होने में इतना समय क्यों लगा? इसका छोटा जवाब यह है: फ़्रैगमेंटेशन को सिस्टम के अलग-अलग लेगसी हिस्सों के साथ सही तरीके से काम करना चाहिए. जब तक सभी डिपेंडेंसी को अपग्रेड नहीं किया जाता, तब तक उन्हें हटाया या अपग्रेड नहीं किया जा सकता.

लेगसी इंजन इंटरैक्शन

लेगसी डेटा स्ट्रक्चर अब भी JavaScript API के लिए काम करते हैं, जो लेआउट की जानकारी को पढ़ते हैं. इसलिए, हमें लेगसी इंजन में डेटा को इस तरह लिखना होगा कि वह उसे समझ सके. इसमें LayoutMultiColumnFlowThread जैसे लेगसी मल्टी-कॉलम डेटा स्ट्रक्चर को सही तरीके से अपडेट करना शामिल है.

लेगसी इंजन फ़ॉलबैक का पता लगाना और उसे मैनेज करना

जब अंदर ऐसा कॉन्टेंट होता था जिसे LayoutNG ब्लॉक फ़्रैगमेंटेशन से मैनेज नहीं किया जा सकता था, तब हमें लेगसी लेआउट इंजन का इस्तेमाल करना पड़ता था. LayoutNG के मुख्य ब्लॉक को अलग-अलग हिस्सों में बांटने के दौरान, इसमें फ़्लेक्स, ग्रिड, टेबल, और प्रिंट की गई कोई भी चीज़ शामिल होती है. यह खास तौर पर मुश्किल था, क्योंकि हमें लेआउट ट्री में ऑब्जेक्ट बनाने से पहले, लेगसी फ़ॉलबैक की ज़रूरत का पता लगाना था. उदाहरण के लिए, हमें यह पता लगाना था कि क्या कोई मल्टी-कॉलम कंटेनर है या नहीं. साथ ही, यह भी पता लगाना था कि कौनसे DOM नोड फ़ॉर्मैटिंग कॉन्टेक्स्ट बनेंगे या नहीं. यह एक ऐसी समस्या है जिसका कोई सटीक समाधान नहीं है. हालांकि, जब तक इसकी गड़बड़ी सिर्फ़ गलत तरीके से सकारात्मक नतीजे दिखाने (जब ज़रूरत न हो, तब लेगसी पर फ़ॉलबैक) तक सीमित है, तब तक यह ठीक है. इसकी वजह यह है कि लेआउट के व्यवहार में मौजूद कोई भी बग, क्रोमियम में पहले से मौजूद है, न कि नया है.

पेड़ों के बीच में चलने का रास्ता

प्री-पेंट, हम लेआउट के बाद, लेकिन पेंट करने से पहले करते हैं. मुख्य समस्या यह है कि हमें अब भी लेआउट ऑब्जेक्ट ट्री को वॉक करने की ज़रूरत है, लेकिन अब हमारे पास NG फ़्रैगमेंट हैं—तो हम इस समस्या को कैसे हल करें? हम एक ही समय में लेआउट ऑब्जेक्ट और NG फ़्रैगमेंट ट्री दोनों पर चलते हैं! यह काफ़ी जटिल है, क्योंकि दोनों पेड़ों के बीच मैपिंग करना आसान नहीं है.

लेआउट ऑब्जेक्ट ट्री का स्ट्रक्चर, डीओएम ट्री से काफ़ी मिलता-जुलता है. हालांकि, फ़्रैगमेंट ट्री, लेआउट का आउटपुट है, न कि उसका इनपुट. इन-लाइन फ़्रैगमेंटेशन (लाइन फ़्रैगमेंट) और ब्लॉक फ़्रैगमेंटेशन (कॉलम या पेज फ़्रैगमेंट) के साथ-साथ किसी भी फ़्रैगमेंटेशन के असर को दिखाने के अलावा, फ़्रैगमेंट ट्री का कंटेनिंग ब्लॉक और डीओएम डिसेंडेंट के बीच पैरंट-चाइल्ड संबंध होता है. उदाहरण के लिए, फ़्रैगमेंट ट्री में, बिलकुल सही जगह पर मौजूद एलिमेंट से जनरेट किया गया फ़्रैगमेंट, उसके चुने गए ब्लॉक फ़्रैगमेंट का डायरेक्ट चाइल्ड होता है. भले ही, आउट-ऑफ़-फ़्लो पोज़िशन डिसेंडेंट और उसके शामिल ब्लॉक के बीच एंसेस्ट्री चेन में अन्य नोड हों.

फ़्रैगमेंटेशन में, आउट-ऑफ़-फ़्लो पोज़िशन वाला एलिमेंट होने पर, यह और भी मुश्किल हो सकता है. ऐसा होने पर, आउट-ऑफ़-फ़्लो फ़्रैगमेंट, फ़्रैगमेंटर के डायरेक्ट चाइल्ड बन जाते हैं. ये उस एलिमेंट के चाइल्ड नहीं होते जिसे सीएसएस, कॉन्टेंट ब्लॉक मानता है. यह एक ऐसी समस्या थी जिसे लेगसी इंजन के साथ काम करने के लिए हल करना ज़रूरी था. आने वाले समय में, हम इस कोड को आसान बना पाएंगे, क्योंकि LayoutNG को सभी मॉडर्न लेआउट मोड के साथ काम करने के लिए डिज़ाइन किया गया है.

लेगसी फ़्रैगमेंटेशन इंजन में आने वाली समस्याएं

वेब के पुराने दौर में डिज़ाइन किए गए लेगसी इंजन में, फ़्रैगमेंटेशन का सिद्धांत नहीं है. भले ही, उस समय फ़्रैगमेंटेशन तकनीकी रूप से भी मौजूद हो (प्रिंटिंग की सुविधा के लिए). फ़्रैगमेंटेशन सपोर्ट ऐसा था जो सबसे ऊपर बोल्ट (प्रिंटिंग) या रेट्रोफ़िट किया गया (मल्टी-कॉलम) था.

फ़्रैगमेंट किए जा सकने वाले कॉन्टेंट को लेआउट करते समय, लेगसी इंजन हर चीज़ को एक लंबी स्ट्रिप में लेआउट करता है. इस स्ट्रिप की चौड़ाई, कॉलम या पेज के इनलाइन साइज़ के बराबर होती है और ऊंचाई, कॉन्टेंट के हिसाब से तय होती है. इस लंबी स्ट्रिप को पेज पर रेंडर नहीं किया जाता. इसे किसी वर्चुअल पेज पर रेंडर करने के तौर पर देखें, जिसे फ़ाइनल डिसप्ले के लिए फिर से व्यवस्थित किया जाता है. यह कॉन्सेप्ट, अखबार के किसी लेख को एक कॉलम में प्रिंट करने और फिर उसे काटकर कई कॉलम में बांटने जैसा है. (पहले के समय में, कुछ अखबारों ने इस तरह की तकनीकों का इस्तेमाल किया था!)

लेगसी इंजन, स्ट्रिप में किसी काल्पनिक पेज या कॉलम की सीमा का ट्रैक रखता है. इससे, उस कॉन्टेंट को अगले पेज या कॉलम में भेजा जा सकता है जो सीमाओं के अंदर नहीं आता. उदाहरण के लिए, अगर इंजन को मौजूदा पेज के बारे में लगता है कि लाइन का सिर्फ़ ऊपरी आधा हिस्सा फ़िट होगा, तो उसे उस पोज़िशन पर नीचे पुश करने के लिए "पेजिनेशन स्ट्रट" डाला जाएगा जहां इंजन के हिसाब से यह पेज सबसे ऊपर है. इसके बाद, पेज को बांटने से जुड़ा ज़्यादातर काम ("कैंची और पेंटिंग के दौरान, पेज को अलग करने और उन्हें पेंट करने के बाद, लेआउट में काट-छांट करने के बाद" (पेजों को काटना और पेंट करना). इस वजह से, कुछ चीज़ें करना असंभव हो गया था. जैसे, फ़्रैगमेंटेशन के बाद ट्रांसफ़ॉर्म और रिलेटिव पोज़िशनिंग लागू करना (जो कि स्पेसिफ़िकेशन के मुताबिक ज़रूरी है). इसके अलावा, लेगसी इंजन में टेबल के फ़्रैगमेंटेशन के लिए कुछ सहायता मिलती है, लेकिन फ़्लेक्स या ग्रिड के फ़्रैगमेंटेशन के लिए कोई सहायता नहीं मिलती.

यहां एक उदाहरण दिया गया है, जिसमें दिखाया गया है कि लेगसी इंजन में, कैंची, प्लेसमेंट, और गोंद का इस्तेमाल करने से पहले, तीन कॉलम वाले लेआउट को अंदरूनी तौर पर कैसे दिखाया जाता है. हमारे पास तय की गई ऊंचाई होती है, ताकि सिर्फ़ चार लाइनें फ़िट हो सकें. हालांकि, सबसे नीचे कुछ अतिरिक्त जगह होती है:

पेजेशन स्ट्रट्स के साथ एक कॉलम के तौर पर इंटरनल रेप्रज़ेंटेशन, जहां कॉन्टेंट के बीच ब्रेक होता है और स्क्रीन पर तीन कॉलम के तौर पर रेप्रज़ेंटेशन

लेगसी लेआउट इंजन, लेआउट के दौरान कॉन्टेंट के अलग-अलग हिस्सों को नहीं बांटता, इसलिए इसमें कई अजीब चीज़ें मौजूद हैं. जैसे, मिलती-जुलती पोज़िशनिंग और गलत तरीके से बदलाव होना और कॉलम के किनारों पर बॉक्स-शैडो क्लिप करना.

यहां text-shadow का इस्तेमाल करने का उदाहरण दिया गया है:

लेगसी इंजन, इन मामलों में ठीक से काम नहीं करता:

दूसरे कॉलम में क्लिप किए गए टेक्स्ट की छायाएं.

क्या आपने देखा कि किस तरह पहले कॉलम में लाइन से टेक्स्ट-शैडो को क्लिप करके दूसरे कॉलम के ऊपर रखा जाता है? ऐसा इसलिए होता है, क्योंकि लेगसी लेआउट इंजन, फ़्रैगमेंटेशन को समझ नहीं पाता.

यह इस तरह दिखना चाहिए:

टेक्स्ट के दो कॉलम, जिनमें शैडो सही तरीके से दिख रहे हैं.

अब, ट्रांसफ़ॉर्म और बॉक्स शैडो की मदद से इसे और मुश्किल बनाते हैं. ध्यान दें कि लेगसी इंजन में, क्लिपिंग और कॉलम ब्लीड गलत तरीके से कैसे हो रहा है. ऐसा इसलिए होता है, क्योंकि ट्रांसफ़ॉर्म की सुविधा को निर्देश के हिसाब से, पोस्ट-लेआउट और पोस्ट-फ़्रैगमेंटेशन इफ़ेक्ट के तौर पर लागू किया जाना चाहिए. LayoutNG फ़्रैगमेंटेशन दोनों सही तरीके से काम करते हैं. इससे Firefox के साथ इंटरऑपरेबिलिटी बढ़ती है. इस ब्राउज़र में, फ़्रैगमेंटेशन के लिए कुछ समय से अच्छी सुविधाएं उपलब्ध हैं. इस क्षेत्र में, ज़्यादातर टेस्ट भी पास हो जाते हैं.

दो कॉलम में बॉक्स गलत तरीके से टूट गए हैं.

लेगसी इंजन में, बड़े मोनोलिथिक कॉन्टेंट से भी समस्याएं आती हैं. अगर कॉन्टेंट को कई फ़्रैगमेंट में नहीं बांटा जा सकता, तो इसे मोनोलिथिक माना जाता है. ओवरफ़्लो स्क्रोलिंग वाले एलिमेंट मोनोलिथिक होते हैं, क्योंकि उपयोगकर्ताओं को गैर-आयताकार क्षेत्र में स्क्रोल करने का कोई फ़ायदा नहीं होता. लाइन बॉक्स और इमेज, मोनोलिथिक कॉन्टेंट के अन्य उदाहरण हैं. यहां एक उदाहरण दिया गया है:

देखें

अगर किसी कॉलम में एक ही कॉन्टेंट का बहुत ज़्यादा कॉन्टेंट फ़िट नहीं हो पा रहा है, तो लेगसी इंजन उसे काट देगा. इससे स्क्रोल किए जा सकने वाले कंटेनर को स्क्रोल करने पर, बहुत "दिलचस्प" व्यवहार दिखेगा:

इसे पहले कॉलम को ओवरफ़्लो होने देने के बजाय (जैसा कि LayoutNG ब्लॉक फ़्रैगमेंटेशन में होता है):

ALT_TEXT_HERE

लेगसी इंजन, फ़ोर्स किए गए ब्रेक के साथ काम करता है. उदाहरण के लिए, <div style="break-before:page;">, DIV से पहले पेज ब्रेक डालेगा. हालांकि, यह बिना किसी दबाव के ऑप्टिमाइज़ किए गए ब्रेक ढूंढने के लिए, सीमित सहायता देता है. यह break-inside:avoid और अनाथ और विधवा के साथ काम करता है. हालांकि, अगर break-before:avoid के ज़रिए अनुरोध किया जाता है, तो ब्लॉक के बीच के ब्रेक से बचने के लिए कोई सुविधा उपलब्ध नहीं है. इस उदाहरण पर ध्यान दें:

देखें

टेक्स्ट को दो कॉलम में बांटा गया है.

यहां, #multicol एलिमेंट में हर कॉलम में पांच लाइनें हो सकती हैं. इसकी वजह यह है कि इसकी ऊंचाई 100 पिक्सल है और लाइन-हाइट 20 पिक्सल है. इसलिए, #firstchild एलिमेंट की सभी लाइनें पहले कॉलम में फ़िट हो सकती हैं. हालांकि, इसके सिबलिंग #secondchild में break-before:avoid है. इसका मतलब है कि कॉन्टेंट के बीच ब्रेक नहीं होना चाहिए. widows की वैल्यू 2 होने पर, हमें ब्रेक से बचने के सभी अनुरोधों को पूरा करने के लिए, दूसरे कॉलम में #firstchild की दो लाइनें जोड़नी होंगी. Chromium, पहला ऐसा ब्राउज़र इंजन है जो इन सुविधाओं के कॉम्बिनेशन के साथ पूरी तरह से काम करता है.

NG फ़्रैगमेंटेशन कैसे काम करता है

आम तौर पर, NG लेआउट इंजन, सीएसएस बॉक्स ट्री को डीप-फ़र्स्ट तरीके से ट्रैवर्स करके दस्तावेज़ को लेआउट करता है. जब किसी नोड के सभी वंशजों को लेआउट किया जाता है, तो उस नोड का लेआउट पूरा किया जा सकता है. इसके लिए, NGPhysicalFragment बनाकर, पैरंट लेआउट एल्गोरिदम पर वापस जाना होगा. यह एल्गोरिदम, फ़्रैगमेंट को चाइल्ड फ़्रैगमेंट की सूची में जोड़ता है. सभी चाइल्ड फ़्रैगमेंट बन जाने के बाद, वह अपने लिए एक फ़्रैगमेंट जनरेट करता है. इसमें सभी चाइल्ड फ़्रैगमेंट शामिल होते हैं. इस तरीके से, यह पूरे दस्तावेज़ के लिए फ़्रैगमेंट ट्री बनाता है. हालांकि, यह एक ओवर-सिंप्लिफ़िकेशन है: उदाहरण के लिए, आउट-ऑफ़-फ़्लो पोज़ीशन किए गए एलिमेंट को रखने से पहले उनके डीओएम ट्री में मौजूद ब्लॉक से बबल अप करना होगा. हम यहां इस बेहतर जानकारी को अनदेखा कर रहे हैं, ताकि इसे आसानी से समझा जा सके.

LayoutNG, सीएसएस बॉक्स के साथ-साथ लेआउट एल्गोरिदम के लिए भी जगह उपलब्ध कराता है. इससे एल्गोरिदम को जानकारी मिलती है, जैसे कि लेआउट के लिए उपलब्ध जगह, नया फ़ॉर्मैटिंग कॉन्टेक्स्ट सेट किया गया है या नहीं, और पिछले कॉन्टेंट से मार्जिन को छोटा करने के बीच के नतीजे. कंस्ट्रेंट स्पेस में, फ़्रैगमेंटर के लेआउट किए गए ब्लॉक का साइज़ और उसमें मौजूदा ब्लॉक का ऑफ़सेट भी होता है. इससे यह पता चलता है कि ब्रेक कहां लेना है.

जब ब्लॉक को अलग-अलग हिस्सों में बांटा जाता है, तो ब्रेक पर वंश के लेआउट को रोकना पड़ता है. पेज या कॉलम में जगह खत्म होने या फ़ोर्स ब्रेक की वजह से, टेक्स्ट में ब्रेक लग सकता है. इसके बाद, हम उन नोड के लिए फ़्रैगमेंट बनाते हैं जिन्हें हमने विज़िट किया है. साथ ही, हम फ़्रैगमेंटेशन कॉन्टेक्स्ट रूट (मल्टीकॉल कंटेनर या प्रिंटिंग के मामले में, दस्तावेज़ रूट) तक वापस आ जाते हैं. इसके बाद, फ़्रैगमेंटेशन कॉन्टेक्स्ट रूट पर, हम नए फ़्रैगमेंटर के लिए तैयारी करते हैं और फिर से ट्री में नीचे जाते हैं. साथ ही, ब्रेक से पहले जहां से हमने छोड़ा था वहां से फिर से शुरू करते हैं.

ब्रेक के बाद लेआउट को फिर से शुरू करने का तरीका बताने वाले अहम डेटा स्ट्रक्चर को NGBlockBreakToken कहा जाता है. इसमें अगले फ़्रैगमेंटर में लेआउट को सही तरीके से फिर से शुरू करने के लिए ज़रूरी सारी जानकारी होती है. NGBlockBreakToken किसी नोड से जुड़ा होता है और यह NGBlockBreakToken ट्री बनाता है, ताकि जिस नोड को फिर से शुरू करना है उसे दिखाया जा सके. NGBlockBreakToken, अंदर ब्रेक करने वाले नोड के लिए जनरेट किए गए NGPhysicalBoxFragment से जुड़ा होता है. ब्रेक टोक़न, पैरंट टोक़न में भेजे जाते हैं. इससे ब्रेक टोक़न का ट्री बनता है. अगर हमें किसी नोड के अंदर के बजाय, उससे पहले ब्रेक करना है, तो कोई फ़्रैगमेंट नहीं बनाया जाएगा. हालांकि, पैरंट नोड को अब भी नोड के लिए "break-before" ब्रेक टोकन बनाना होगा, ताकि अगले फ़्रैगमेंटर में नोड ट्री में उसी पोज़िशन पर पहुंचने पर, हम उसे लेआउट करना शुरू कर सकें.

ब्रेक तब डाले जाते हैं, जब फ़्रैगमेंटेनर में जगह खत्म हो जाती है (बिना किसी वजह के ब्रेक) या जब ब्रेक का अनुरोध किया जाता है.

बेहतर ढंग से अनफ़ोर्स किए गए ब्रेक के लिए नियमों में कुछ नियम तय किए गए हैं. ज़रूरत के हिसाब से जहां ब्रेक खत्म हो जाता है, वहां ठीक ब्रेक डालना हमेशा सही नहीं होता. उदाहरण के लिए, break-before जैसी कई सीएसएस प्रॉपर्टी हैं, जो ब्रेक की जगह के चुनाव को प्रभावित करती हैं.

लेआउट के दौरान, बिना किसी रुकावट के ब्रेक वाले स्पेसिफ़िकेशन सेक्शन को सही तरीके से लागू करने के लिए, हमें अच्छे ब्रेकपॉइंट का ट्रैक रखना होगा. इस रिकॉर्ड का मतलब है कि हम वापस जाकर, मिले आखिरी सबसे अच्छे ब्रेकपॉइंट का इस्तेमाल कर सकते हैं. ऐसा तब होता है, जब किसी ऐसी जगह पर हम ब्रेक से बचने के अनुरोधों का उल्लंघन करते हैं जहां से हम ब्रेक से बचने के अनुरोधों (उदाहरण के लिए, break-before:avoid या orphans:7) का उल्लंघन करते हैं. हर संभावित ब्रेकपॉइंट के लिए स्कोर दिया जाता है. इसमें "इसे सिर्फ़ आखिरी उपाय के तौर पर करें" से लेकर "ब्रेकपॉइंट के लिए सबसे सही जगह" तक का स्कोर दिया गया है. इसके बीच में कुछ वैल्यू हो सकती हैं. अगर ब्रेक की जगह का स्कोर "बेहतरीन" है, तो इसका मतलब है कि अगर हम उसे तोड़ते हैं, तो उसके किसी भी नियम का उल्लंघन नहीं होगा (और अगर हमें जगह खत्म होने के बाद ही यह स्कोर मिल जाता है, तो आपको कुछ और करने की ज़रूरत नहीं है). अगर स्कोर "लास्ट-रिज़ॉर्ट" है, तो ब्रेकपॉइंट मान्य भी नहीं है. हालांकि, अगर हमें कोई बेहतर विकल्प नहीं मिलता है, तो फ़्रैगमेंटर ओवरफ़्लो से बचने के लिए, हम वहां ब्रेक कर सकते हैं.

मान्य ब्रेकपॉइंट आम तौर पर, सिबलिंग (लाइन बॉक्स या ब्लॉक) के बीच ही होते हैं. उदाहरण के लिए, पैरंट और उसके पहले चाइल्ड के बीच नहीं. हालांकि, क्लास C ब्रेकपॉइंट एक अपवाद हैं, लेकिन हमें यहां उनकी चर्चा करने की ज़रूरत नहीं है. उदाहरण के लिए, break-before:avoid वाले ब्लॉक सिबलिंग से पहले एक मान्य ब्रेकपॉइंट है, लेकिन यह "परफ़ेक्ट" और "लास्ट-रिज़ॉर्ट" के बीच कहीं है.

लेआउट के दौरान, हम NGEarlyBreak स्ट्रक्चर में मिले सबसे अच्छे ब्रेकपॉइंट का पता लगाते हैं. शुरुआती ब्रेक, ब्लॉक नोड के पहले या अंदर या लाइन के पहले (ब्लॉक कंटेनर लाइन या फ़्लेक्स लाइन) एक संभावित ब्रेकपॉइंट होता है. अगर सबसे अच्छा ब्रेकपॉइंट, किसी ऐसी जगह पर है जहां पहले हमने स्पेस खत्म होने पर, आगे बढ़ने से पहले रुकने का विकल्प नहीं चुना था, तो हम NGEarlyBreak ऑब्जेक्ट की चेन या पाथ बना सकते हैं. यहां एक उदाहरण दिया गया है:

देखें

इस मामले में, #second से ठीक पहले हमारे डिवाइस में जगह खत्म हो जाती है, लेकिन इसमें "break-before:avoid" का निशान है, जिसे "उल्लंघन से बचने के लिए वीडियो का उल्लंघन करने से बचें" का स्कोर मिलता है. उस समय हमारे पास "#outer के अंदर > #middle के अंदर > #inner के अंदर > "लाइन 3" से पहले"' की NGEarlyBreak चेन है, जिसमें "perfect" है. इसलिए, हम वहां ब्रेक लेना चाहेंगे. इसलिए हमें #outer की शुरुआत से लेआउट को फिर से चलाना और फिर से चलाना होगा (और इस बार हमने वह NGEarlyBreak पास कर दिया है, जो हमें मिला था), ताकि हम #inner में "लाइन 3" से पहले ब्रेक को रोक सकें. (हम "लाइन 3" से पहले ब्रेक लेते हैं, ताकि बाकी चार लाइनें अगले फ़्रैगमेंटर में जा सकें. साथ ही, widows:4 को सम्मान दिया जा सके.)

एल्गोरिदम को इस तरह से डिज़ाइन किया गया है कि वह हमेशा सबसे अच्छे ब्रेकपॉइंट पर रुक जाए. यह स्पेसिफ़िकेशन में बताया गया है. अगर सभी नियमों को पूरा नहीं किया जा सकता, तो एल्गोरिदम सही क्रम में नियमों को हटाकर, सबसे अच्छे ब्रेकपॉइंट पर रुक जाता है. ध्यान दें कि हमें हर फ़्रैगमेंटेशन फ़्लो के लिए, ज़्यादा से ज़्यादा एक बार लेआउट करना पड़ता है. दूसरे लेआउट पास के दौरान, लेआउट एल्गोरिदम को ब्रेक की सबसे अच्छी जगह पहले ही भेज दी जाती है. यह ब्रेक की वह जगह होती है जो पहले लेआउट पास में पता चली थी और उस राउंड में लेआउट आउटपुट के हिस्से के तौर पर दी गई थी. दूसरे लेआउट पास में, हम तब तक लेआउट नहीं कर रहे हैं, जब तक कि हमारे पास जगह खत्म नहीं हो जाती. असल में, हमारे पास जगह खत्म होने की उम्मीद नहीं है (यह असल में एक गड़बड़ी होगी), क्योंकि हमें ब्रेक को जल्दी डालने के लिए एक बेहतरीन जगह (जहां तक उपलब्ध थी) दी गई है, ताकि ब्रेक के किसी भी नियम का गलत तरीके से उल्लंघन न हो. इसलिए, हम उस बिंदु तक ही प्लान बनाते हैं और फिर ब्रेक लेते हैं.

इस बात का ध्यान रखें कि अगर फ़्रैगमेंटर ओवरफ़्लो से बचने में मदद मिलती है, तो कभी-कभी हमें ब्रेक से बचने के कुछ अनुरोधों का उल्लंघन करना पड़ता है. उदाहरण के लिए:

देखें

यहां #second से ठीक पहले स्पेस खत्म हो गया है, लेकिन इसमें "break-before:avoid" है. इसका अनुवाद, पिछले उदाहरण की तरह ही "break avoid का उल्लंघन" के तौर पर किया गया है. हमारे पास "अनाथ और विधवाओं का उल्लंघन" (#first के अंदर > "लाइन 2" से पहले) वाला NGEarlyBreak भी है, जो अब भी सही नहीं है, लेकिन "ब्रेक से बचने का उल्लंघन" से बेहतर है. इसलिए, हम अनाथ बच्चों / विडो के अनुरोध का उल्लंघन करने वाली "लाइन 2" से पहले की क्वेरी का जवाब देंगे. यह शर्त 4.4. अनफ़ोर्स्ड ब्रेक, जहां यह तय किया जाता है कि फ़्रैगमेंटानेर ओवरफ़्लो से बचने के लिए, हमारे पास ज़रूरत के मुताबिक ब्रेकपॉइंट न होने पर, ब्रेकिंग के कौनसे नियमों को पहले अनदेखा किया जाए.

नतीजा

LayoutNG ब्लॉक फ़्रैगमेंटेशन प्रोजेक्ट का फ़ंक्शनल लक्ष्य, लेगसी इंजन के साथ काम करने वाली सभी चीज़ों को LayoutNG-आर्किटेक्चर के साथ काम करने वाला बनाना था. साथ ही, बग ठीक करने के अलावा, इसमें कम से कम बदलाव करना था. हालांकि, break-before:avoid जैसे ब्रेक से बचने के लिए बेहतर सहायता देने की सुविधा को अपवाद माना गया है. इसकी वजह यह है कि यह फ़्रैगमेंटेशन इंजन का मुख्य हिस्सा है. इसलिए, इसे शुरू से ही शामिल करना ज़रूरी था. बाद में इसे जोड़ने का मतलब होगा कि इसे फिर से लिखना होगा.

LayoutNG ब्लॉक फ़्रैगमेंटेशन की प्रोसेस पूरी हो चुकी है. इसलिए, हम नई सुविधाएं जोड़ने पर काम कर सकते हैं. जैसे, प्रिंट करते समय अलग-अलग पेज साइज़ का इस्तेमाल करना, @page प्रिंट करते समय मार्जिन बॉक्स का इस्तेमाल करना, box-decoration-break:clone वगैरह. आम तौर पर, LayoutNG की तरह ही, हमें उम्मीद है कि समय के साथ नए सिस्टम में गड़बड़ी की दर और उसे मैनेज करने में लगने वाला समय काफ़ी कम हो जाएगा.

स्वीकार की गई

  • Una Kravets को, बेहतरीन "हाथ से बनाए गए स्क्रीनशॉट" के लिए.
  • क्रिस हैरलसन, प्रूफ़रीडिंग, सुझाव, और राय देने के लिए.
  • सुझाव, राय या शिकायत के लिए Philip Jägenstedt से संपर्क करें.
  • बदलाव करने और एक से ज़्यादा कॉलम वाले पहले उदाहरण के लिए, रेचल एंड्रयू.