CSS baseline-source: choose the first or last line

A box with several lines of text that sits inside a sentence has to line up on one of them. baseline-source says which one.

baseline-source decides which line of a multi-line inline box lines up with the text around it. first uses the box's first line, last uses its last line, and auto (the default) uses the last line for inline-block and the first line for everything else.

Chrome, Edge and Firefox support it. Safari does not.

Try it first. The card below has three lines and sits in the middle of a sentence. Press the buttons to change its baseline-source.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>baseline-source: auto, first, last</title>
<style>
  body { margin: 0; padding: 16px; font: 16px/1.5 system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  .line { background: #fff; border-radius: 10px; padding: 18px 14px; }
  .card {
    display: inline-block;              /* a box with three lines of text */
    padding: 4px 10px; border-radius: 8px;
    background: #e8f0ff; border: 1px solid #b7c9ef; line-height: 1.3;
  }
  .buttons { margin-top: 14px; display: flex; gap: 8px; flex-wrap: wrap; }
  button { font: inherit; font-size: 14px; padding: 6px 12px; border-radius: 8px; border: 1px solid #c9cdd4; background: #fff; cursor: pointer; }
  button[aria-pressed="true"] { background: #1d2330; color: #fff; border-color: #1d2330; }
  #note { font-size: 13px; color: #5b6270; margin: 10px 0 0; }
</style>
</head>
<body>
<div class="line">
  The plan is <span class="card" id="card"><b>Pro</b><br>$12 a month<br>billed yearly</span> for the whole team.
</div>

<div class="buttons">
  <button aria-pressed="true" data-v="auto">auto</button>
  <button aria-pressed="false" data-v="first">first</button>
  <button aria-pressed="false" data-v="last">last</button>
</div>
<p id="note"></p>

<script>
  const card = document.getElementById('card');
  const note = document.getElementById('note');

  document.querySelectorAll('button').forEach((btn) => {
    btn.addEventListener('click', () => {
      card.style.baselineSource = btn.dataset.v;  // the one line that matters
      document.querySelectorAll('button').forEach((b) => b.setAttribute('aria-pressed', b === btn));
    });
  });

  // Tell the reader if the buttons can do anything in this browser
  note.textContent = CSS.supports('baseline-source', 'first')
    ? 'Your browser supports baseline-source.'
    : 'Your browser does not support baseline-source, so all three buttons look the same.';
</script>
</body>
</html>
One inline-block card, three values. The note under the buttons says whether your browser supports the property.

With auto and last, the card rises so that "billed yearly" sits on the sentence. With first, "Pro" sits on the sentence and the rest of the card hangs below.

What baseline-source changes

Text in a line sits on a shared baseline, the line the letters rest on. A box inside that line has to put one of its own baselines on it. A box that holds several lines has several candidates.

The CSS Inline Layout spec says: when an inline-level box has more than one possible source for baseline information, baseline-source says whether its first or last baseline set is preferred for alignment.

.card {
  display: inline-block;
  baseline-source: first;  /* auto | first | last */
}

It does not move the text inside the box. It only moves the whole box up or down in its line.

Why auto means two different things

The default is auto, and it depends on the box. For inline-block it means the last line. For every other box, including inline-flex and inline-grid, it means the first line.

With auto, an inline-block lines up on its last line and an inline flex box on its first.
With auto, an inline-block lines up on its last line and an inline flex box on its first.

The inline-block rule is old. CSS 2.1 already defined the baseline of an inline-block as the baseline of its last line box. baseline-source keeps that as the default and adds a way to ask for the first line.

The three values

Value inline-block inline-flex, inline-grid
auto Last line First line
first First line First line
last Last line Last line

So first is the useful value on an inline-block, and last is the useful value on an inline flex or grid box. The other combinations match the default.

The property is not inherited. Set it on the box that sits in the line, not on its parent.

This example puts the same three-line box into a line of text as an inline-block, as a column inline flex box, and as an inline-block with overflow: hidden.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>baseline-source on three kinds of box</title>
<style>
  body { margin: 0; padding: 14px; font: 15px/1.5 system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  .row { background: #fff; border-radius: 10px; padding: 12px 12px 14px; margin-bottom: 10px; }
  .row h3 { margin: 0 0 6px; font-size: 13px; color: #5b6270; font-weight: 600; }
  .box { width: 64px; padding: 2px 6px; line-height: 1.25; border: 1px solid #b7c9ef; background: #e8f0ff; border-radius: 6px; }
  .ib { display: inline-block; }
  .fx { display: inline-flex; flex-direction: column; }
  .scroll { display: inline-block; overflow: hidden; }  /* overflow: hidden makes a scroll container */
  .first { baseline-source: first; }
  .last { baseline-source: last; }
  code { font-size: 12px; background: #eef1f5; padding: 0 3px; border-radius: 4px; }
</style>
</head>
<body>
<div class="row">
  <h3>inline-block</h3>
  Text <span class="box ib">auto<br>B<br>C</span> text <span class="box ib first">first<br>B<br>C</span> text
</div>
<div class="row">
  <h3>inline-flex, column</h3>
  Text <span class="box fx"><span>auto</span><span>B</span><span>C</span></span> text <span class="box fx last"><span>A</span><span>B</span><span>last</span></span> text
</div>
<div class="row">
  <h3>inline-block with <code>overflow: hidden</code></h3>
  Text <span class="box scroll">auto<br>B<br>C</span> text <span class="box scroll first">first<br>B<br>C</span> text
</div>
</body>
</html>
Left of each row: auto. Right: the other value. In a browser without support, the right boxes look like the left ones.

The third row shows a case that surprises people. Setting overflow: hidden on an inline-block makes the whole box drop so that its bottom edge sits on the text line.

Why overflow: hidden drops the box

The CSS Box Alignment spec keeps a legacy rule. A block container that scrolls in the block direction, and whose baseline-source is auto, uses its bottom margin edge as its last baseline. A box with overflow: hidden counts, because it is a scroll container.

A scroll container with auto uses its bottom edge. Setting first uses a real line of text.
A scroll container with auto uses its bottom edge. Setting first uses a real line of text.

The legacy rule only applies while the value is auto. Setting baseline-source: first puts the first line of text on the sentence again, and last uses the real last line instead of the bottom edge.

The same fix works for overflow: auto and overflow: scroll. overflow: clip does not make a scroll container, so it never had the problem.

For more on the other ways to move an inline box up and down, see CSS vertical-align.

Browser support and a fallback

MDN's compatibility data lists baseline-source as supported in Chrome, Edge and Firefox, and in Chrome and Firefox for Android. It lists Safari, on macOS and iOS, as not supported.

I checked in Playwright's Chromium 147, Firefox 148 and WebKit 26.4: the first two applied it, WebKit ignored it.

A support check returned false in that WebKit build, so @supports can tell the two apart:

CSS.supports('baseline-source', 'first')  // false in WebKit

The fallback is to change display, because each display type already has a default line:

@supports not (baseline-source: first) {
  /* inline-flex lines up on its first line by default */
  .chip { display: inline-flex; flex-direction: column; }
  /* inline-block lines up on its last line by default */
  .stat { display: inline-block; }
}
Where the property is ignored, a display swap inside @supports gives the same line.
Where the property is ignored, a display swap inside @supports gives the same line.

The spec also lets vertical-align take first or last as a shorthand. None of the three engines above accepted that syntax, so write the baseline-source longhand.

A finished example: chips and a stat inside a sentence

Two common cases. A person chip has a name and a role; the name should read as part of the sentence. A stat has a small label and a big number; the number should sit on the line.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>People chips and a stat in a sentence</title>
<style>
  body { margin: 0; padding: 16px; font: 16px/1.6 system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  p { background: #fff; border-radius: 10px; padding: 14px 16px; margin: 0 0 12px; }

  /* Two-line chip: name on the first line lines up with the sentence */
  .chip {
    display: inline-block; baseline-source: first;
    padding: 2px 10px 4px 34px; border-radius: 10px; line-height: 1.3;
    background: #eef1f5 no-repeat 6px 6px / 22px 22px;
  }
  .chip b { font-weight: 600; }
  .chip small { display: block; color: #5b6270; font-size: 12px; }
  .a { background-image: radial-gradient(circle, #7aa7ff 64%, transparent 66%); }
  .b { background-image: radial-gradient(circle, #62c28d 64%, transparent 66%); }

  /* Stat: label on top, the number on the last line sits on the sentence */
  .stat {
    display: inline-flex; flex-direction: column; baseline-source: last;
    padding: 2px 10px; border-radius: 10px; background: #fff4d6; line-height: 1.2;
  }
  .stat small { font-size: 11px; color: #7a5b00; text-transform: uppercase; letter-spacing: .4px; }
  .stat b { font-size: 26px; }

  /* Browsers without baseline-source: swap display to get the same result */
  @supports not (baseline-source: first) {
    .chip { display: inline-flex; flex-direction: column; }  /* inline-flex uses its first line */
    .stat { display: inline-block; }                          /* inline-block uses its last line */
    .stat small { display: block; }
  }
</style>
</head>
<body>
<p>
  Review by <span class="chip a"><b>Ana Kim</b><small>Design</small></span>
  and <span class="chip b"><b>Ben Ito</b><small>Front end</small></span> is due on Friday.
</p>
<p>
  This sprint closed <span class="stat"><small>tickets</small><b>42</b></span> issues, up from last week.
</p>
</body>
</html>
The chips use first, the stat uses last. The @supports block gives the same result where the property is not supported.
  • Chips: display: inline-block with baseline-source: first. The role hangs below the name.
  • Stat: a column inline flex box with baseline-source: last. The label sits above the line and the number sits on it.
  • Fallback: the @supports not block swaps display so Safari lines them up the same way.

If you only need the first line on a box, display: inline-flex with flex-direction: column gets it in every browser. baseline-source is for keeping the display you want.

When it does not work

What you see Cause Fix
Nothing changes The browser does not support it (Safari) Swap display inside @supports not
Nothing changes on a block It only affects inline-level boxes Use inline-block, inline-flex or inline-grid
Flex items do not line up with each other That is item alignment, not baseline-source align-items: first baseline or last baseline
The box sits on its bottom edge It is a scroll container (overflow: hidden) with auto baseline-source: first or last
Setting it on the parent does nothing It is not inherited Put it on the box in the line
vertical-align: first is dropped Browsers tested do not accept that shorthand form Use baseline-source: first

For lining up items inside a flex container rather than in a line of text, see align-items.

Alignment is easier to judge by looking than by reading a description, and it can differ by browser. A screenshot only shows one browser, and an .html attachment may open as plain code on a phone.

To let someone check it in their own browser, paste the page into a NOS document and choose Create share link. HTML to link walks through it.

The page renders as written and its scripts run, so they can press the buttons themselves. If you change the code later, the same link shows the new version.

Questions people ask

What does baseline-source do in CSS?

When an inline-level box such as a multi-line inline-block or an inline flex container has more than one possible baseline, baseline-source picks whether its first or last baseline set is used to line it up with the text around it.

What is the default value?

auto. It means the last baseline for an inline-block and the first baseline for everything else, such as inline-flex and inline-grid.

Does Safari support baseline-source?

MDN's compatibility data lists support in Chrome, Edge and Firefox and no support in Safari. In WebKit the property is ignored, so an inline-block keeps lining up on its last line. Swapping to display: inline-flex with flex-direction: column gets first-line alignment there.

Is baseline-source the same as align-items: first baseline?

No. baseline-source applies to inline-level boxes that sit in a line of text. To line up flex or grid items with each other, use align-items or align-self with first baseline or last baseline on the container or item.

Can I write vertical-align: first instead?

The CSS Inline Layout spec makes vertical-align a shorthand that accepts first or last and sets baseline-source. In my tests, Chromium, Firefox and WebKit all rejected that syntax, so use the baseline-source longhand.

Keep reading