Bat­tle for Base­line

Kitties

The best so­lu­tion for in­line blocks were, well, in­line-blocks. I used to like them be­cause you could solve a lot of tasks with them. But they're not ideal. They're not ca­pa­ble of do­ing base­line ver­ti­cal align­ing right. And the prob­lems come straight from the specs, just read the last two para­graphs to see the problems:

  1. “The base­line of an in­line-block is the base­line of its last line box in the nor­mal flow.”

  2. “If [in­line-block's] over­flow prop­erty has a com­puted value other than vis­i­ble, [its] base­line is the bot­tom mar­gin edge.”

Those rules make only one lined, sim­ple in­line-blocks us­able with ver­ti­cal-align: base­line, in all other com­plex cases, we would get not what we would need.

Here is an ex­am­ple: all three blocks have dis­play: in­line-block, the first one is sim­ple one­liner, but with big­ger padding, sec­ond one is mul­ti­line, but has smaller font-size and the third one has over­flow: auto.

Screenshot
I'm an inline-block
I'm an inline-block
With a second line
I'm an inline-block with an overflow auto

You can see (Btw, in the lat­est Sa­fari the block with over­flow don't be­have ac­cord­ing to the specs) where each block has its base­line in this ex­ample.

in­line-table

Ac­tu­ally, there was one place in CSS, where the base­line align­ing worked prop­erly: dis­play: in­line-table. If we'd use it in­stead of in­line-blocks in our ex­am­ple, we'd get al­most what we tried to achieve:

Screenshot
I'm an inline-table
I'm an inline-table
With a second line
I'm an inline-table with an overflow auto

You can see an ob­vi­ous flaw: the over­flow: auto is not work­ing. And you shouldn't for­get that you'll need to have table-lay­out: fixed. So, in­line-table is nice as long as we don't need over­flow other than vis­i­ble.

Try­ing to go flex

So, can we do a block both with the proper base­line and with some over­flow? It seems we can, us­ing flexboxes —dis­play: in­line-flex. In the­ory, they have a cor­rect base­line po­si­tion in all com­plex cases, but what would we get in practice?

Screenshot
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto

If you'd look at this ex­am­ple in any browser other than Fire­fox, you'll see nicely aligned blocks (yep, even in IE10 and Opera 12).

But in Fx the block with over­flow: auto, sud­denly, be­haves just like the in­line-blocks —it loses the base­line. So sad, this way we'll need to wait for this newly re­ported bug to be fixed.

Is there an­other way?

It is nice we could align in­line-flex blocks with the base­lines of other blocks, if only there wasn't this Fx bug… But what if we'd go and try to align not dif­fer­ent in­line-flex blocks, but their children?

Screenshot
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto

Oh, it works. But… While mul­ti­ple in­line-flex blocks could wrap on over­flow, for el­e­ments in­side flexbox we would need to use flex-wrap to wrap them. And guess what? Fire­fox didn't sup­port this prop­erty un­til 28.0.

All to­gether

But hey! If in­line-flex is prop­erly aligned along­side other blocks and the nested block with over­flow: auto also has a proper base­line, then what if we'd com­bine those two? We would add an­other wrap­per in­side each el­e­ment, then move all the paddings and over­flow to them:

Screenshot
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto

In most browsers you won't see any changes, but when we'll look at Fx, we would see that the blocks now won't have base­line at their bot­tom mar­gin edge. But they won't have it at the proper place ei­ther —they're shifted from the base­line of other blocks a lit­tle. Let's mea­sure it —10 pix­els. Hey, it is our padding! By re­mov­ing paddings from each side we found that the prob­lem is at the top padding —when we re­move it every­thing works great. So, if the bug is in the padding (and I re­ported it too), how could we work around it? Let's re­move it and re­place with a pseudo-el­ement:

Screenshot
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto

Perfect!

Fin­ish­ing strokes

Well, not per­fect. There are two small is­sues that can ap­pear in IE 10 and Opera 12.

In IE flexbox with the set width wouldn't have wrapped text in­side of it. That's a rather strange bug, but we could work around it by adding width: 100% or -ms-flex-neg­a­tive: 1 to the in­ner el­e­ment, the lat­ter is better.

Opera has a sim­i­lar bug —the el­e­ment in­side a flexbox would have the width set to con­tent. The only fix I found is adding flex-di­rec­tion: col­umn to flexbox. As there would be only one el­e­ment in­side our wrap­per, it won't af­fect any­thing else.

There, now it's per­fect (No fall­backs for older browsers though, but this slightly falls out of this post's scope), there is the last ex­am­ple with dif­fer­ent vari­ants of blocks and with the wrap­ping blocks:

Screenshot
Just some inline text
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
I'm an inline-flex with the text wrapped on the next lines
I'm just another inline-flex block with a lot of content and overflow: auto.

The re­sult­ing code for this ex­am­ple would be:

.flex {
    dis­play: -ms-in­line-flexbox;
    dis­play: -we­bkit-in­line-flex;
    dis­play: in­line-flex;

    /* Fix­ing Opera is­sue */
    flex-di­rec­tion: col­umn;

    ver­ti­cal-align: base­line;
    }

.flex-con­tent {
    padding: 0 10px 10px;
    bor­der: 1px solid lime;

    /* Fix­ing IE is­sue */
    -ms-flex-neg­a­tive: 1;
    }

/* Fix­ing Fx is­sue */
.flex-con­tent:be­fore {
    con­tent: "";
    dis­play: block;
    padding-top: 10px;
    }

Ove­rall

Ah, Fire­fox! With­out its bugs (and IE's one) we could use only one el­e­ment per block. Also, if you'll need just mul­ti­line in­line blocks, and you're not afraid of ta­bles, you could use dis­play: in­line-table.

But, over­all, we won. We can now use base­line ver­ti­cal align­ing for blocks of any com­plex­ity, hooray! But if you'd want to write even bet­ter code in the fu­ture, I'd rec­om­mend you to go and vote for the cor­re­spond­ing bugs in Bugzilla.