51

I have a <div> element with a fixed height, and I'd like to center some text vertically within that element.

I've been trying to follow the instructions at http://phrogz.net/css/vertical-align/index.html. However, it doesn't seem to work for me.

I've posted what I'm trying at http://jsfiddle.net/scwebgroup/74Rnq/. If I change the HeaderBrand's margin-top to about -22px, it seems about right.

Can anyone see why the technique described in the article is not working as expected for me?

Note: The best answer here only works if the text doesn't wrap to a second line.

Community
  • 1
  • 1
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Proper demo: http://jsfiddle.net/74Rnq/2/ – Šime Vidas Sep 30 '11 at 23:19
  • Thanks, but in Google Chrome, the text is not vertically centered. – Jonathan Wood Sep 30 '11 at 23:21
  • That's not supposed to be the solution. I merely improved the presentation of your own demo. – Šime Vidas Sep 30 '11 at 23:26
  • possible duplicate of [How to align text vertically center in div with css?](http://stackoverflow.com/questions/8865458/how-to-align-text-vertically-center-in-div-with-css) – user Mar 07 '14 at 20:53
  • @JonathanWood I chose that answer because it's more popular. Duplicate is not always about newer vs older, see, for example, [this topic](http://meta.stackexchange.com/questions/182868/why-is-an-older-question-marked-as-duplicate) on meta. – user Mar 07 '14 at 21:03

7 Answers7

46

This:

<!DOCTYPE html>
<style>
  .outer { outline: 1px solid #eee; }
  .outer > p { display: table-cell; height: 200px; vertical-align: middle; }
</style>

<div class="outer">
  <p>This text will be vertically aligned</p>
</div>

<div class="outer">
  <p>This longer text will be vertically aligned. Assumenda quinoa cupidatat messenger bag tofu. Commodo sustainable raw denim, lo-fi keytar brunch high life nisi labore 3 wolf moon readymade eiusmod viral. Exercitation velit ex, brooklyn farm-to-table in hoodie id aliquip. Keytar skateboard synth blog minim sed. Nisi do wes anderson seitan, banksy sartorial +1 cliche. Iphone scenester tumblr consequat keffiyeh you probably haven't heard of them, sartorial qui hoodie. Leggings labore cillum freegan put a bird on it tempor duis.</p>
</div>

works in modern browsers, regardless of whether text spans only one or multiple lines.

Also updated the fiddle at http://jsfiddle.net/74Rnq/135/ Not sure what you were doing with a 625px margin on the left when the thing itself was only 150px in width… Tidied things up a bit by removing the inline styling and using a bit of padding as well.

Matijs
  • 3,118
  • 2
  • 29
  • 41
14

You can try setting the line-height to the height of the div, like this:

<div style="height:200px;border:1px solid #000;"> 
    <span style="line-height:200px;">Hello world!</span> 
</div> 

Here's another technique that seems to work:

#vertical{
    position:absolute;
    top:50%;    
    left:0;
    width:100%;
}

<div style="position:relative;height:200px;">
    <div id="vertical">
        Hello world!
    </div>              
</div>
James Johnson
  • 45,496
  • 8
  • 73
  • 110
  • 1
    Thanks, but this appears to be the same technique described in the stackoverflow link I mentioned at the end. It's a nice clean technique, but fails if the text wraps to a second line. – Jonathan Wood Sep 30 '11 at 23:22
  • 1
    @JonathanWood - If you want this technique with multiple lines, you can follow my answer here: http://stackoverflow.com/questions/7542387/how-can-i-align-to-middle-by-height/7542684#7542684 – Alohci Sep 30 '11 at 23:30
  • Thanks but this is getting a bit too "out there" for me. Your warning that it won't work with IE7 is a show-stopper for me. – Jonathan Wood Sep 30 '11 at 23:36
5

I know this method adds some HTML, but it seems to work in all major browsers (even IE7+).

Basic HTML Structure

<div id="hold">
  <div>Content</div>
  <div class="aligner">&nbsp;</div>
</div>​

Require CSS

#hold{
    height:400px;
}
div{
    display:        -moz-inline-stack;
    display:        inline-block;
    zoom:            1;
    *display:        inline;
    vertical-align:middle;
}
.aligner{
    width:0px;
    height:100%;
    overflow:hidden;
}​

The jsFiddle

DACrosby
  • 11,116
  • 3
  • 39
  • 51
4

As shown below you can easily just set the parent of a text element to position: relative, and the text element itself to position: absolute; Then use direction properties to move around the text inside the parent. See examples below...

<!--Good and responsive ways to center text vertically inside block elements-->
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Centered Text&reg;</title>
<style type="text/css">
@charset "UTF-8";
* {
 margin: 0;
 padding: 0;
}

body {
 font-family: Helvetica;
}

#wrapper {
 width: 100%;
 height: auto;
}

#wrapper > div {
 margin: 40px auto;
 overflow: hidden;
   position: relative;
   height: 100px;
   width: 50%;
}

p {
 position: absolute;
 word-wrap: break-word;
 text-align: center;
 color: white;
 background-color: rgba(0,0,0,0.5);
}

#parent1 {
  background-color: orange;
}

#parent1 p {
   top: 10px;
   bottom: 10px;
   left: 10px;
   right: 10px;
   height: auto;
   width: auto;
   padding-top: 30px; /* Parent1's height * 0.5 = parent1 p's padding-top (Adjust to make look more centered) */
}

#parent2 {
 background-color: skyblue;

}

#parent2 p {
 left: 50%;
 top: 50%;
 padding: 10px;
 transform: translate(-50%, -50%);
}

#parent3 {
 background-color: hotpink;
}

#parent3 p {
 top: 50%;
 left: 0;
 transform: translateY(-50%);
 width: 100%;
}
</style>
</head>
<body>
<div id="wrapper">
 <div id="parent1">
  <p>Center Method 1</p>
 </div>
 <div id="parent2">
  <p>Center Method 2</p>
 </div>
 <div id="parent3">
  <p>Center Method 3</p>
 </div>
</div>
</body>
</html>
I hope this helps!
1

I was recently delighted to find that Flexbox can handle this problem for you. The flex-center class in the CSS below will center your div's text, both vertically and horizontally. The example comes out a little smashed, so I recommend resizing the window until the div border isn't flush to the text.

As far as whether you can get away with using flexbox regarding compatibility, see Can I use...

I don't fully understand why this works, and if someone has more insight into the flex box machinery, I'd enjoy the explanation.

.border-boxed {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  /* This is just to make it look pretty */
  box-sizing: border-box;
  background: linear-gradient(135deg, 
    rgba(85,239,203,1) 0%,
    rgba(30,87,153,1) 0%,
    rgba(85,239,203,1) 0%,
    rgba(91,202,255,1) 100%);
  color: #f7f7f7;
  font-family: 'Lato', sans-serif;
  font-weight: 300;
  font-size: .8rem;
  
  /* Expand <body> to entire viewport height */
  height: 100vh;
  
  /* Arrange the boxes in a centered, vertical column */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}


.box {
  width: 25%;
  height: 25%;
  border: 2px solid #f7f7f7;
  border-radius: 16px;
  margin: .5rem; 
  text-transform: uppercase;
  text-align: center;
}

.small {
  height: 8%; 
}
<div class="box large flexitem flex-center">
  Large Box. <br>
  So big. <br>
  My god.
</div>

<div class="box small flexitem flex-center">
  Smaller Box
</div>
AManOfScience
  • 1,183
  • 9
  • 9
1

One method with your current setup is to set the margin-top to -25%

http://jsfiddle.net/ycAta/

the only reason why it looks offish is because the position is based off of the top of the text and there is a necessary gap because not all letters are the same height.

As A manual fix -30% looks better. :P

Joseph Marikle
  • 76,418
  • 17
  • 112
  • 129
  • Thanks but I'm not sure that explains why it doesn't work like the article I was working from. If I can't explain it, I can't say how likely it is to work in different browsers. And, in fact, when I load your link into IE9, I can't see the text at all. – Jonathan Wood Sep 30 '11 at 23:29
  • @JonathanWood correction: top:25% and not margin-top is better. But as for why the other methods don't work, I don't know. I'd have to look into that article more. – Joseph Marikle Sep 30 '11 at 23:38
  • @JonathanWood [This example](http://jsfiddle.net/hW46u/) roughly works (even in IE7 as far as I can tell [IE9 in IE7 mode]). Again it's limited but basically assumes a two line height content box and compensates by 5% for differing letter height. – Joseph Marikle Oct 01 '11 at 17:34
1

I was unable to determine the reason why the code in the article I referenced would not work for me. A couple of people offered answers but nothing that struck me as reliable across browsers.

Ultimately, I decided to keep my text on one line, which I do not like as much. But I do need my technique to be clear and well-understood, and for it to work reliably.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466