Bei einer horizontalen Zeile mit an der Grundlinie ausgerichteten Inline-Bildern liegt die Grundlinie an der unteren Außenkante des unteren Rands jedes Bildes. Diese Anleitung zeigt, wie Sie diese Koordinate in Chrome auf einem Mac ermitteln, mit einer kleinen Markierung überprüfen und erkennen, wann diese Methode nicht anwendbar ist.

Warum hat eine Zeile, die nur Bilder enthält, eine Grundlinie?

Auch eine Zeile, die nur aus Bildern besteht, nimmt am CSS-Inline-Layout teil. Ein erfolgreich angezeigtes img ist ein ersetztes Element: Der Browser richtet dessen Box nach CSS aus, anstatt das Bild als Text zu behandeln. WHATWG dokumentiert dieses Darstellungsverhalten in den Regeln zur Bilddarstellung im HTML-Standard.

Im gewöhnlichen horizontalen Inline-Layout wird für ein Bild ohne intrinsische Textgrundlinie die untere Außenkante seines unteren Rands zur Grundlinienausrichtung verwendet. Deshalb können sich zwei an der Grundlinie ausgerichtete Bilder unterschiedlicher Höhe dieselbe Grundlinie teilen, während ihre oberen Kanten auf unterschiedlichen Höhen liegen. Die Regel bezieht sich auf ihre Boxen; das Bildmotiv selbst wird dabei nicht untersucht. Siehe CSS 2, vertikale Ausrichtung.

Drei verschiedene Begrenzungen sind relevant:

Begrenzung Bedeutung Als Referenz für die Grundlinie geeignet?
Sichtbare Bildkante Wo die sichtbaren Pixel des Bildes enden Nein; die Datei kann transparente Bereiche enthalten
Unterkante der Bild-Rahmenbox Die von getBoundingClientRect() zurückgegebene Unterkante Ja, wenn der untere Rand berücksichtigt und die Grundlinienausrichtung bestätigt wird
Unterkante der Zeilenbox Die untere Begrenzung der gesamten CSS-Zeile Nein; sie kann unterhalb der Grundlinie liegen

Die Schriftart des übergeordneten Elements und line-height spielen weiterhin eine Rolle, auch wenn keine Buchstaben sichtbar sind. CSS beschreibt einen unsichtbaren Beitrag auf Basis der Schriftart, den sogenannten Strut, der die Mindesthöhe und -tiefe der Zeile mitbestimmt. Das erklärt, warum ein Bild auf der Grundlinie sitzen kann, während unterhalb davon weiterhin Platz in der Zeile bleibt. Die CSS-Spezifikation für Inline-Layout beschreibt diese Schriftmetriken und Layoutgrenzen. Bei der abgerufenen veröffentlichten Fassung handelt es sich um einen Working Draft; daher sollte nicht davon ausgegangen werden, dass neuere Funktionen von allen Browsern unterstützt werden.

Wie finden Sie die Grundlinie auf einer vorhandenen Seite?

Öffnen Sie eine Seite, die Sie in Chrome auf Ihrem Mac untersuchen können. Klicken Sie mit der rechten Maustaste auf ein Bild und wählen Sie Inspect. Chrome öffnet den Bereich Elements und markiert das Element; im Bereich Styles sehen Sie das angewendete CSS. Google beschreibt diesen Ablauf unter Chrome DevTools öffnen.

Prüfen Sie vor dem Berechnen einer Koordinate die folgenden Bedingungen:

  1. Das Bild nimmt auf der betreffenden Zeile am normalen Inline-Fluss teil.
  2. Seine effektive Ausrichtung ist vertical-align: baseline.
  3. Die Schreibrichtung ist horizontal.
  4. Weder das Bild noch seine übergeordneten Elemente weisen eine Transformation oder visuelle Positionsverschiebung auf, die die Messung beeinflusst.
  5. Sie messen das Bild selbst und keinen umgebenden Wrapper mit eigenem Grundlinienverhalten.

Diese Bedingungen legen den Anwendungsbereich der Berechnung fest. Beispielsweise richtet vertical-align: bottom ein Element an der Unterkante der Zeile aus, während middle die Grundlinie des übergeordneten Elements plus die halbe x-Höhe verwendet. Keiner der beiden Werte bedeutet, dass die Unterkante des Bildes die Grundlinie des übergeordneten Elements angibt. MDN erläutert diese Unterschiede in der Referenz zu vertical-align.

Wenn diese Bedingungen erfüllt sind, verwenden Sie folgende Beziehung. Alle Abstände sind in CSS-Pixeln angegeben:

baselineY = imageBorderBoxBottom + imageMarginBottom

getBoundingClientRect() liefert die Unterkante der Rahmenbox relativ zum Viewport. Das Rechteck umfasst Innenabstände und Rahmen, die daher nicht ein zweites Mal addiert werden dürfen. Außenabstände liegen außerhalb dieses Rechtecks. MDN dokumentiert die zurückgegebene Geometrie und das Koordinatensystem unter Element.getBoundingClientRect().

Nehmen wir zur Veranschaulichung an, die Unterkante der Bild-Rahmenbox liege bei 240.5 und der untere Außenabstand betrage 6. Die Grundlinie liegt somit 246.5 CSS-Pixel unterhalb der Oberkante des Viewports. Liegt die Oberkante der Rahmenbox des Containers bei 200, befindet sich diese Grundlinie 46.5 CSS-Pixel unterhalb der oberen Rahmenkante des Containers. Dies ist ein Abstand von der Rahmenkante und nicht automatisch von der Inhaltskante.

Messen Sie als Gegenprobe ein weiteres geeignetes Bild auf derselben Zeile. Seine untere Außenkante sollte dieselbe Grundlinie angeben, selbst wenn seine Höhe abweicht. Bei einer Abweichung sollten Sie Ausrichtung, Wrapper, Positionierung oder Zeilenumbrüche prüfen, bevor Sie das CSS ändern. Behalten Sie beim Vergleich Nachkommastellen bei.

Wie können Sie das Ergebnis mit einer Grundlinienmarkierung überprüfen?

Ein nützliches Diagnoseelement ist ein leeres Inline-Block-Element mit einer Breite, Höhe, Außenabständen, Innenabständen und Rahmen von null, das an der Grundlinie ausgerichtet ist. Da es keine Inline-Zeilenboxen im normalen Fluss enthält, liegt seine Grundlinie an der unteren Außenkante seines unteren Rands. Da all diese Maße null sind, stimmt diese Kante mit seiner gemessenen vertikalen Position überein. Das folgt aus der CSS-2-Regel zur Grundlinie von Inline-Block-Elementen.

Das folgende vollständige Konsolenprogramm erstellt eine temporäre Demonstration mit zwei neutralen rechteckigen Bildern und einer Markierung. Es verwendet einen Shadow Root, damit die internen Stile des Beispiels von den üblichen Seiten-Selektoren getrennt bleiben. Führen Sie es in einem Dokument im Standards-Modus aus, dessen Dokument oder Body keine Transformationen aufweist. Es misst nur die eigens dafür erstellte Zeile, nicht den Inhalt einer vorhandenen Seite.

Öffnen Sie die Console mit Command + Option + J, wie in den DevTools-Tastenkombinationen von Chrome dokumentiert, und führen Sie das Programm aus. Eine Bibliotheksinstallation oder externe Bilddatei ist nicht erforderlich. Das Beispiel erzeugt seine Rechtecke mit der standardmäßigen 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;
  }
})();

Das Programm wartet vor der Messung, bis beide Bilder dekodiert sind. Die dokumentierte Methode HTMLImageElement.decode() gibt ein Promise zurück und kann abgewiesen werden, wenn die Dekodierung fehlschlägt. In diesem Fall entfernt das Programm das temporäre Panel und meldet den Fehler.

Beide Bilder haben einen unteren Außenabstand von null. Ihre angezeigten Werte für imageBottom sollten daher mit markerBaseline übereinstimmen. Die dünne horizontale Linie markiert diese Koordinate. Der Hintergrund der Zeile lässt Sie außerdem den Unterschied zur verbleibenden Fläche darunter erkennen. Wählen Sie anschließend Remove demonstration.

Ändern Sie für ein kontrolliertes Experiment den unteren Außenabstand der Beispielbilder im Bildstil von 0 auf 6px. Ihre Rahmenboxen sollten dann sechs CSS-Pixel oberhalb der Grundlinienmarkierung enden. Wenden Sie die vorherige Formel an, um die gemeinsame Koordinate zu ermitteln. Im Beispiel haben Sie damit zwei unabhängige Referenzen: die Außenkante des Bildes und die leere Markierung.

Wann ist für diese Methode ein anderer Ansatz nötig?

Eine Markierung ist ein Diagnoseelement, das in das Layout eingefügt wird. Daher misst sie das resultierende Layout. Wenn Sie sie in einen beliebigen vorhandenen Absatz einfügen, kann dadurch eine Umbruchmöglichkeit entstehen oder das Layout anderweitig beeinflusst werden. Verwenden Sie vorzugsweise die Berechnung anhand des vorhandenen Bildes, wenn deren Voraussetzungen erfüllt sind. Wenn Sie eine Markierung in echten Inhalt einfügen, prüfen Sie, ob dieselben Bilder weiterhin auf derselben Zeile liegen und ihre Positionen unverändert geblieben sind.

Situation Geeigneter nächster Schritt
Bilder verwenden die Ausrichtung top, bottom oder middle Prüfen Sie diese Ausrichtungsregel; wenden Sie die Formel für grundlinienausgerichtete Bilder nicht unverändert an
Das Bild befindet sich in einem Inline-Block-Wrapper Prüfen Sie die Grundlinie des Wrappers; sie kann sich aus dessen letzter Inhaltszeile ergeben
Bilder verteilen sich auf mehrere umgebrochene Zeilen Bestimmen Sie die Grundlinie für jede Zeile einzeln
Das übergeordnete Element verwendet ein Flex- oder Grid-Layout Prüfen Sie die Ausrichtungsregeln dieses Layouts, bevor Sie die Reihe als Inline-Zeile behandeln
Das Dokument verwendet vertikale Schreibrichtung Verwenden Sie Grundlinienregeln, die die Schreibrichtung berücksichtigen, anstatt eine y-Koordinate an der Unterkante zu verwenden
Das Bild wurde nicht erfolgreich geladen Klären Sie seinen Darstellungszustand, bevor Sie es als angezeigte Bildbox behandeln

Die letzte Bedingung ist relevant, weil WHATWG unterschiedliche Darstellungswege für angezeigte Bilder, noch nicht geladene Bilder und Alternativtext beschreibt. Ein defektes Bild, das seine Beschriftung anzeigt, muss daher möglicherweise anders interpretiert werden als das erfolgreich dargestellte Bild, das Sie messen wollten. Siehe die Regeln zur Bilddarstellung im HTML-Standard.

Leiten Sie nicht allein daraus eine gemeinsame Grundlinie ab, dass mehrere Bildrechtecke ähnliche obere Koordinaten haben. Bilder unterschiedlicher Höhe können eine gemeinsame Grundlinie haben und unterschiedliche Oberkanten aufweisen. Umgekehrt belegen übereinstimmende Oberkanten keine Grundlinienausrichtung. Prüfen Sie, welche Boxen an derselben Zeile teilnehmen und welche Ausrichtungsregel gilt.

Können Textmessungs-APIs oder Shaping-Bibliotheken die Antwort liefern?

Die hier verwendeten Browser-Geometriemethoden geben Rechtecke zurück und kein eigenes Feld für die Grundlinie einer Zeile. Range.getClientRects() kann dabei helfen, die von einem Bereich belegten Flächen zu untersuchen, aber die zurückgegebenen Rechtecke liefern die Grundlinienkoordinate nicht direkt. MDN beschreibt diese Schnittstelle unter Range.getClientRects().

Canvas-Textmetriken beantworten eine andere Frage: Wie ein Stück Canvas-Text zur ausgewählten Textgrundlinie des Canvas-Kontexts liegt. Zum Beispiel beschreiben actualBoundingBoxAscent und actualBoundingBoxDescent die Tintenbegrenzungen des Textes relativ zu dieser Referenz. Damit lässt sich die Position einer vorhandenen DOM-Bildzeile nicht direkt bestimmen. Siehe die MDN-Dokumentation zu TextMetrics.

Eine Text-Shaping-Bibliothek hat ebenfalls einen engeren Aufgabenbereich als das Zeilenlayout des Browsers. Das HarfBuzz-Handbuch erläutert, dass die Bibliothek Textläufe formt und Informationen zur Glyphenanordnung bereitstellt, während der Zeilenumbruch und die Blocksatzausrichtung von Absätzen nicht zu ihrem Aufgabenbereich gehören. HarfBuzz zu installieren, liefert daher keine Messung einer Bildzeile im Browser. Der dokumentierte Aufgabenbereich verdeutlicht diese Abgrenzung.

Prüfen Sie bei einer horizontalen Zeile, die nur aus Bildern besteht, zunächst den normalen Inline-Fluss und die Grundlinienausrichtung. Lesen Sie dann die Unterkante der Rahmenbox eines geeigneten Bildes aus und addieren Sie dessen unteren Außenabstand. Verwenden Sie in einem kontrollierten Layout die Markierung mit den Maßen null als sichtbare Gegenprobe. Wenn diese beiden Referenzen voneinander abweichen, untersuchen Sie den Formatierungskontext erneut.

Quellen