W poziomym wierszu obrazów śródliniowych wyrównanych do linii bazowej linia bazowa przebiega przy dolnej krawędzi marginesu każdego obrazu. Ten poradnik pokazuje, jak znaleźć tę współrzędną w Chrome na Macu, sprawdzić ją za pomocą małego znacznika i rozpoznać sytuacje, w których ta metoda nie ma zastosowania.

Dlaczego wiersz zawierający wyłącznie obrazy ma linię bazową?

Wiersz zawierający wyłącznie obrazy nadal uczestniczy w układzie śródliniowym CSS. Pomyślnie wyświetlony element img jest elementem zastępowanym: przeglądarka układa jego pole zgodnie z CSS, zamiast traktować obraz jako tekst. WHATWG opisuje to zachowanie związane z renderowaniem w regułach renderowania obrazów w standardzie HTML.

W zwykłym poziomym układzie śródliniowym obraz bez wewnętrznej linii bazowej tekstu używa dolnej krawędzi marginesu do wyrównania względem linii bazowej. W rezultacie dwa obrazy o różnej wysokości, wyrównane do linii bazowej, mogą mieć wspólną linię bazową, mimo że ich górne krawędzie znajdują się na różnych wysokościach. Reguła dotyczy ich pól; nie analizuje znajdującej się w nich grafiki. Zobacz CSS 2, wyrównanie pionowe.

Znaczenie mają trzy różne granice:

Granica Znaczenie Czy nadaje się jako odniesienie do linii bazowej?
Krawędź widocznej grafiki Miejsce, w którym kończą się widoczne piksele obrazu Nie; plik może zawierać przezroczysty obszar
Dolna krawędź obramowania obrazu Dolna krawędź zwracana przez getBoundingClientRect() Tak, po uwzględnieniu dolnego marginesu i potwierdzeniu wyrównania do linii bazowej
Dolna krawędź pola wiersza Dolna granica całego wiersza CSS Nie; może sięgać poniżej linii bazowej

Krój pisma rodzica i jego line-height nadal mają znaczenie, nawet jeśli nie widać żadnych liter. CSS opisuje niewidoczny wkład oparty na kroju pisma, nazywany rozpórką (strut), który pomaga wyznaczyć minimalną wysokość i głębokość wiersza. To wyjaśnia, dlaczego obraz może spoczywać na linii bazowej, a pod nim nadal pozostaje miejsce w wierszu. Specyfikacja CSS Inline Layout opisuje te metryki kroju pisma i granice układu; pobrana, opublikowana wersja jest szkicem roboczym, dlatego nie należy zakładać, że jej nowsze funkcje są obsługiwane we wszystkich przeglądarkach.

Jak znaleźć linię bazową na istniejącej stronie?

Otwórz stronę, którą możesz sprawdzić w Chrome na Macu. Kliknij obraz prawym przyciskiem myszy i wybierz Zbadaj. Chrome otworzy panel Elements z zaznaczonym elementem; panel Styles pokaże zastosowane do niego reguły CSS. Google opisuje ten sposób pracy w Otwieraniu Chrome DevTools.

Przed obliczeniem współrzędnej sprawdź następujące warunki:

  1. Obraz uczestniczy w zwykłym przepływie śródliniowym w docelowym wierszu.
  2. Jego efektywne wyrównanie to vertical-align: baseline.
  3. Tryb pisania jest poziomy.
  4. Obraz ani żaden z jego elementów nadrzędnych nie ma transformacji ani wizualnego przesunięcia wpływającego na pomiar.
  5. Mierzysz sam obraz, a nie otaczający go kontener z własnym zachowaniem względem linii bazowej.

Te warunki określają zakres obliczenia. Na przykład vertical-align: bottom wyrównuje element do dołu wiersza, a middle wykorzystuje linię bazową rodzica przesuniętą o połowę jego wysokości x. Żadna z tych wartości nie oznacza, że dolna krawędź obrazu wskazuje linię bazową rodzica. MDN wyjaśnia te różnice w opisie właściwości vertical-align.

Gdy te warunki są spełnione, zastosuj poniższą zależność, wyrażając wszystkie odległości w pikselach CSS:

baselineY = imageBorderBoxBottom + imageMarginBottom

getBoundingClientRect() podaje dolną krawędź obramowania względem okna widoku. Zwrócony prostokąt obejmuje dopełnienie i obramowanie, więc nie należy dodawać ich ponownie. Marginesy znajdują się poza tym prostokątem. MDN opisuje zwracaną geometrię i układ współrzędnych w Element.getBoundingClientRect().

Dla przykładowego obliczenia załóżmy, że dolna krawędź obramowania obrazu znajduje się na 240.5, a jego dolny margines wynosi 6. Linia bazowa znajduje się zatem 246.5 pikseli CSS poniżej górnej krawędzi okna widoku. Jeśli górna krawędź obramowania kontenera znajduje się na 200, linia bazowa wypada 46.5 pikseli CSS poniżej górnej krawędzi obramowania kontenera. Jest to odległość od krawędzi obramowania, a niekoniecznie od krawędzi obszaru zawartości.

Dla porównania zmierz inny obraz z tego samego wiersza, który spełnia te warunki. Jego krawędź marginesu powinna wskazywać tę samą linię bazową, nawet jeśli obraz ma inną wysokość. Rozbieżność oznacza, że przed zmianą CSS warto sprawdzić wyrównanie, kontenery, pozycjonowanie lub zawijanie wierszy. Podczas porównania zachowuj wartości ułamkowe.

Jak sprawdzić wynik za pomocą znacznika linii bazowej?

Przydatnym narzędziem diagnostycznym jest pusty element śródliniowo-blokowy o zerowej szerokości, wysokości, marginesach, dopełnieniu i obramowaniu, wyrównany do linii bazowej. Ponieważ nie zawiera wierszy w przepływie, jego linia bazowa pokrywa się z dolną krawędzią marginesu. Gdy wszystkie te wymiary wynoszą zero, ta krawędź pokrywa się z jego zmierzoną pozycją pionową. Wynika to z reguły linii bazowej elementu śródliniowo-blokowego w CSS 2.

Poniższy kompletny program konsolowy tworzy tymczasowy przykład z dwoma neutralnymi, prostokątnymi obrazami i znacznikiem. Korzysta z korzenia shadow DOM, aby oddzielić wewnętrzne style przykładu od zwykłych selektorów strony. Uruchom go w dokumencie w trybie standardów, bez transformacji na dokumencie ani elemencie body. Mierzy wyłącznie własny, syntetyczny wiersz, a nie zawartość istniejącej strony.

Otwórz Console skrótem Command + Option + J, opisanym w skrócie klawiszowym DevTools Chrome, i uruchom program. Nie trzeba instalować bibliotek ani korzystać z zewnętrznego pliku obrazu. Przykład tworzy prostokąty za pomocą standardowego 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;
  }
})();

Program czeka, aż oba obrazy zostaną zdekodowane, i dopiero wtedy wykonuje pomiar. Opisana metoda HTMLImageElement.decode() zwraca obietnicę i może ją odrzucić, jeśli dekodowanie się nie powiedzie; w takim przypadku program usuwa tymczasowy panel i zgłasza błąd.

Oba obrazy mają zerowy dolny margines, więc podane dla nich wartości imageBottom powinny być zgodne z markerBaseline. Cienka pozioma linia wskazuje tę współrzędną. Tło wiersza pozwala też odróżnić linię bazową od ewentualnej pozostałej przestrzeni poniżej. Po zakończeniu wybierz Remove demonstration.

W kontrolowanym eksperymencie zmień dolny margines obrazów w przykładzie z 0 na 6px w stylu obrazu. Ich dolne krawędzie obramowania powinny wtedy znajdować się sześć pikseli CSS powyżej linii bazowej znacznika. Zastosuj wcześniejszy wzór, aby wyznaczyć wspólną współrzędną. W ten sposób otrzymujesz w przykładzie dwa niezależne punkty odniesienia: krawędź marginesu obrazu i pusty znacznik.

Kiedy ta metoda wymaga innego podejścia?

Wstawienie znacznika jest działaniem diagnostycznym, więc mierzy powstały układ. Dodanie go do dowolnego istniejącego akapitu może utworzyć możliwość złamania wiersza lub w inny sposób wpłynąć na układ. Jeśli spełnione są warunki wstępne, lepiej obliczyć pozycję na podstawie istniejącego obrazu. Jeśli wstawiasz znacznik do rzeczywistej treści, sprawdź, czy te same obrazy nadal znajdują się w tym samym wierszu i czy ich pozycje się nie zmieniły.

Sytuacja Zalecany następny krok
Obrazy używają wyrównania top, bottom lub middle Sprawdź tę regułę wyrównania; nie stosuj bez zmian wzoru dla obrazów wyrównanych do linii bazowej
Obraz znajduje się wewnątrz kontenera śródliniowo-blokowego Sprawdź linię bazową kontenera, która może wynikać z ostatniego wiersza jego zawartości
Obrazy zajmują kilka zawiniętych wierszy Wyznacz osobną linię bazową dla każdego wiersza
Rodzic używa układu flex lub grid Przed potraktowaniem wiersza jako układu śródliniowego sprawdź reguły wyrównywania właściwe dla tego układu
Dokument używa pionowego trybu pisania Zastosuj reguły uwzględniające tryb pisania zamiast współrzędnej y dolnej krawędzi
Obraz nie załadował się poprawnie Ustal stan renderowania, zanim potraktujesz go jako wyświetlone pole obrazu

Ostatni warunek ma znaczenie, ponieważ WHATWG opisuje różne ścieżki renderowania dla wyświetlanych obrazów, obrazów oczekujących i tekstu alternatywnego. Uszkodzony obraz wyświetlający swoją etykietę może więc wymagać innej interpretacji niż poprawnie wyrenderowany obraz, którego położenie chcesz zmierzyć. Zobacz reguły renderowania obrazów w HTML.

Nie zakładaj istnienia jednej wspólnej linii bazowej tylko dlatego, że kilka prostokątów obrazów ma podobne współrzędne górnej krawędzi. Obrazy o różnej wysokości mogą mieć wspólną linię bazową i różne górne krawędzie. Z kolei wyrównane górne krawędzie nie potwierdzają wyrównania do linii bazowej. Sprawdź, które pola uczestniczą w tym samym wierszu i jaka reguła wyrównania ma zastosowanie.

Czy interfejsy do pomiaru tekstu lub biblioteki kształtowania tekstu mogą podać odpowiedź?

Używane tutaj metody geometrii przeglądarki zwracają prostokąty, a nie osobne pole z linią bazową wiersza. Range.getClientRects() może pomóc sprawdzić obszary zajmowane przez zakres, ale zwracane prostokąty nie podają bezpośrednio współrzędnej linii bazowej. MDN opisuje ten interfejs w Range.getClientRects().

Metryki tekstu Canvas odpowiadają na inne pytanie: określają, jak fragment tekstu na canvasie jest powiązany z wybraną linią bazową tekstu w kontekście canvasu. Na przykład actualBoundingBoxAscent i actualBoundingBoxDescent opisują granice tuszu tekstu względem tego punktu odniesienia. Nie lokalizują bezpośrednio istniejącego wiersza obrazów w DOM. Zobacz dokumentację TextMetrics w MDN.

Biblioteka do kształtowania tekstu ma węższy zakres odpowiedzialności niż układanie wierszy przez przeglądarkę. Podręcznik HarfBuzz stwierdza, że biblioteka kształtuje ciągi tekstu i dostarcza informacji o układzie glifów, natomiast łamanie wierszy akapitu i justowanie pozostają poza jej zakresem. Instalacja HarfBuzz nie zapewni więc pomiaru wiersza obrazów w przeglądarce. Opisany zakres działania pozwala ustalić tę granicę.

W poziomym wierszu zawierającym wyłącznie obrazy najpierw potwierdź zwykły przepływ śródliniowy i wyrównanie do linii bazowej. Następnie odczytaj dolną krawędź obramowania obrazu spełniającego te warunki i dodaj jego dolny margines. Jeśli potrzebujesz widocznego porównania, użyj znacznika o zerowych wymiarach w kontrolowanym układzie. Gdy te dwa punkty odniesienia się różnią, ponownie sprawdź kontekst formatowania.

Źródła