1.21 gigawatts 1.21 gigawatts - 4 years ago 138
HTML Question

How to vertically align content without nested additional containers?

I've been having a lot of trouble with vertically aligning an item in it's container.

I've implemented plenty of suggestions. All of them suggest wrapping the content in another div or container.

This has caused all sorts of issues for various reasons I won't get into but I would like to choose a new requirement: That it not be wrapped in another container.

That lead me to this solution (styles inline for brevity):

<div style="display:table-cell;vertical-align:middle">my content</div>


Or this:

<td style="vertical-align:middle">my content</td>


I like the first option more than the second because with the second you sort of go, "why is there a Table Cell in the middle of this other content that is independent of a table?"

The reason I'm hesitant to use the first option is because I'm not sure it will work in all browsers. I could say the same about the second option as well.

Which option is better in terms of semantics and browser support?

Answer Source

To vertically center content, without nesting additional wrappers, you can simply use flexbox.

CSS

div {
    display: flex;
    align-items: center;  /* center content vertically, in this case */
    justify-content: center; /* (optional) center content horizontally, in this case */
}

HTML

<div>my content</div>

DEMO

Note that although the text in the div appears to not have a container, technically when the div becomes a flex container the text becomes wrapped in an anonymous container that becomes the flex item. This is how CSS works. If you don't wrap your content in an HTML element, CSS will create anonymous block or inline boxes.


You wrote:

I like the first option more than the second because the second you sort of go, "why is there a Table Cell in the middle of this other content that is independent of a table?"

The reason I'm hesitant to use the first option is because I'm not sure it will work in all browsers. I could say the same about the second option as well.

From a functional perspective, there is no difference between:

<div style="display:table-cell;">my content</div>

and

<td>my content</td>

Both do the same thing. Here's why:

HTML elements, including div and td, have no display value until the browser applies styles with the default stylesheet.

Hence, the only reason a td acts like a table cell is because the browser's default stylesheet specifies td { display: table-cell; }.

You're doing the same with the div, by overriding the browser's display: block with your own display: table-cell.

So it's really the same thing in terms of functionality and all players – div, td, display: table-cell and vertical-align: middle are supported by all browsers going back to at least IE6.

Browser support for flexbox, however, is not yet complete. Flexbox, which is CSS3, is supported by all major browsers, except IE 8 & 9. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add all the prefixes you need, post your CSS in the left panel here: Autoprefixer.


As an aside:

HTML elements have no inherent styling. In other words, the tag names themselves don't carry styles. It isn't until they go through the browser that display and other CSS properties are applied. (See an HTML Default Stylesheet.)

Based on this MDN Bug Report, it appears that the only HTML elements who's boxes are constructed based on their tag name are <button>, <fieldset> and <legend>.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download