ब्राउज़र टेक्स्ट पूर्वावलोकन का आकार तय करने के लिए, इच्छित व्यूपोर्ट चौड़ाई पर लेआउट किए गए DOM एलिमेंट को मापें। एकल-पंक्ति टेक्स्ट मेट्रिक्स के लिए Canvas का उपयोग करें। यह गाइड दिखाती है कि Mac पर दोनों की तुलना कैसे करें और समझें कि उनकी चौड़ाइयाँ और ऊँचाइयाँ अलग क्यों होती हैं।

व्यावहारिक काम यह पता लगाना है कि ब्राउज़र व्यूपोर्ट बदलने पर एक कृत्रिम कार्ड लेबल को कितनी जगह चाहिए। उपयोगी परिणाम में व्यूपोर्ट, उपलब्ध टेक्स्ट चौड़ाई, फ़ॉन्ट सेटिंग और मापा गया बॉक्स एक साथ दर्ज होते हैं। इन स्थितियों के बिना चौड़ाई को दोबारा प्राप्त करना कठिन है।

आपको टेक्स्ट की कौन-सी चौड़ाई और ऊँचाई मापनी चाहिए?

ब्राउज़र API आकार मापने से जुड़े कई अलग-अलग सवालों के जवाब देते हैं। कुछ भी गणना करने से पहले वह माप चुनें जो आपके निर्णय से मेल खाता हो।

आपका सवाल माप यह किसे दर्शाता है
एक बिना रैप हुई स्ट्रिंग क्षैतिज दिशा में कितनी आगे तक जाती है? Canvas measureText(text).width टेक्स्ट की अग्रगति चौड़ाई
Canvas ग्लिफ़ आकृतियों की सीमाएँ क्या हैं? Canvas actualBoundingBox… प्रॉपर्टीज़ संरेखण बिंदु और बेसलाइन के सापेक्ष ग्लिफ़ की सीमाएँ
कार्ड कितनी लेआउट जगह घेरता है? एलिमेंट getBoundingClientRect() उसका बॉर्डर बॉक्स, जिसमें पैडिंग और बॉर्डर शामिल हैं
रैप होने के बाद टेक्स्ट के खंड कहाँ हैं? Range getClientRects() चुने गए टेक्स्ट से जुड़े आयत
इन टेक्स्ट खंडों को कौन-सा आयत घेरता है? Range getBoundingClientRect() उनका संयुक्त बाउंडिंग आयत

Canvas की अग्रगति चौड़ाई और ग्लिफ़ चौड़ाई अलग हो सकती हैं: इटैलिक आकृतियाँ अपनी अग्रगति सीमा से बाहर तक जा सकती हैं। ग्लिफ़ की सीमाओं के लिए, चौड़ाई actualBoundingBoxLeft + actualBoundingBoxRight और ऊँचाई actualBoundingBoxAscent + actualBoundingBoxDescent से निकालें। ये माप CSS पिक्सेल में होते हैं। TextMetrics — MDN

एलिमेंट के माप में पैडिंग और बॉर्डर शामिल होते हैं, जबकि केवल टेक्स्ट वाला Range फ़ॉन्ट मेट्रिक्स का उपयोग करके चुने गए टेक्स्ट को मापता है। इनमें से किसी को भी रंगे गए पिक्सेल का सटीक आयत नहीं कहना चाहिए। W3C विनिर्देश Range के क्षैतिज टेक्स्ट आयतों को एसेंट, डिसेंट और टेक्स्ट अग्रगति के आधार पर परिभाषित करता है। Element: getBoundingClientRect() method — MDN, CSSOM View Module — W3C

ब्राउज़र आकार के पूर्वावलोकन के लिए, जगह आवंटित करने हेतु एलिमेंट बॉक्स का उपयोग करें और टेक्स्ट के प्रवाह की जाँच के लिए Range आयतों का। बिना रैप हुई स्ट्रिंग के अलग संदर्भ के रूप में Canvas के माप रखें।

पहले व्यूपोर्ट और टेक्स्ट की स्थितियाँ सेट करें

अपने Mac पर Chrome में DevTools खोलें, Toggle device toolbar चालू करें और Dimensions के अंतर्गत Responsive चुनें। व्यूपोर्ट फ़ील्ड में इच्छित चौड़ाई और ऊँचाई दर्ज करें। Chrome में संख्याएँ दर्ज करने और व्यूपोर्ट का आकार खींचकर बदलने, दोनों तरीकों का विवरण दिया गया है। डेस्कटॉप पूर्वावलोकन के लिए, यदि यह नियंत्रण उपलब्ध हो तो डेस्कटॉप डिवाइस प्रकार चुनें। Simulate mobile devices with device mode — Chrome for Developers

व्यूपोर्ट की चौड़ाई और टेक्स्ट की चौड़ाई में अंतर समझें। किसी कार्ड की अधिकतम चौड़ाई, बाहरी मार्जिन, पैडिंग और बॉर्डर हो सकते हैं। कार्ड के अधिकतम आकार तक पहुँचने के बाद, ब्राउज़र की चौड़ाई बढ़ाने से उसका टेक्स्ट क्षेत्र और चौड़ा नहीं होगा।

उदाहरण के लिए, मान लें कि कार्ड की बॉर्डर-बॉक्स चौड़ाई 360px, दोनों ओर क्षैतिज पैडिंग 16px और दो 1px बॉर्डर हैं। इसकी उपलब्ध कंटेंट चौड़ाई 360 − 32 − 2 = 326px है। रैप होने के लिए यही चौड़ाई उपलब्ध है। एलिमेंट का बाउंडिंग आयत फिर भी 360px दिखाता है। यह बॉर्डर-बॉक्स माप के दस्तावेज़ित व्यवहार के अनुरूप है। Element: getBoundingClientRect() method — MDN

इच्छित फ़ॉन्ट फ़ैमिली, वज़न, आकार, शैली, लाइन ऊँचाई, स्पेसिंग और रैपिंग नियमों से मेल बैठाएँ। खास तौर पर, white-space: normal खाली जगह को समेटता है और रैपिंग की अनुमति देता है, जबकि pre-wrap खाली जगह और स्रोत की नई पंक्तियों को बनाए रखते हुए रैपिंग की अनुमति देता है। एक का उपयोग करने वाला पूर्वावलोकन दूसरे का विश्वसनीय प्रतिनिधित्व नहीं कर सकता। white-space — MDN

फ़ॉन्ट आकार और लाइन ऊँचाई में भी अंतर समझें। क्षैतिज लेखन में, line-height लाइन-बॉक्स की ऊँचाई तय करने में शामिल होता है; यह अक्षरों की दिखाई देने वाली ऊँचाई नहीं बताता। इसलिए 24px लाइन ऊँचाई वाले 16px फ़ॉन्ट के लिए Canvas ग्लिफ़ सीमाओं से अलग ऊँचाई गणना चाहिए। line-height — MDN

एक पूरा कृत्रिम टेक्स्ट पूर्वावलोकन चलाएँ

खाली टैब खोलें, DevTools खोलें, Console चुनें और नीचे दी गई पूरी ब्राउज़र स्क्रिप्ट एक बार चलाएँ। यह एक साधारण कार्ड और मापों की रिपोर्ट बनाती है। इसके लिए किसी लाइब्रेरी, बाहरी फ़ॉन्ट, मौजूदा सिलेक्टर या HTML फ़ाइल की ज़रूरत नहीं है। इसकी दूसरी कॉपी चलाने से पहले खाली टैब को फिर से लोड करें।

कार्ड व्यूपोर्ट के साथ आकार बदलता है, जब तक कि वह 480px की बॉर्डर-बॉक्स चौड़ाई तक न पहुँच जाए। विंडो या अनुकरण किए गए व्यूपोर्ट का आकार बदलने पर रिपोर्ट अपडेट होती है। यह उदाहरण जानबूझकर एक साधारण क्षैतिज टेक्स्ट ब्लॉक और एकसमान शैली तक सीमित है। ब्राउज़र पर निर्भर कोड की जाँच की गई है; तैयारी के दौरान उसे ब्राउज़र में चलाया नहीं गया।

(async () => {
  const text =
    "Sample collection: round forms, soft gradients, and simple patterns.";

  document.body.style.margin = "0";

  const card = document.createElement("div");
  card.textContent = text;
  card.lang = "en";
  card.dir = "ltr";
  card.style.cssText = [
    "box-sizing: border-box",
    "width: min(480px, calc(100% - 48px))",
    "margin: 24px",
    "padding: 16px",
    "border: 1px solid #777",
    "font: normal 400 16px/24px Arial, sans-serif",
    "font-kerning: normal",
    "letter-spacing: 0px",
    "word-spacing: 0px",
    "white-space: normal",
    "overflow-wrap: normal",
    "word-break: normal",
    "hyphens: none",
    "color: #222",
    "background: #f4f4f4"
  ].join(";");

  const report = document.createElement("pre");
  report.style.cssText =
    "margin: 24px; white-space: pre-wrap; overflow-wrap: anywhere;";
  document.body.append(card, report);

  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  if (!ctx) {
    report.textContent = "A Canvas 2D context is unavailable.";
    return;
  }

  // Establish layout before waiting for the fonts used by that layout.
  card.getBoundingClientRect();
  await document.fonts.ready;

  const format = value =>
    Number.isFinite(value) ? value.toFixed(2) : "unavailable";

  function measure() {
    const style = getComputedStyle(card);
    const box = card.getBoundingClientRect();
    const horizontalExtras =
      parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) +
      parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);

    const range = document.createRange();
    range.selectNodeContents(card);
    const textBox = range.getBoundingClientRect();
    const fragments = Array.from(range.getClientRects());

    ctx.font = "normal 400 16px Arial, sans-serif";
    ctx.fontKerning = "normal";
    ctx.direction = "ltr";
    ctx.textAlign = "left";
    ctx.textBaseline = "alphabetic";
    const metrics = ctx.measureText(text);
    const inkWidth =
      metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight;
    const inkHeight =
      metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

    report.textContent = [
      "All dimensions below are CSS pixels.",
      `Layout viewport: ${document.documentElement.clientWidth} x ${document.documentElement.clientHeight}`,
      `Card border box: ${format(box.width)} x ${format(box.height)}`,
      `Available text width: ${format(box.width - horizontalExtras)}`,
      `Range bounds: ${format(textBox.width)} x ${format(textBox.height)}`,
      `Range fragment count: ${fragments.length}`,
      `Canvas unwrapped advance: ${format(metrics.width)}`,
      `Canvas glyph bounds: ${format(inkWidth)} x ${format(inkHeight)}`,
      `Computed line height: ${style.lineHeight}`
    ].join("\n");
  }

  measure();
  window.addEventListener("resize", measure);
})().catch(error => console.error("Preview failed:", error));

एलिमेंट और Range कॉल ब्राउज़र के वास्तविक लेआउट का उपयोग करते हैं। Canvas उसी कृत्रिम स्ट्रिंग को एक बिना रैप हुए रन के रूप में मापता है। HTML Standard के Canvas टेक्स्ट प्रिपरेशन में ASCII खाली जगह को स्पेस से बदल दिया जाता है; measureText() में न्यूलाइन देने से CSS का कई पंक्तियों वाला पैराग्राफ नहीं बनता। HTML Standard: The canvas element — WHATWG

लेआउट स्थापित करने के बाद स्क्रिप्ट document.fonts.ready का इंतज़ार करती है। MDN के अनुसार, यह प्रॉमिस तब पूरा होता है जब उपयोग में आने वाले फ़ॉन्टों के लिए लोडिंग और लेआउट ऑपरेशन समाप्त हो जाते हैं। इसका अर्थ यह नहीं है कि हर घोषित फ़ॉन्ट लोड हो गया है या स्क्रीन पर वही फ़ॉन्ट दिखेगा जिसे मूल रूप से प्राथमिकता दी गई थी। Document: fonts property — MDN

नतीजे पढ़ें और तय करें कि टेक्स्ट फिट होता है या नहीं

Available text width से शुरुआत करें, फिर दो व्यूपोर्ट आकारों पर कार्ड की ऊँचाई की तुलना करें। रैपिंग से एक पंक्ति जुड़ने पर कार्ड की ऊँचाई बदलती है, जबकि Canvas की बिना रैप वाली अग्रगति अपरिवर्तित रह सकती है। यह संयोजन रैपिंग में बदलाव को फ़ॉन्ट में बदलाव से अलग पहचानने में मदद करता है।

इस उदाहरण में, नीचे दी गई चौड़ाइयाँ केवल गणना समझाने के लिए हैं; ये मापे गए फ़ॉन्ट नतीजे नहीं हैं। ये मानती हैं कि लेआउट व्यूपोर्ट की चौड़ाई बताई गई चौड़ाई के बराबर है और स्क्रिप्ट की शैलियाँ अपरिवर्तित हैं।

लेआउट व्यूपोर्ट की चौड़ाई कार्ड की बॉर्डर-बॉक्स चौड़ाई उपलब्ध टेक्स्ट चौड़ाई
360px 312px 278px
800px 480px 446px
1200px 480px 446px

आखिरी दो पंक्तियाँ बताती हैं कि ब्राउज़र चौड़ा करने पर भी टेक्स्ट की रैपिंग क्यों अपरिवर्तित रह सकती है: कार्ड अपनी अधिकतम चौड़ाई तक पहुँच चुका है। केवल व्यूपोर्ट बदलने से कार्ड के लिए अधिक कंटेंट जगह नहीं बनती।

एक साधारण ब्लॉक में केवल एकसमान टेक्स्ट हो, तो 24px लाइन ऊँचाई पर तीन पंक्तियों का उदाहरणात्मक लेआउट 72px लाइन-बॉक्स जगह घेरता है। 32px की लंबवत पैडिंग और 2px के बॉर्डर जोड़ें, तो कार्ड की उदाहरणात्मक ऊँचाई 106px होगी। यह गणना नतीजे को समझने के लिए उपयोगी है; जब कंटेंट या शैली अधिक जटिल हो जाए, तो मापा गया DOM ऊँचाई का मान ही निर्णायक है। line-height — MDN

Range fragment count को हर स्थिति में पंक्तियों की संख्या न मानें। Range API अपने चयन नियमों के अनुसार टेक्स्ट और एलिमेंट आयत लौटाता है। रिच टेक्स्ट, नेस्टेड एलिमेंट और खंडित लेआउट से आयतों का अधिक जटिल समूह बन सकता है। इस निदान को समझने योग्य रखने के लिए नमूना केवल एक साधारण टेक्स्ट नोड चुनता है। CSSOM View Module — W3C

इसी तरह, ceil(unwrappedWidth / availableWidth) से रैप हुई ऊँचाई का अनुमान लगाने से बचें। यह फ़ॉर्मूला मानता है कि टेक्स्ट क्षैतिज दिशा में किसी भी जगह टूट सकता है। ब्राउज़र रैपिंग को कॉन्फ़िगर किए गए खाली जगह और ब्रेकिंग व्यवहार का पालन करना होता है, इसलिए इसके बजाय रैप हुए ब्लॉक को मापें। white-space — MDN

मापों में अंतर हो तो क्या जाँचें?

सबसे पहले माप की सीमा जाँचें। पूरे कार्ड का आयत और उससे संकरा Range आयत, दोनों सही हो सकते हैं। कार्ड लेआउट जगह आरक्षित करता है; Range उसके चुने गए टेक्स्ट का वर्णन करता है। Canvas ग्लिफ़ की ऊँचाई तीसरा मान देती है, जिसका उद्देश्य अलग है।

इसके बाद फ़ॉन्ट की तैयारी जाँचें। घोषित वेब फ़ॉन्ट जोड़ने पर, मापने से पहले मेल खाने वाले फ़ॉन्ट फ़ेस स्पष्ट रूप से माँगने के लिए document.fonts.load(fontSpecification, sampleText) का उपयोग किया जा सकता है। अस्वीकृति को संभालें, ताकि बिना बताए किसी वैकल्पिक फ़ॉन्ट से सफल नतीजा न मिले। वैकल्पिक टेक्स्ट तर्क यूनिकोड रेंज के आधार पर फ़िल्टर करता है; यह हर ग्लिफ़ के उपलब्ध होने की पुष्टि नहीं करता। FontFaceSet: load() method — MDN

लेबल की चौड़ाई की गणना करते समय शेपिंग की सीमाएँ बनाए रखें। हर अक्षर की अलग-अलग मापी गई चौड़ाइयाँ जोड़ने के बजाय पूरी स्ट्रिंग को मापें। Canvas विनिर्देश मौजूदा फ़ॉन्ट और टेक्स्ट सेटिंग का उपयोग करके स्थित ग्लिफ़ रन तैयार करता है; उस स्ट्रिंग के लिए यही उचित इकाई है। इस नमूने में Canvas तुलना को बताई गई फ़ॉन्ट सेटिंग तक सीमित रखें और यह न मानें कि यह CSS की हर टाइपोग्राफ़ी सुविधा को दोहराती है। HTML Standard: The canvas element — WHATWG

मौजूदा पेज के लिए, उसके वास्तविक कंपोनेंट को उसी जगह मापें। टेक्स्ट को किसी सामान्य छिपे हुए बॉक्स में ले जाने से लेआउट की स्थितियाँ बदल जाती हैं, जब तक कि आप उसकी प्रासंगिक शैलियों और कंटेनर संदर्भ को भी न दोहराएँ। जुड़े हुए लेआउट बॉक्स के बिना एलिमेंट सामान्य बॉक्स माप के लिए उपयोगी मान नहीं दे सकते, और CSS ट्रांसफ़ॉर्म इन API द्वारा लौटाए गए आयतों को प्रभावित करते हैं। कृत्रिम उदाहरण इन दोनों जटिलताओं से बचता है। CSSOM View Module — W3C

कई ब्राउज़र आकारों पर पूर्वावलोकन कैसे दोहराएँ?

कभी-कभार जाँच के लिए, हर व्यूपोर्ट आकार हाथ से दर्ज करें और रिपोर्ट लिख लें। केवल बहुत संकरे और बहुत चौड़े लेआउट जाँचने के बजाय, उस बिंदु के आसपास की चौड़ाइयों की तुलना करें जहाँ रैपिंग बदलती है।

बार-बार जाँच के लिए, Playwright स्पष्ट व्यूपोर्ट आयाम और अलग deviceScaleFactor सेटिंग का समर्थन करता है। इसका दस्तावेज़ डिवाइस प्रीसेट के व्यूपोर्ट को बदलने की भी अनुमति देता है। इससे स्वचालन का एक समर्थित तरीका मिलता है: व्यूपोर्ट सेट करें, पेज लोड करें, उसके फ़ॉन्ट और संबंधित कंटेंट के तैयार होने की प्रतीक्षा करें, फिर ब्राउज़र में DOM माप एकत्र करें। Emulation — Playwright

CSS आयामों और डिस्प्ले पिक्सेल घनत्व को अलग रखें। Playwright व्यूपोर्ट और स्केल फ़ैक्टर को अलग-अलग सेटिंग के रूप में दिखाता है, जबकि Canvas टेक्स्ट मेट्रिक्स CSS पिक्सेल में व्यक्त होते हैं। केवल अधिक घनत्व वाला डिस्प्ले होने से लेबल के लिए आवंटित CSS चौड़ाई दोगुनी करने की ज़रूरत नहीं पड़ती। Emulation — Playwright, TextMetrics — MDN

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

स्रोत