Vertically Center Multi-Lined Text

Chris Coyier on Updated on

If you only have a single word or a single line of text, there is a clever way to vertically center it in a block with CSS. You set the line-height of that text to be equal to the height of the box. Works great, but is a major fail if that text needs to wrap.

A “speech bubble” is a classic example of somewhere we might want text to be centered both horizontally and vertically and be adaptable to multiple lines. There is a little, fairly simple CSS trick for this, using CSS tables. Here is the outcome:

View DemoDownload Files

The HTML is nothing fancy. The “area” is just the region we are dealing with, where we can set position: relative; so that we can absolutely position the text are inside the bubble.

<div class="area"> <div class="bubble"> <p>To look best, text should really be centered inside this bubble both vertically and horizontally.</p> </div> </div>

The “bubble” we’ll set to display: table;, which really doesn’t do much by itself, but then we can set the <p> element inside to be a table-cell, which allows us to use the vertical-align property on it.

.area { width: 300px; height: 300px; background: url(../images/abe-bg.png) no-repeat; position: relative; } .bubble { position: absolute; left: 93px; top: 21px; width: 135px; height: 84px; display: table; } .bubble p { display: table-cell; vertical-align: middle; text-align: center; }

Does the trick beautifully I think. This current version of CSS-Tricks has a little twitter speech bubble down by the footer I used this for.

What about IE <= 7 ?!

IE 8 is supporting CSS tables, but IE 7 and below do not. Too bad, so sad. Instead you get this:

… could be worse. I was hoping the Dean Edwards ie8.js would solve this but no dice (yet).

UPDATE 1

Boris Kuzmic comments below a perfect solution to make IE 6 and 7 work perfectly:

<!--[if lt IE 8]> <style> .bubble { position: absolute; left: 93px; top: 21px; width: 135px; height: 84px; text-align: center;} .bubble p { position: relative; font-size: 11px; margin-top: expression(this.offsetHeight < this.parentNode.offsetHeight ? parseInt((this.parentNode.offsetHeight - this.offsetHeight) / 2) + "px" : "0"); } </style> <![endif]-->

UPDATE 2

Boris again with a way to make the IE expression not leak memory (this way it only needs to be evaluated once, not continuously run).

.bubble p { position: relative; font-size: 11px; margin-top: inherit; *clear: expression( style.marginTop = "" + (offsetHeight < parentNode.offsetHeight ? parseInt((parentNode.offsetHeight - offsetHeight) / 2) + "px" : "0"), style.clear = "none", 0 ); }

UPDATE 3

James John Malcolm chimes in with another technique for IE. It’s slightly less semantic (requires and extra div), but it needs no expression.

First wrap the inside <p> in a new <div> and then:

<!--[if lt IE 8]> <style> .bubble div { position: absolute; top:50%;} .bubble div p {position: relative; top: -50%} </style> <![endif]–>

UPDATE 4

Another method from Andy Howard.