Aby określić rozmiar podglądu tekstu w przeglądarce, zmierz ułożony element DOM przy docelowej szerokości obszaru roboczego. Użyj Canvas do pomiaru parametrów tekstu w jednym wierszu. W tym poradniku pokazano, jak porównać oba pomiary na komputerze Mac i zrozumieć, dlaczego ich szerokości i wysokości się różnią.

Praktyczne zadanie polega na ustaleniu, ile miejsca potrzebuje etykieta syntetycznej karty przy zmianach rozmiaru obszaru roboczego przeglądarki. Przydatny wynik obejmuje łącznie obszar roboczy, dostępną szerokość tekstu, ustawienia czcionki i zmierzony blok. Szerokość bez tych warunków trudno odtworzyć.

Jaką szerokość i wysokość tekstu należy zmierzyć?

Interfejsy API przeglądarki odpowiadają na kilka różnych pytań dotyczących rozmiaru. Zanim cokolwiek obliczysz, wybierz pomiar odpowiadający decyzji, którą chcesz podjąć.

Pytanie Pomiar Co przedstawia
Jak daleko w poziomie rozciąga się pojedynczy, niezawijany ciąg znaków? Canvas measureText(text).width Szerokość wysunięcia tekstu
Jakie są granice kształtów glifów w Canvas? Właściwości Canvas actualBoundingBox… Granice glifów względem punktu wyrównania i linii bazowej
Ile miejsca w układzie zajmuje karta? Element getBoundingClientRect() Jego prostokąt obramowania, z dopełnieniem i obramowaniem
Gdzie znajdują się fragmenty tekstu po zawinięciu? Range getClientRects() Prostokąty odpowiadające zaznaczonemu tekstowi
Jaki prostokąt obejmuje te fragmenty tekstu? Range getBoundingClientRect() Ich łączny prostokąt ograniczający

Szerokość wysunięcia tekstu w Canvas może różnić się od szerokości glifów: kształty kursywy mogą wykraczać poza szerokość wysunięcia. Aby uzyskać granice glifów, oblicz szerokość jako actualBoundingBoxLeft + actualBoundingBoxRight, a wysokość jako actualBoundingBoxAscent + actualBoundingBoxDescent. Pomiary te są wyrażone w pikselach CSS. TextMetrics — MDN

Pomiar elementu obejmuje dopełnienie i obramowanie, a Range obejmujący wyłącznie tekst mierzy zaznaczony tekst przy użyciu parametrów czcionki. Żadnego z nich nie należy opisywać jako dokładnego prostokąta pomalowanych pikseli. Specyfikacja W3C definiuje poziome prostokąty tekstu Range na podstawie wysokości nad linią bazową, wysokości pod nią i szerokości wysunięcia tekstu. Element: metoda getBoundingClientRect() — MDN, Moduł CSSOM View — W3C

Do podglądu rozmiaru w przeglądarce użyj bloku elementu, aby przydzielić miejsce, a prostokątów Range, aby sprawdzić przepływ tekstu. Pomiary Canvas traktuj jako osobny punkt odniesienia dla niezawijanego ciągu znaków.

Najpierw ustaw obszar roboczy i warunki wyświetlania tekstu

W Chrome na komputerze Mac otwórz DevTools, włącz Toggle device toolbar i wybierz Responsive w sekcji Dimensions. Wprowadź docelową szerokość i wysokość w polach obszaru roboczego. Chrome dokumentuje zarówno wpisywanie wartości liczbowych, jak i zmianę rozmiaru obszaru roboczego przez przeciąganie. W przypadku podglądu na komputerze użyj typu urządzenia desktopowego, jeśli ta opcja jest dostępna. Symulowanie urządzeń mobilnych w trybie urządzenia — Chrome dla deweloperów

Rozróżnij szerokość obszaru roboczego od szerokości tekstu. Karta może mieć maksymalną szerokość, zewnętrzne odstępy, dopełnienie i obramowania. Zwiększanie szerokości przeglądarki przestanie powiększać obszar tekstu, gdy karta osiągnie maksymalną szerokość.

Załóżmy na przykład, że karta ma przykładową szerokość bloku obramowania 360px, poziome dopełnienie po 16px z każdej strony i dwa obramowania po 1px. Dostępna szerokość zawartości wynosi 360 − 32 − 2 = 326px. To szerokość dostępna na zawijanie tekstu. Prostokąt karty nadal ma szerokość 360px. Wynika to z udokumentowanego sposobu pomiaru bloku obramowania. Element: metoda getBoundingClientRect() — MDN

Ustaw zgodne z zamierzeniami: rodzinę i grubość czcionki, jej rozmiar, styl, wysokość wiersza, odstępy oraz reguły zawijania. W szczególności white-space: normal zwija białe znaki i pozwala na zawijanie, podczas gdy pre-wrap zachowuje białe znaki i znaki nowego wiersza ze źródła, nadal pozwalając na zawijanie. Podgląd używający jednego z tych ustawień nie odzwierciedli wiarygodnie drugiego. white-space — MDN

Rozróżnij również rozmiar czcionki od wysokości wiersza. W poziomym kierunku pisma wartość line-height wpływa na wysokość bloku wiersza; nie określa widocznej wysokości liter. Dlatego dla czcionki 16px z wysokością wiersza 24px trzeba inaczej obliczyć wysokość niż w przypadku granic glifów Canvas. line-height — MDN

Uruchom pełny podgląd syntetycznego tekstu

Otwórz pustą kartę, uruchom DevTools, wybierz Console i jednokrotnie wykonaj poniższy kompletny skrypt przeglądarkowy. Tworzy on neutralną kartę i raport pomiarów. Nie wymaga biblioteki, zewnętrznej czcionki, istniejącego selektora ani pliku HTML. Przed uruchomieniem kolejnej kopii odśwież pustą kartę.

Karta dopasowuje się do obszaru roboczego, dopóki nie osiągnie szerokości bloku obramowania 480px. Raport aktualizuje się po zmianie rozmiaru okna lub emulowanego obszaru roboczego. Ten przykład celowo ograniczono do zwykłego poziomego bloku tekstu o jednolitym stylu. Kod zależny od przeglądarki został sprawdzony, ale podczas przygotowania nie uruchomiono go w przeglądarce.

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

Wywołania elementu i Range używają rzeczywistego układu przeglądarki. Canvas mierzy ten sam syntetyczny ciąg znaków jako pojedynczy, niezawijany fragment. Standard HTML dotyczący przygotowania tekstu na Canvas zamienia białe znaki ASCII na spacje; przekazanie znaku nowego wiersza do measureText() nie tworzy akapitu CSS z wieloma wierszami. Standard HTML: element canvas — WHATWG

Skrypt czeka na document.fonts.ready po ustaleniu układu. MDN podaje, że ta obietnica jest spełniana po zakończeniu ładowania i operacji układu dotyczących używanych czcionek. Nie oznacza to, że załadowała się każda zadeklarowana czcionka ani że wyświetlana jest pierwotnie preferowana odmiana. Document: właściwość fonts — MDN

Odczytaj wyniki i ustal, czy tekst się mieści

Zacznij od Available text width, a następnie porównaj wysokość karty dla dwóch rozmiarów obszaru roboczego. Gdy zawijanie doda wiersz, zmieni się wysokość karty, podczas gdy niezawijane wysunięcie tekstu w Canvas może pozostać bez zmian. To połączenie pomaga odróżnić zmianę zawijania od zmiany czcionki.

Poniższe szerokości dla tego przykładu to obliczenia poglądowe, a nie zmierzone wyniki dla czcionki. Zakładają podaną szerokość obszaru układu i niezmienione style skryptu.

Szerokość obszaru układu Szerokość bloku obramowania karty Dostępna szerokość tekstu
360px 312px 278px
800px 480px 446px
1200px 480px 446px

Dwa ostatnie wiersze wyjaśniają, dlaczego poszerzenie przeglądarki może nie zmienić zawijania tekstu: karta osiągnęła już maksymalną szerokość. Sama zmiana obszaru roboczego nie zwiększy ilości miejsca na zawartość tej karty.

W prostym bloku zawierającym wyłącznie tekst o jednolitym stylu przykładowy układ z trzema wierszami i wysokością wiersza 24px zajmuje 72px przestrzeni bloku wiersza. Dodaj 32px dopełnienia w pionie i 2px obramowania, aby uzyskać przykładową wysokość karty 106px. Takie obliczenie pomaga zrozumieć wynik; gdy zawartość lub styl stają się bardziej złożone, rozstrzygający pozostaje zmierzony wymiar DOM. line-height — MDN

Nie traktuj automatycznie Range fragment count jako uniwersalnej liczby wierszy. Interfejs Range API zwraca prostokąty tekstu i elementów zgodnie z regułami zaznaczania. Tekst sformatowany, zagnieżdżone elementy i fragmentacja układu mogą prowadzić do bardziej złożonego zestawu prostokątów. Przykład zaznacza tylko pojedynczy zwykły węzeł tekstowy, aby ułatwić zrozumienie diagnostyki. Moduł CSSOM View — W3C

Unikaj też szacowania wysokości zawiniętego tekstu za pomocą ceil(unwrappedWidth / availableWidth). Ten wzór zakłada, że tekst może być dzielony w dowolnych miejscach w poziomie. Zawijanie w przeglądarce musi uwzględniać skonfigurowane zasady białych znaków i dzielenia, dlatego zamiast tego zmierz zawinięty blok. white-space — MDN

Co sprawdzić, gdy pomiary się różnią?

Najpierw sprawdź granice pomiaru. Prostokąt karty na pełną szerokość i węższy prostokąt Range mogą być jednocześnie poprawne. Karta rezerwuje miejsce w układzie, a Range opisuje zaznaczony tekst. Wysokość glifów Canvas stanowi trzecią wartość o innym zastosowaniu.

Następnie sprawdź, czy czcionki są gotowe. Jeśli dodasz zadeklarowaną czcionkę internetową, document.fonts.load(fontSpecification, sampleText) może jawnie zażądać pasujących odmian czcionki przed pomiarem. Obsłuż odrzucenie, zamiast po cichu podstawiać pomyślny wynik. Opcjonalny argument tekstowy filtruje według zakresów Unicode; nie weryfikuje obsługi poszczególnych glifów. FontFaceSet: metoda load() — MDN

Zachowaj granice kształtowania tekstu podczas obliczania szerokości etykiety. Mierz cały ciąg znaków zamiast dodawać szerokości zmierzone niezależnie dla poszczególnych znaków. Specyfikacja Canvas opisuje przygotowanie pozycjonowanego ciągu glifów z użyciem bieżącej czcionki i ustawień tekstu; wynik jest właściwą jednostką dla tego ciągu. Porównanie z Canvas w tym przykładzie ogranicz do podanych ustawień czcionki, zamiast zakładać, że odwzorowuje wszystkie funkcje typograficzne CSS. Standard HTML: element canvas — WHATWG

W przypadku istniejącej strony zmierz jej rzeczywisty komponent na miejscu. Przeniesienie tekstu do ogólnego, ukrytego bloku zmienia warunki układu, chyba że odtworzysz również istotne style i otaczający kontekst. Elementy bez powiązanych bloków układu nie dostarczają użytecznych pomiarów zwykłych bloków, a transformacje CSS wpływają na prostokąty zwracane przez te interfejsy API. Przykład syntetyczny omija oba te problemy. Moduł CSSOM View — W3C

Jak powtórzyć podgląd dla kilku rozmiarów przeglądarki?

Przy sporadycznych kontrolach ręcznie wpisz każdy rozmiar obszaru roboczego i zapisz raport. Porównuj szerokości w pobliżu punktu, w którym zmienia się zawijanie, zamiast sprawdzać tylko bardzo wąski i bardzo szeroki układ.

Do powtarzanych kontroli Playwright obsługuje jawne wymiary obszaru roboczego oraz osobne ustawienie deviceScaleFactor. Dokumentacja pozwala też zastąpić obszar roboczy ustawiony w predefiniowanym profilu urządzenia. To obsługiwana ścieżka automatyzacji: ustaw obszar roboczy, załaduj stronę, poczekaj na czcionki i istotną zawartość, a następnie pobierz pomiary DOM w przeglądarce. Emulacja — Playwright

Traktuj wymiary CSS oddzielnie od gęstości pikseli ekranu. Playwright udostępnia obszar roboczy i współczynnik skali jako osobne ustawienia, a parametry tekstu Canvas są wyrażone w pikselach CSS. Ekran o większej gęstości sam w sobie nie wymaga podwojenia szerokości CSS przydzielonej etykiecie. Emulacja — Playwright, TextMetrics — MDN

Przydatny wynik podglądu to zatem krótki zapis warunków: przeglądarki, obszaru roboczego, tekstu, typografii, szerokości zawartości i zmierzonej wysokości karty. Użyj wyniku DOM, aby określić rozmiar zawijanego komponentu, zachowaj parametry Canvas do pytań dotyczących pojedynczego ciągu, a pomiar powtórz w każdej przeglądarce, którą chcesz odwzorować.

Źródła