For a horizontal line of baseline-aligned inline images, the baseline is at each image’s bottom margin edge. This guide shows how to locate that coordinate in Chrome on a Mac, check it with a small marker, and recognize when that method does not apply.
Why does a line containing only images have a baseline?
An image-only line still participates in CSS inline layout. A successfully displayed img is a replaced element: the browser lays out its box according to CSS rather than treating its picture as text. WHATWG documents this rendering behavior in the HTML Standard’s image-rendering rules.
In ordinary horizontal inline layout, an image without an intrinsic text baseline uses its bottom margin edge for baseline alignment. Consequently, two baseline-aligned images of different heights can share the same baseline while their top edges sit at different heights. The rule concerns their boxes; it does not examine the artwork inside them. See CSS 2, vertical alignment.
Three different boundaries matter:
| Boundary | Meaning | Suitable baseline reference? |
|---|---|---|
| Visible artwork edge | Where the picture’s visible pixels end | No; the file may contain transparent space |
| Image border-box bottom | The bottom returned by getBoundingClientRect() |
Yes, after accounting for the bottom margin and confirming baseline alignment |
| Line-box bottom | The lower boundary of the complete CSS line | No; it can extend below the baseline |
The parent’s font and line-height still matter when there are no visible letters. CSS describes an invisible font-based contribution called a strut, which helps establish the line’s minimum height and depth. That explains why an image can sit on the baseline while the line retains space underneath it. The CSS Inline Layout specification describes these font metrics and layout bounds; the retrieved published version is a Working Draft, so its newer features should not be assumed to have universal browser support.
How do you find the baseline on an existing page?
Start with a page you can inspect in Chrome on your Mac. Right-click an image and choose Inspect. Chrome opens the Elements panel with that element selected; the Styles pane shows its applied CSS. Google documents this workflow in Open Chrome DevTools.
Check the following conditions before calculating a coordinate:
- The image participates in normal inline flow on the target line.
- Its effective alignment is
vertical-align: baseline. - The writing mode is horizontal.
- Neither the image nor its ancestors has a transform or visual positioning offset affecting the measurement.
- You are measuring the image itself, rather than a surrounding wrapper with its own baseline behavior.
These conditions define the scope of the calculation. For example, vertical-align: bottom aligns an element with the bottom of the line, while middle uses the parent’s baseline plus half its x-height. Neither value means that the image’s bottom edge identifies the parent baseline. MDN explains these distinctions in its vertical-align reference.
Once those conditions hold, use this relationship, with all distances expressed in CSS pixels:
baselineY = imageBorderBoxBottom + imageMarginBottom
getBoundingClientRect() supplies the border-box bottom relative to the viewport. Its rectangle includes padding and borders, so those must not be added a second time. Margins sit outside that rectangle. MDN documents the returned geometry and coordinate system in Element.getBoundingClientRect().
For an explicitly illustrative calculation, suppose the image’s border-box bottom is 240.5 and its bottom margin is 6. The baseline is therefore 246.5 CSS pixels below the viewport’s top. If the container’s border-box top is 200, that baseline is 46.5 CSS pixels below the container’s top border edge. This is an offset from the border edge, not automatically from the content edge.
Measure another qualifying image on the same line as a cross-check. Its bottom margin edge should identify the same baseline, even if its height differs. A disagreement is a reason to inspect alignment, wrappers, positioning, or line wrapping before changing CSS. Keep fractional values during the comparison.
How can you verify the result with a baseline marker?
A useful diagnostic is an empty inline-block with zero width, height, margins, padding, and borders, aligned to the baseline. Because it has no in-flow line boxes, its baseline is its bottom margin edge. With all those dimensions zero, that edge coincides with its measured vertical position. This follows the CSS 2 inline-block baseline rule.
The following complete console program creates a temporary demonstration with two neutral rectangular images and a marker. It uses a shadow root to keep the sample’s internal styles separate from ordinary page selectors. Run it in a standards-mode document without transforms on the document or body. It measures only its own synthetic row, not an existing page’s content.
Open the Console with Command + Option + J, as documented in Chrome’s DevTools shortcuts, and run the program. No library installation or external image file is required. The sample generates its rectangles with the standard 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;
}
})();
The program waits for both images to decode before measuring. The documented HTMLImageElement.decode() method returns a promise and can reject if decoding fails; the program removes its temporary panel and reports the error in that case.
Both images have zero bottom margin, so their reported imageBottom values should match markerBaseline. The thin horizontal guide marks that coordinate. The row’s background also lets you distinguish the baseline from any remaining space underneath. Select Remove demonstration when finished.
For a controlled experiment, change the sample images’ bottom margin from 0 to 6px in the image style. Their border-box bottoms should then sit six CSS pixels above the marker baseline. Apply the earlier formula to recover the shared coordinate. This gives you two independent references within the sample: the image’s margin edge and the empty marker.
When does this method need a different approach?
A marker is a diagnostic insertion, so it measures the resulting layout. Adding one to an arbitrary existing paragraph can introduce a break opportunity or otherwise affect layout. Prefer the existing-image calculation when its prerequisites hold. If you insert a marker into real content, confirm that the same images remain on the same line and that their positions have not changed.
| Situation | Appropriate next step |
|---|---|
Images use top, bottom, or middle alignment |
Inspect that alignment rule; do not apply the baseline-aligned-image formula unchanged |
| The image sits inside an inline-block wrapper | Inspect the wrapper’s baseline, which may come from its last line of content |
| Images occupy multiple wrapped lines | Determine a baseline separately for each line |
| The parent uses flex or grid layout | Inspect that layout’s alignment rules before treating the row as an inline line |
| The document uses vertical writing | Use writing-mode-aware baseline rules rather than a bottom-edge y-coordinate |
| The image has not loaded successfully | Resolve its rendering state before treating it as a displayed image box |
The last condition matters because WHATWG describes different rendering paths for displayed images, pending images, and alternative text. A broken image displaying its label may therefore require a different interpretation from the successfully rendered image you intended to measure. See the HTML image-rendering rules.
Avoid inferring one shared baseline merely because several image rectangles have similar top coordinates. Images with different heights can share a baseline and have different tops. Conversely, aligned tops do not establish baseline alignment. Confirm which boxes participate in the same line and which alignment rule applies.
Can text-measurement APIs or shaping libraries supply the answer?
The browser geometry methods used here return rectangles, rather than a dedicated line-baseline field. Range.getClientRects() can help inspect the areas occupied by a range, but its returned rectangles do not directly provide the baseline coordinate. MDN describes that interface in Range.getClientRects().
Canvas text metrics answer another question: how a piece of canvas text relates to the canvas context’s selected text baseline. For example, actualBoundingBoxAscent and actualBoundingBoxDescent describe the text’s ink bounds relative to that reference. They do not directly locate an existing DOM image row. See MDN’s TextMetrics documentation.
A text-shaping library also has a narrower responsibility than browser line layout. The HarfBuzz manual states that it shapes text runs and supplies glyph-layout information, while paragraph line breaking and justification remain outside its responsibility. Thus, installing HarfBuzz does not provide a measurement of a browser’s image-only line. Its documented scope helps establish that boundary.
For a horizontal image-only line, first confirm normal inline flow and baseline alignment. Then read a qualifying image’s border-box bottom and add its bottom margin. Use the zero-size marker in a controlled layout when you need a visible cross-check, and reassess the formatting context whenever those two references disagree.
Sources
HTML Standard: Rendering — WHATWG.
HTML Standard: The canvas element — WHATWG.
Open Chrome DevTools — Google Chrome for Developers.
vertical-align CSS property — MDN Web Docs.
Element: getBoundingClientRect() method — MDN Web Docs.
HTMLImageElement: decode() method — MDN Web Docs.
Range: getClientRects() method — MDN Web Docs.
TextMetrics — MDN Web Docs.
What HarfBuzz doesn’t do — HarfBuzz.