बेसलाइन के साथ संरेखित इनलाइन छवियों की क्षैतिज पंक्ति में, बेसलाइन हर छवि के निचले मार्जिन किनारे पर होती है। यह गाइड बताती है कि Mac पर Chrome में उस निर्देशांक का पता कैसे लगाएँ, छोटे मार्कर से उसकी जाँच कैसे करें, और कैसे पहचानें कि यह तरीका कब लागू नहीं होता।
केवल छवियों वाली पंक्ति में बेसलाइन क्यों होती है?
केवल छवियों वाली पंक्ति भी CSS इनलाइन लेआउट में भाग लेती है। सफलतापूर्वक प्रदर्शित img एक प्रतिस्थापित एलिमेंट है: ब्राउज़र उसके बॉक्स का लेआउट CSS के अनुसार करता है, उसकी तस्वीर को टेक्स्ट नहीं मानता। WHATWG इस रेंडरिंग व्यवहार को HTML Standard के छवि-रेंडरिंग नियमों में दर्ज करता है।
सामान्य क्षैतिज इनलाइन लेआउट में, जिस छवि की अपनी टेक्स्ट बेसलाइन नहीं होती, वह बेसलाइन संरेखण के लिए अपना निचला मार्जिन किनारा इस्तेमाल करती है। इसलिए अलग-अलग ऊँचाई वाली दो बेसलाइन-संरेखित छवियाँ एक ही बेसलाइन साझा कर सकती हैं, जबकि उनके ऊपरी किनारे अलग-अलग ऊँचाइयों पर हों। यह नियम उनके बॉक्स पर लागू होता है; यह उनके भीतर की कलाकृति की जाँच नहीं करता। CSS 2, vertical alignment देखें।
तीन अलग-अलग सीमाएँ महत्वपूर्ण हैं:
| सीमा | अर्थ | बेसलाइन के उपयुक्त संदर्भ के रूप में? |
|---|---|---|
| दिखाई देने वाली कलाकृति का किनारा | जहाँ तस्वीर के दिखाई देने वाले पिक्सेल समाप्त होते हैं | नहीं; फ़ाइल में पारदर्शी खाली जगह हो सकती है |
| छवि के बॉर्डर-बॉक्स का निचला किनारा | getBoundingClientRect() से मिलने वाला निचला किनारा |
हाँ, नीचे का मार्जिन जोड़ने और बेसलाइन संरेखण की पुष्टि करने के बाद |
| लाइन-बॉक्स का निचला किनारा | पूरी CSS पंक्ति की निचली सीमा | नहीं; यह बेसलाइन से नीचे तक जा सकता है |
दिखाई देने वाले अक्षर न होने पर भी पैरेंट का फ़ॉन्ट और line-height मायने रखते हैं। CSS एक अदृश्य फ़ॉन्ट-आधारित योगदान का वर्णन करता है, जिसे स्ट्रट कहते हैं। यह पंक्ति की न्यूनतम ऊँचाई और गहराई तय करने में मदद करता है। इससे समझ आता है कि छवि बेसलाइन पर बैठ सकती है, फिर भी उसके नीचे पंक्ति में जगह बनी रह सकती है। CSS Inline Layout विनिर्देश इन फ़ॉन्ट मेट्रिक्स और लेआउट सीमाओं का वर्णन करता है; इसका प्राप्त प्रकाशित संस्करण एक Working Draft है, इसलिए यह नहीं मानना चाहिए कि इसकी नई सुविधाओं को सभी ब्राउज़र समर्थन देते हैं।
मौजूदा पेज पर बेसलाइन कैसे ढूँढ़ें?
Mac पर Chrome में कोई ऐसा पेज खोलें जिसकी जाँच आप कर सकें। किसी छवि पर दायाँ-क्लिक करें और Inspect चुनें। Chrome उस एलिमेंट को चुना हुआ रखते हुए Elements पैनल खोलता है; Styles पैन में उस पर लागू CSS दिखाई देती है। Google इस तरीके को Chrome DevTools खोलें में दर्ज करता है।
निर्देशांक निकालने से पहले इन शर्तों की जाँच करें:
- छवि लक्षित पंक्ति में सामान्य इनलाइन फ़्लो में भाग लेती हो।
- उसका प्रभावी संरेखण
vertical-align: baselineहो। - लेखन मोड क्षैतिज हो।
- मापन को प्रभावित करने वाला कोई ट्रांसफ़ॉर्म या दृश्य स्थिति-ऑफ़सेट छवि या उसके पूर्वजों पर लागू न हो।
- आप छवि को माप रहे हों, उसके आसपास के ऐसे रैपर को नहीं जिसका अपना बेसलाइन व्यवहार हो।
ये शर्तें गणना का दायरा तय करती हैं। उदाहरण के लिए, vertical-align: bottom किसी एलिमेंट को पंक्ति के निचले किनारे से संरेखित करता है, जबकि middle पैरेंट की बेसलाइन में उसकी x-height का आधा जोड़ता है। इनमें से किसी मान का अर्थ यह नहीं है कि छवि का निचला किनारा पैरेंट की बेसलाइन बताता है। MDN अपने vertical-align संदर्भ में इन अंतरों को समझाता है।
इन शर्तों के पूरा होने पर, CSS पिक्सेल में दूरी व्यक्त करते हुए यह संबंध इस्तेमाल करें:
baselineY = imageBorderBoxBottom + imageMarginBottom
getBoundingClientRect() व्यूपोर्ट के सापेक्ष बॉर्डर-बॉक्स का निचला किनारा देता है। उसके आयत में पैडिंग और बॉर्डर शामिल होते हैं, इसलिए उन्हें दोबारा नहीं जोड़ना चाहिए। मार्जिन उस आयत के बाहर होते हैं। MDN Element.getBoundingClientRect() में लौटाए गए ज्यामितीय माप और निर्देशांक प्रणाली का दस्तावेज़ देता है।
स्पष्ट रूप से उदाहरण के लिए मान लें कि छवि के बॉर्डर-बॉक्स का निचला किनारा 240.5 है और उसका निचला मार्जिन 6 है। इसलिए बेसलाइन व्यूपोर्ट के ऊपरी किनारे से 246.5 CSS पिक्सेल नीचे है। यदि कंटेनर के बॉर्डर-बॉक्स का ऊपरी किनारा 200 है, तो वह बेसलाइन कंटेनर के ऊपरी बॉर्डर किनारे से 46.5 CSS पिक्सेल नीचे है। यह बॉर्डर किनारे से मापा गया ऑफ़सेट है, अपने आप कंटेंट किनारे से नहीं।
उसी पंक्ति में किसी दूसरी उपयुक्त छवि को दोबारा मापकर पुष्टि करें। उसकी ऊँचाई अलग होने पर भी उसका निचला मार्जिन किनारा उसी बेसलाइन को दिखाना चाहिए। यदि दोनों में अंतर हो, तो CSS बदलने से पहले संरेखण, रैपर, पोज़िशनिंग या पंक्ति-विभाजन की जाँच करें। तुलना करते समय भिन्नात्मक मान बनाए रखें।
बेसलाइन मार्कर से नतीजे की पुष्टि कैसे करें?
एक उपयोगी निदान तरीका है ऐसा खाली इनलाइन-ब्लॉक, जिसकी चौड़ाई, ऊँचाई, मार्जिन, पैडिंग और बॉर्डर शून्य हों और जो बेसलाइन से संरेखित हो। चूँकि इसमें फ़्लो के भीतर कोई लाइन-बॉक्स नहीं होता, इसकी बेसलाइन इसका निचला मार्जिन किनारा होती है। ये सभी माप शून्य होने पर वह किनारा उसके मापे गए ऊर्ध्वाधर स्थान से मेल खाता है। यह CSS 2 के इनलाइन-ब्लॉक बेसलाइन नियम के अनुरूप है।
यह पूरा कंसोल प्रोग्राम दो तटस्थ आयताकार छवियों और एक मार्कर से अस्थायी प्रदर्शन बनाता है। यह नमूने की आंतरिक शैलियों को सामान्य पेज सिलेक्टरों से अलग रखने के लिए शैडो रूट का इस्तेमाल करता है। इसे स्टैंडर्ड्स मोड वाले ऐसे दस्तावेज़ में चलाएँ, जिसके दस्तावेज़ या बॉडी पर कोई ट्रांसफ़ॉर्म लागू न हो। यह केवल अपनी कृत्रिम पंक्ति को मापता है, किसी मौजूदा पेज की सामग्री को नहीं।
Chrome के DevTools शॉर्टकट में बताए अनुसार Command + Option + J दबाकर Console खोलें और प्रोग्राम चलाएँ। किसी लाइब्रेरी को इंस्टॉल करने या बाहरी छवि फ़ाइल की ज़रूरत नहीं है। यह नमूना स्टैंडर्ड Canvas API से आयत बनाता है।
(async () => {
if (document.compatMode !== "CSS1Compat") {
throw new Error("Use a standards-mode document for this demonstration.");
}
const host = document.createElement("div");
host.style.cssText =
"all:initial;position:fixed;top:16px;left:16px;" +
"z-index:2147483647;background:white;padding:16px;" +
"color:#222;font:16px/1.5 sans-serif;";
const root = host.attachShadow({ mode: "open" });
const label = document.createElement("div");
label.textContent = "Sample A and Sample B";
const row = document.createElement("div");
row.style.cssText =
"display:block;position:relative;width:280px;" +
"margin:0;padding:0;border:0;white-space:nowrap;" +
"writing-mode:horizontal-tb;font:16px/24px sans-serif;" +
"background:#eee;";
const close = document.createElement("button");
close.textContent = "Remove demonstration";
close.addEventListener("click", () => host.remove());
root.append(label, row, close);
document.body.append(host);
try {
const images = [];
const samples = [
{ label: "Sample A", height: 32, color: "#777" },
{ label: "Sample B", height: 48, color: "#aaa" }
];
for (const sample of samples) {
const canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = sample.height;
const context = canvas.getContext("2d");
if (!context) throw new Error("A 2D canvas context is required.");
context.fillStyle = sample.color;
context.fillRect(0, 0, canvas.width, canvas.height);
const image = document.createElement("img");
image.alt = sample.label;
image.width = 64;
image.height = sample.height;
image.style.cssText =
"display:inline;vertical-align:baseline;" +
"margin:0 12px 0 0;padding:0;border:0;";
image.src = canvas.toDataURL("image/png");
row.append(image);
images.push(image);
}
await Promise.all(images.map(image => image.decode()));
if (!host.isConnected) return;
const marker = document.createElement("span");
marker.style.cssText =
"display:inline-block;vertical-align:baseline;" +
"width:0;height:0;margin:0;padding:0;border:0;" +
"font-size:0;line-height:0;";
row.append(marker);
const baselineY = marker.getBoundingClientRect().bottom;
const rowTop = row.getBoundingClientRect().top;
console.table(images.map(image => ({
sample: image.alt,
imageBottom: image.getBoundingClientRect().bottom,
markerBaseline: baselineY,
baselineFromRowTop: baselineY - rowTop
})));
const guide = document.createElement("div");
guide.style.cssText =
"position:absolute;left:0;right:0;height:1px;" +
"background:#222;pointer-events:none;";
guide.style.top = `${baselineY - rowTop}px`;
row.append(guide);
} catch (error) {
host.remove();
throw error;
}
})();
माप लेने से पहले प्रोग्राम दोनों छवियों के डिकोड होने की प्रतीक्षा करता है। दस्तावेज़ीकृत HTMLImageElement.decode() विधि एक प्रॉमिस लौटाती है और डिकोडिंग विफल होने पर अस्वीकार हो सकती है; ऐसी स्थिति में प्रोग्राम अस्थायी पैनल हटाकर त्रुटि बताता है।
दोनों छवियों का निचला मार्जिन शून्य है, इसलिए उनकी रिपोर्ट की गई imageBottom वैल्यू markerBaseline के बराबर होनी चाहिए। पतली क्षैतिज गाइड उस निर्देशांक को दर्शाती है। पंक्ति की पृष्ठभूमि आपको बेसलाइन और उसके नीचे बची जगह के बीच अंतर करने में भी मदद करती है। काम पूरा होने पर Remove demonstration चुनें।
नियंत्रित प्रयोग के लिए, छवि शैली में नमूना छवियों का निचला मार्जिन 0 से बदलकर 6px करें। तब उनके बॉर्डर-बॉक्स के निचले किनारे मार्कर की बेसलाइन से छह CSS पिक्सेल ऊपर होने चाहिए। साझा निर्देशांक निकालने के लिए पहले वाला सूत्र लागू करें। इससे नमूने में दो स्वतंत्र संदर्भ मिलते हैं: छवि का मार्जिन किनारा और खाली मार्कर।
इस तरीके के लिए कब अलग दृष्टिकोण चाहिए?
मार्कर एक निदान के लिए जोड़ा गया एलिमेंट है, इसलिए यह बदले हुए लेआउट को मापता है। किसी भी मौजूदा पैराग्राफ में उसे जोड़ने से पंक्ति-विभाजन का अवसर बन सकता है या लेआउट किसी और तरह प्रभावित हो सकता है। जब आवश्यक शर्तें पूरी हों, तो मौजूदा छवि की गणना को प्राथमिकता दें। यदि आप वास्तविक सामग्री में मार्कर डालते हैं, तो पुष्टि करें कि वही छवियाँ उसी पंक्ति में बनी हुई हैं और उनकी स्थिति नहीं बदली है।
| स्थिति | उपयुक्त अगला कदम |
|---|---|
छवियों में top, bottom, या middle संरेखण इस्तेमाल होता है |
उस संरेखण नियम की जाँच करें; बेसलाइन-संरेखित छवि वाला सूत्र ज्यों का त्यों लागू न करें |
| छवि इनलाइन-ब्लॉक रैपर के भीतर है | रैपर की बेसलाइन जाँचें, जो उसकी सामग्री की आखिरी पंक्ति से आ सकती है |
| छवियाँ कई लिपटी हुई पंक्तियों में हैं | हर पंक्ति की बेसलाइन अलग-अलग तय करें |
| पैरेंट फ्लेक्स या ग्रिड लेआउट इस्तेमाल करता है | पंक्ति को इनलाइन पंक्ति मानने से पहले उस लेआउट के संरेखण नियम जाँचें |
| दस्तावेज़ में ऊर्ध्वाधर लेखन है | नीचे के किनारे के y-निर्देशांक के बजाय लेखन-मोड के अनुसार बेसलाइन नियम इस्तेमाल करें |
| छवि सफलतापूर्वक लोड नहीं हुई है | उसे प्रदर्शित छवि-बॉक्स मानने से पहले उसकी रेंडरिंग स्थिति स्पष्ट करें |
आखिरी शर्त महत्वपूर्ण है, क्योंकि WHATWG प्रदर्शित छवियों, लंबित छवियों और वैकल्पिक टेक्स्ट के लिए अलग-अलग रेंडरिंग पथों का वर्णन करता है। इसलिए टूटी हुई छवि अपना लेबल दिखा रही हो, तो उसकी व्याख्या उस सफलतापूर्वक रेंडर हुई छवि से अलग हो सकती है जिसे आप मापना चाहते थे। HTML के छवि-रेंडरिंग नियम देखें।
केवल इसलिए एक साझा बेसलाइन का अनुमान न लगाएँ कि कई छवि आयतों के ऊपरी निर्देशांक लगभग समान हैं। अलग-अलग ऊँचाई वाली छवियाँ एक ही बेसलाइन साझा कर सकती हैं और उनके ऊपरी किनारे अलग हो सकते हैं। इसके उलट, ऊपरी किनारों का संरेखित होना बेसलाइन संरेखण साबित नहीं करता। पुष्टि करें कि कौन-से बॉक्स एक ही पंक्ति में भाग लेते हैं और कौन-सा संरेखण नियम लागू होता है।
क्या टेक्स्ट-मापन API या शेपिंग लाइब्रेरी उत्तर दे सकती हैं?
यहाँ इस्तेमाल की गई ब्राउज़र ज्यामिति विधियाँ आयत लौटाती हैं, कोई समर्पित लाइन-बेसलाइन फ़ील्ड नहीं। Range.getClientRects() किसी रेंज द्वारा घेरे गए क्षेत्रों की जाँच में मदद कर सकता है, लेकिन लौटाए गए आयत सीधे बेसलाइन निर्देशांक नहीं देते। MDN इस इंटरफ़ेस को Range.getClientRects() में समझाता है।
कैनवस टेक्स्ट मेट्रिक्स एक अलग सवाल का जवाब देते हैं: कैनवस टेक्स्ट का कोई अंश कैनवस कॉन्टेक्स्ट के चुने हुए टेक्स्ट बेसलाइन से कैसे संबंधित है। उदाहरण के लिए, actualBoundingBoxAscent और actualBoundingBoxDescent उस संदर्भ के सापेक्ष टेक्स्ट की स्याही की सीमाओं का वर्णन करते हैं। वे किसी मौजूदा DOM छवि-पंक्ति का स्थान सीधे नहीं बताते। MDN का TextMetrics दस्तावेज़ देखें।
टेक्स्ट-शेपिंग लाइब्रेरी की ज़िम्मेदारी भी ब्राउज़र के लाइन लेआउट से सीमित है। HarfBuzz मैनुअल कहता है कि यह टेक्स्ट रन को शेप करता है और ग्लिफ़ लेआउट की जानकारी देता है, जबकि पैराग्राफ में लाइन तोड़ना और जस्टिफ़िकेशन इसकी ज़िम्मेदारी में नहीं आते। इसलिए HarfBuzz इंस्टॉल करने से ब्राउज़र की केवल-छवियों वाली पंक्ति का माप नहीं मिलता। इसकी दस्तावेज़ीकृत सीमा इस अंतर को स्पष्ट करती है।
क्षैतिज केवल-छवि पंक्ति के लिए पहले सामान्य इनलाइन फ़्लो और बेसलाइन संरेखण की पुष्टि करें। फिर किसी उपयुक्त छवि के बॉर्डर-बॉक्स का निचला किनारा पढ़ें और उसमें उसका निचला मार्जिन जोड़ें। दृश्य पुष्टि के लिए नियंत्रित लेआउट में शून्य-आकार का मार्कर इस्तेमाल करें, और जब उन दोनों संदर्भों में अंतर हो तो फ़ॉर्मेटिंग कॉन्टेक्स्ट का दोबारा आकलन करें।
स्रोत
HTML Standard: Rendering — WHATWG।
HTML Standard: The canvas element — WHATWG।
Chrome DevTools खोलें — Google Chrome for Developers।
vertical-align CSS property — MDN Web Docs।
Element: getBoundingClientRect() method — MDN Web Docs।
HTMLImageElement: decode() method — MDN Web Docs।
Range: getClientRects() method — MDN Web Docs।
TextMetrics — MDN Web Docs।
What HarfBuzz doesn’t do — HarfBuzz।