Untuk menentukan ukuran pratinjau teks di browser, ukur elemen DOM yang sudah ditata pada lebar viewport yang diinginkan. Gunakan Canvas untuk metrik teks satu baris. Panduan ini menunjukkan cara membandingkan keduanya di Mac dan memahami alasan lebar serta tingginya berbeda.

Tugas praktisnya adalah mencari tahu berapa banyak ruang yang dibutuhkan label kartu sintetis saat viewport browser berubah. Hasil yang berguna mencatat viewport, lebar teks yang tersedia, pengaturan font, dan kotak yang diukur secara bersamaan. Lebar tanpa kondisi tersebut sulit direproduksi.

Lebar dan tinggi teks mana yang harus Anda ukur?

API browser menjawab beberapa pertanyaan pengukuran yang berbeda. Pilih pengukuran yang sesuai dengan keputusan yang perlu Anda ambil sebelum mulai menghitung.

Pertanyaan Anda Pengukuran Maknanya
Seberapa jauh satu string tanpa pembungkusan bergerak secara horizontal? Canvas measureText(text).width Lebar pergerakan teks
Berapa batas bentuk glif Canvas? Properti Canvas actualBoundingBox… Batas glif relatif terhadap titik perataan dan garis dasar
Berapa banyak ruang tata letak yang ditempati kartu? Elemen getBoundingClientRect() Kotak batasnya, termasuk padding dan border
Di mana fragmen teks berada setelah dibungkus? Range getClientRects() Persegi panjang yang terkait dengan teks yang dipilih
Persegi panjang apa yang mencakup fragmen teks tersebut? Range getBoundingClientRect() Persegi panjang gabungannya

Lebar pergerakan Canvas dan lebar glif bisa berbeda: bentuk miring dapat melampaui lebar pergerakannya. Untuk batas glif, hitung lebar sebagai actualBoundingBoxLeft + actualBoundingBoxRight dan tinggi sebagai actualBoundingBoxAscent + actualBoundingBoxDescent. Pengukuran ini menggunakan piksel CSS. TextMetrics — MDN

Pengukuran elemen mencakup padding dan border, sedangkan Range khusus teks mengukur teks yang dipilih menggunakan metrik font. Keduanya tidak boleh disebut sebagai persegi panjang piksel yang benar-benar diwarnai secara persis. Spesifikasi W3C menetapkan persegi panjang teks horizontal Range menggunakan ascender, descender, dan pergerakan teks. Element: metode getBoundingClientRect() — MDN, Modul CSSOM View — W3C

Untuk pratinjau ukuran browser, gunakan kotak elemen untuk mengalokasikan ruang dan persegi panjang Range untuk memeriksa alur teks. Jadikan pengukuran Canvas sebagai referensi terpisah untuk string tanpa pembungkusan.

Tetapkan viewport dan kondisi teks terlebih dahulu

Di Chrome pada Mac Anda, buka DevTools, aktifkan Toggle device toolbar, lalu pilih Responsive di bagian Dimensions. Masukkan lebar dan tinggi yang diinginkan pada kolom viewport. Dokumentasi Chrome menjelaskan cara memasukkan angka maupun mengubah ukuran viewport dengan menyeretnya. Untuk pratinjau desktop, gunakan jenis perangkat desktop jika kontrol tersebut tersedia. Simulasikan perangkat seluler dengan mode perangkat — Chrome for Developers

Bedakan lebar viewport dari lebar teks. Kartu dapat memiliki lebar maksimum, jarak luar, padding, dan border. Penambahan lebar browser tidak akan lagi memperbesar area teks setelah kartu mencapai lebar maksimumnya.

Sebagai contoh, anggap lebar border-box kartu adalah 360px untuk ilustrasi, padding horizontalnya 16px di setiap sisi, dan bordernya 1px di kedua sisi. Lebar konten yang tersedia adalah 360 − 32 − 2 = 326px. Itulah lebar yang tersedia untuk pembungkusan. Persegi panjang batas elemen tetap melaporkan 360px. Hal ini mengikuti perilaku pengukuran border-box yang didokumentasikan. Element: metode getBoundingClientRect() — MDN

Sesuaikan keluarga font, ketebalan, ukuran, gaya, tinggi baris, spasi, dan aturan pembungkusan dengan yang diinginkan. Secara khusus, white-space: normal merapatkan spasi dan memungkinkan pembungkusan, sedangkan pre-wrap mempertahankan spasi dan baris baru sumber sambil tetap memungkinkan pembungkusan. Pratinjau yang menggunakan salah satunya tidak dapat merepresentasikan yang lain secara andal. white-space — MDN

Bedakan juga ukuran font dari tinggi baris. Dalam penulisan horizontal, line-height ikut menentukan tinggi kotak baris; properti ini tidak menggambarkan tinggi huruf yang terlihat. Karena itu, font 16px dengan tinggi baris 24px memerlukan perhitungan tinggi yang berbeda dari batas glif Canvas-nya. line-height — MDN

Jalankan pratinjau teks sintetis secara lengkap

Buka tab kosong, buka DevTools, pilih Console, lalu jalankan skrip browser lengkap berikut satu kali. Skrip ini membuat kartu netral dan laporan pengukuran. Anda tidak memerlukan pustaka, font eksternal, selector yang sudah ada, atau file HTML. Muat ulang tab kosong sebelum menjalankan salinan lain.

Kartu mengikuti viewport hingga mencapai lebar border-box 480px. Laporan diperbarui saat jendela atau viewport yang diemulasikan berubah ukuran. Contoh ini sengaja dibatasi pada blok teks horizontal biasa dengan gaya seragam. Kode yang bergantung pada browser telah diperiksa; kode tersebut tidak dijalankan di browser selama persiapan.

(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));

Pemanggilan elemen dan Range menggunakan tata letak aktual browser. Canvas mengukur string sintetis yang sama sebagai satu rangkaian tanpa pembungkusan. HTML Standard mengganti spasi ASCII dengan spasi saat menyiapkan teks Canvas; meneruskan baris baru ke measureText() tidak membuat paragraf CSS yang terdiri dari beberapa baris. HTML Standard: Elemen canvas — WHATWG

Skrip menunggu document.fonts.ready setelah tata letak ditetapkan. MDN menyatakan bahwa promise ini terpenuhi setelah operasi pemuatan dan tata letak untuk font yang digunakan selesai. Ini tidak berarti semua font yang dideklarasikan telah dimuat atau bahwa font pilihan awal pasti yang ditampilkan. Document: properti fonts — MDN

Baca hasilnya dan tentukan apakah teks muat

Mulailah dengan Available text width, lalu bandingkan tinggi kartu pada dua ukuran viewport. Saat pembungkusan menambahkan satu baris, tinggi kartu berubah, sedangkan lebar pergerakan Canvas tanpa pembungkusan dapat tetap sama. Kombinasi ini membantu membedakan perubahan pembungkusan dari perubahan font.

Untuk contoh ini, lebar berikut adalah perhitungan ilustratif, bukan hasil pengukuran font. Perhitungan ini mengasumsikan viewport tata letak memiliki lebar yang disebutkan dan gaya skrip tidak berubah.

Lebar viewport tata letak Lebar border-box kartu Lebar teks yang tersedia
360px 312px 278px
800px 480px 446px
1200px 480px 446px

Dua baris terakhir menjelaskan mengapa memperlebar browser bisa membuat pembungkusan teks tetap sama: kartu sudah mencapai lebar maksimumnya. Mengubah viewport saja tidak dapat menambah ruang konten untuk kartu tersebut.

Untuk blok sederhana yang hanya berisi teks seragam, tata letak ilustratif tiga baris dengan tinggi baris 24px menempati ruang kotak baris sebesar 72px. Tambahkan padding vertikal 32px dan border 2px untuk mendapatkan tinggi kartu ilustratif 106px. Perhitungan ini berguna untuk memahami hasilnya; tinggi DOM yang diukur tetap menjadi nilai penentu saat konten atau gayanya lebih kompleks. line-height — MDN

Jangan langsung menganggap Range fragment count sebagai jumlah baris universal. API Range mengembalikan persegi panjang teks dan elemen berdasarkan aturan pemilihannya. Teks berformat kaya, elemen bertingkat, dan tata letak yang terfragmentasi dapat menghasilkan sekumpulan persegi panjang yang lebih rumit. Contoh ini hanya memilih satu simpul teks biasa agar diagnostiknya mudah dipahami. Modul CSSOM View — W3C

Hindari juga memperkirakan tinggi teks yang dibungkus dengan ceil(unwrappedWidth / availableWidth). Rumus tersebut mengasumsikan bahwa teks dapat dipatahkan pada posisi horizontal mana pun. Pembungkusan browser harus mengikuti perilaku spasi dan pemenggalan yang dikonfigurasi, jadi ukurlah blok yang sudah dibungkus. white-space — MDN

Apa yang perlu diperiksa saat hasil pengukuran tidak cocok?

Periksa batas pengukuran terlebih dahulu. Persegi panjang kartu selebar penuh dan persegi panjang Range yang lebih sempit bisa sama-sama benar. Kartu menyediakan ruang tata letak; Range menggambarkan teks yang dipilih. Tinggi glif Canvas memberikan nilai ketiga dengan tujuan berbeda.

Selanjutnya, periksa kesiapan font. Jika Anda menggunakan font web yang dideklarasikan, document.fonts.load(fontSpecification, sampleText) dapat secara eksplisit meminta font yang cocok sebelum pengukuran. Tangani kegagalan alih-alih diam-diam menggantinya dengan hasil yang berhasil. Argumen teks opsional menyaring berdasarkan rentang Unicode; argumen ini tidak memverifikasi cakupan glif individual. FontFaceSet: metode load() — MDN

Pertahankan batas pembentukan teks saat menghitung lebar label. Ukur seluruh string, jangan menjumlahkan lebar karakter yang diukur secara terpisah. Spesifikasi Canvas menyiapkan rangkaian glif berposisi menggunakan font dan pengaturan teks saat ini; hasilnya merupakan satuan yang tepat untuk string tersebut. Batasi perbandingan Canvas dalam contoh ini pada pengaturan font yang disebutkan, alih-alih menganggapnya mereproduksi setiap fitur tipografi CSS. HTML Standard: Elemen canvas — WHATWG

Untuk halaman yang sudah ada, ukur komponen sebenarnya di tempatnya. Memindahkan teks ke kotak tersembunyi generik akan mengubah kondisi tata letak kecuali Anda juga meniru gaya dan konteks penampung yang relevan. Elemen tanpa kotak tata letak terkait tidak dapat memberikan pengukuran kotak normal yang berguna, dan transformasi CSS memengaruhi persegi panjang yang dilaporkan oleh API ini. Contoh sintetis menghindari kedua kerumitan tersebut. Modul CSSOM View — W3C

Bagaimana cara mengulangi pratinjau pada beberapa ukuran browser?

Untuk pemeriksaan sesekali, masukkan setiap ukuran viewport secara manual dan catat laporannya. Bandingkan lebar di sekitar titik perubahan pembungkusan, alih-alih hanya memeriksa tata letak yang sangat sempit dan sangat lebar.

Untuk pemeriksaan berulang, Playwright mendukung dimensi viewport yang eksplisit dan pengaturan deviceScaleFactor secara terpisah. Dokumentasinya juga memungkinkan penggantian viewport preset perangkat. Ini menyediakan jalur otomatisasi yang didukung: tetapkan viewport, muat halaman, tunggu font dan konten terkait, lalu kumpulkan pengukuran DOM di browser. Emulasi — Playwright

Pisahkan dimensi CSS dari kepadatan piksel layar. Playwright menyediakan viewport dan faktor skala sebagai pengaturan yang berbeda, sedangkan metrik teks Canvas dinyatakan dalam piksel CSS. Layar dengan kepadatan lebih tinggi tidak dengan sendirinya mengharuskan penggandaan lebar CSS yang dialokasikan untuk label. Emulasi — Playwright, TextMetrics — MDN

Karena itu, hasil pratinjau yang berguna adalah catatan singkat berisi kondisi: browser, viewport, teks, tipografi, lebar konten, dan tinggi kartu yang diukur. Gunakan hasil DOM untuk menentukan ukuran komponen yang dibungkus, pertahankan metrik Canvas untuk pertanyaan tentang satu rangkaian teks, dan ulangi pengukuran di setiap browser yang perlu Anda representasikan.

Sumber