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

Morten Stenshorne
Morten Stenshorne

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

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

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

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

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

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

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

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

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

LayoutNG में ब्लॉक फ़्रैगमेंटेशन अब पूरा हो गया है

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

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

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

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

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

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

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

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

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

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

प्री-पेंट ट्री की सैर

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

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

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

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

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

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

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

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

एक कॉलम के तौर पर, पेज को इस तरह दिखाया गया है कि कॉन्टेंट ब्रेक होता है और स्क्रीन पर तीन कॉलम दिखते हैं

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

यहां टेक्स्ट-शैडो का एक उदाहरण दिया गया है:

लेगसी इंजन, इसे सही तरीके से हैंडल नहीं करता है:

दूसरे कॉलम में क्लिप की गई टेक्स्ट शैडो.

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

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

टेक्स्ट के दो कॉलम, जिनकी परछाई सही तरीके से दिख रही है.

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

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

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

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

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

ALT_TEXT_HERE

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

नतीजा

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

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

स्वीकार की गई

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