157

So I know we can center a div horizontally if we use margin:0 auto;. Should margin:auto auto; work how I think it should work? Centering it vertically as well?

Why doesn't vertical-align:middle; work either?

.black {
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    background:rgba(0,0,0,.5);
}
.message {
    background:yellow;
    width:200px;
    margin:auto auto;
    padding:10px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>

JSFiddle

TylerH
  • 20,799
  • 66
  • 75
  • 101
savinger
  • 6,544
  • 9
  • 40
  • 57
  • 2
    Highly suggest reading and implementing @zpr's answer below regarding Flexbox. It is quite well supported as of today and your css will be much, much cleaner. – Govind Rai Jan 01 '17 at 10:46
  • if((new Date()).getFullYear() > 2017) useFlexBox = true; – brandito Apr 05 '18 at 06:30

15 Answers15

203

Update Aug 2020

Although the below is still worth reading for the useful info, we have had Flexbox for some time now, so just use that, as per this answer.


You can't use:

vertical-align:middle because it's not applicable to block-level elements

margin-top:auto and margin-bottom:auto because their used values would compute as zero

margin-top:-50% because percentage-based margin values are calculated relative to the width of containing block

In fact, the nature of document flow and element height calculation algorithms make it impossible to use margins for centering an element vertically inside its parent. Whenever a vertical margin's value is changed, it will trigger a parent element height re-calculation (re-flow), which would in turn trigger a re-center of the original element... making it an infinite loop.

You can use:

A few workarounds like this which work for your scenario; the three elements have to be nested like so:

.container {
    display: table;
    height: 100%;
    position: absolute;
    overflow: hidden;
    width: 100%;
}
.helper {
    #position: absolute;
    #top: 50%;
    display: table-cell;
    vertical-align: middle;
}
.content {
    #position: relative;
    #top: -50%;
    margin: 0 auto;
    width: 200px;
    border: 1px solid orange;
}
<div class="container">
    <div class="helper">
        <div class="content">
            <p>stuff</p>
        </div>
    </div>
</div

JSFiddle works fine according to Browsershot.

rmcsharry
  • 5,363
  • 6
  • 65
  • 108
Oleg
  • 24,465
  • 8
  • 61
  • 91
  • Thanks! The top three notes are very helpful to know. Quick question... are the pound signs in your css simply comments? – savinger Sep 14 '12 at 16:32
  • 11
    `#` is a hack to have the rule prefixed with it only interpreted by IE7 and under. You may prefer to instead include these rules in an IE-specific stylesheet [by using conditional comments](http://www.quirksmode.org/css/condcom.html) etc. – Oleg Sep 15 '12 at 02:10
  • 3
    +1 for the citing the reasons why this is the case, the margin percentage calculation based on the width was very eye-opening. – ricosrealm Mar 09 '13 at 22:58
  • Excelent, just what I needed. Coming back to the good ol' table, but in css way. I was just trying to do the same with flex box, I did it, but it's support is so inestable that I had to come to another approach. – JorgeeFG Apr 17 '13 at 15:35
  • 2
    I doubt about the 'infinite loop' statement. – Barun Jun 11 '14 at 16:07
  • 1
    There is a newer and shorter [answer](http://stackoverflow.com/a/18106475/985454). – Qwerty Apr 09 '15 at 14:49
  • 157
    humanity has already been to the moon years ago and we still have to deal with this bullcrap. vertically aligning things in a browser, jesus – user151496 May 11 '15 at 09:44
  • FIX: `.content` need `display: table;` to center .. thanks.. its works – KingRider Oct 23 '15 at 13:36
  • @KingRider Don't use tables for layout. – TylerH Aug 11 '16 at 13:33
  • @TylerH problem my bootstrap a conflict. Well happen. – KingRider Aug 11 '16 at 15:40
  • 4
    In the >= IE9 age, `position: absolute; top: 50%; transform: translateY(-50%);` is also feasible and quite popular... (unlike `top:50%;margin: - $halfHeight` you don't have to know the height in advance...) – Frank N Apr 09 '17 at 10:15
  • If you're coming to this question post 2019 please look below for a better answer that addresses FlexBox as a way of doing this. – clayRay Jul 03 '20 at 06:08
165

Since this question was asked in 2012 and we have come a long way with browser support for flexboxes, I felt as though this answer was obligatory.

If the display of your parent container is flex, then yes, margin: auto auto (also known as margin: auto) will work to center it both horizontally and vertically, regardless if it is an inline or block element.

#parent {
    width: 50vw;
    height: 50vh;
    background-color: gray;
    display: flex;
}
#child {
    margin: auto auto;
}
<div id="parent">
    <div id="child">hello world</div>
</div>

Note that the width/height do not have to be specified absolutely, as in this example jfiddle which uses sizing relative to the viewport.

Although browser support for flexboxes is at an all-time high at time of posting, many browsers still do not support it or require vendor prefixes. Refer to http://caniuse.com/flexbox for updated browser support information.

Update

Since this answer received a bit of attention, I would also like to point out that you don't need to specify margin at all if you're using display: flex and would like to center all of the elements in the container:

#parent {
    width: 50vw;
    height: 50vh;
    background-color: gray;
    display: flex;
    align-items: center; /* vertical */
    justify-content: center; /* horizontal */
}
<div id="parent">
    <div>hello world</div>
</div>
Roman
  • 33
  • 5
zpr
  • 2,886
  • 1
  • 18
  • 21
68

Here's the best solution I've found: http://jsfiddle.net/yWnZ2/446/ Works in Chrome, Firefox, Safari, IE8-11 & Edge.

If you have a declared height (height: 1em, height: 50%, etc.) or it's an element where the browser knows the height (img, svg, or canvas for example), then all you need for vertical centering is this:

.message {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
    margin: auto;
}

You'll usually want to specify a width or max-width so the content doesn't stretch the whole length of the screen/container.

If you're using this for a modal that you want always centered in the viewport overlapping other content, use position: fixed; for both elements instead of position: absolute. http://jsfiddle.net/yWnZ2/445/

Here's a more complete writeup: http://codepen.io/shshaw/pen/gEiDt

shshaw
  • 3,123
  • 2
  • 23
  • 33
  • 3
    This doesn't center it in its parent element necessarily. Nice hack if you just want it in the center of the page though. – Joel Mellon Jan 24 '14 at 00:38
  • 3
    Just add `position: relative` to the parent, and the element will be centered within the parent. I did a much larger writeup on Smashing Magazine about the technique if you'd like to read more: http://coding.smashingmagazine.com/2013/08/09/absolute-horizontal-vertical-centering-css/ – shshaw Jan 24 '14 at 14:27
  • Sometimes absolute is based on a parent or two up (vs the body) and relative could be a grand or great grandparent (vs the parent). Maybe those who know when or why that occurs could control this technique better - I've never really looked into those issues but I do know that switching from absolute to relative is not in itself a solution to make this work. I read a little bit of your article and it looks like absolute and relative go up to the first absolute or relative ancestor, is that correct? – Joel Mellon Jan 24 '14 at 19:29
  • I'm a little slow. I just re-read your comment above. I didn't notice you said to add it to the `parent` - got it. Thanks so much! – Joel Mellon Jan 24 '14 at 19:44
  • Yup, that's it! `position: absolute` elements are always positioned based on the closest `position: relative` parent. – shshaw Jan 24 '14 at 22:50
  • Definitely the best way. – APAD1 Aug 05 '14 at 22:00
  • Can someone tell us about the caveats for ie8/9, or link to a document describing them ? – commonpike Mar 18 '16 at 12:43
  • 1
    @commonpike The only issue with IE8/9 is if you use `display: table` for variable height content. Otherwise, this method should work as expected. Read through the [writeup](http://codepen.io/shshaw/pen/gEiDt) for more details overall. You should also be able to test the [full view](http://codepen.io/shshaw/full/gEiDt/) in IE8/9 to see if there are any issues. – shshaw Mar 18 '16 at 16:24
  • 2017. The approach doesn't work in IE10+ (no vertical or horizontal alignment) or Firefox 52 (only horizontal alignment), IE9 emulation does not support jsfiddle, so could not test earlier versions if IE. Works in Chrome 57 (both vertical and horizontal). – Victor Zakharov Apr 18 '17 at 14:17
  • @Neolisk This method works solidly back to IE8/9 as long as you declare a height ( `height: 50%`, `height: 100px`, `height: 0; padding-top: 50%` ) or a height is automatically known by the browser ( `img`, `svg` and `canvas` elements, etc.). The `display: table` hack doesn't work well cross-browser, but supplying a height should work without trouble. Check out the full writeup for more information: http://codepen.io/shshaw/pen/gEiDt – shshaw Apr 18 '17 at 14:26
  • @shshaw: Yes, your latest example works in all browsers it seems, but it's rather complicated. The jsfiddle in the answer has issues, could you please update that so it works in all browsers? Please keep it as simple as possible. One empty div filled with solid color is enough to demo. – Victor Zakharov Apr 18 '17 at 14:45
  • @Neolisk The original Fiddle was based off the original asker's exact needs. The only necessary pieces for centering is `position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto;` and a `height`. I've updated the FIddle to be a little more straightforward: http://jsfiddle.net/yWnZ2/445/ – shshaw Apr 18 '17 at 15:13
26

Edit: it's 2020, I would use flex box instead.

Original answer:

Html

<body>
  <div class="centered">
  </div>
</body>

CSS

.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
Gal Margalit
  • 5,525
  • 6
  • 52
  • 56
10

I know the question is from 2012, but I found the easiest way ever, and I wanted to share.

HTML:

<div id="parent">
     <div id="child">Content here</div>
</div>

and CSS:

#parent{
     height: 100%;
     display: table;
}    
#child {
     display: table-cell;
     vertical-align: middle; 
}
Paula Fleck
  • 835
  • 11
  • 21
8

If you know the height of the div you want to center, you can position it absolutely within its parent and then set the top value to 50%. That will put the top of the child div 50% of the way down its parent, i.e. too low. Pull it back up by setting its margin-top to half its height. So now you have the vertical midpoint of the child div sitting at the vertical midpoint of the parent - vertically centered!

Example:

.black {
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    background:rgba(0,0,0,.5);
}
.message {
    background:yellow;
    width:200px;
    margin:auto auto;
    padding:10px;
    position: absolute;
    top: 50%;
    margin-top: -25px;
    height: 50px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>

http://jsfiddle.net/yWnZ2/2/

TylerH
  • 20,799
  • 66
  • 75
  • 101
tuff
  • 4,895
  • 6
  • 26
  • 43
  • 1
    `margin-top` cannot be set in % relative to the element height, so you'll end up with a dimensions dependant fix – Oleg Sep 14 '12 at 02:03
  • 1
    Which is...exactly what I said in my answer? "If you know the height of the div you want to center". And I did not say that OP should use % in `margin-top`. – tuff Sep 14 '12 at 03:38
  • I disagree with the solution as it locks you into a pre-defined element height - but your comment makes sense. You may want to reflect that in the answer – Oleg Sep 14 '12 at 06:25
  • 3
    OK, I've bolded the part that you overlooked, hopefully that's clearer now. – tuff Sep 14 '12 at 14:18
  • 1
    @o.v.: If the element doesn't have a fixed height, you can just use JS to get the computed height and then set the negative top margin accordingly. This is still the best method for vertically centering, in my opinion. – daGUY Sep 14 '12 at 16:52
  • +1 - we already have a div we're using as a bounding box for an `img`, which has a set height – Izkata Jun 04 '13 at 14:51
4

Those two solution require only two nested elements.
First - Relative and absolute positioning if the content is static (manual center).

.black {
    position:relative;
    min-height:500px;
    background:rgba(0,0,0,.5);

}
.message {
    position:absolute;
    margin: 0 auto;
    width: 180px;
    top: 45%; bottom:45%;  left: 0%; right: 0%;
}

https://jsfiddle.net/GlupiJas/5mv3j171/

or for fluid design - for exact content center use below example instead:

.message {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

https://jsfiddle.net/GlupiJas/w3jnjuv0/

You need 'min-height' set in case the content will exceed 50% of window height. You can also manipulate this height with media query for mobile and tablet devices . But only if You play with responsive design.

I guess You could go further and use simple JavaScript/JQuery script to manipulate the min-height or fixed height if there is a need for some reason.

Second - if content is fluid u can also use table and table-cell css properties with vertical alignment and text-align centered:

/*in a wrapper*/  
display:table;   

and

/*in the element inside the wrapper*/
display:table-cell;
vertical-align: middle;
text-align: center;

Works and scale perfectly, often used as responsive web design solution with grid layouts and media query that manipulate the width of the object.

.black {
    display:table;
    height:500px;
    width:100%;
    background:rgba(0,0,0,.5);

}
.message {
    display:table-cell;
    vertical-align: middle;
    text-align: center;
}

https://jsfiddle.net/GlupiJas/4daf2v36/

I prefer table solution for exact content centering, but in some cases relative absolute positioning will do better job especially if we don't want to keep exact proportion of content alignment.

Antoine
  • 800
  • 3
  • 14
  • 29
DevWL
  • 17,345
  • 6
  • 90
  • 86
3

.black {
    display:flex;
    flex-direction: column;
    height: 200px;
    background:grey
}
.message {
    background:yellow;
    width:200px;
    padding:10px;
    margin: auto auto;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>
Seetpal singh
  • 3,505
  • 1
  • 15
  • 12
  • Could you please share with us, how this solution is about? Plus, I see your "popup message" on bottom not centered – Alex Sep 21 '17 at 07:05
  • I did miss something, but now it's refined to keep the div in middle vertically. you can check now. – Seetpal singh Sep 25 '17 at 10:52
1

There isn't one easy way to center div vertically which would do the trick in every situation.

However, there are lots of ways to do it depending on the situation.

Here are few of them:

  • Set top and bottom padding of the parent element for example padding:20px 0px 20px 0px
  • Use table, table cell centers its' content vertically
  • Set parent element's position relative and the div's you want to vertically center to absolute and style it as top:50px; bottom:50px; for example

You may also google for "css vertical centering"

hasu
  • 29
  • 1
1

Using Flexbox:

HTML:

<div class="container">
  <img src="http://lorempixel.com/400/200" />
</div>

CSS:

.container {
  height: 500px;
  display: flex;
  justify-content: center; /* horizontal center */
  align-items: center;     /* vertical center */
}

View result

LW001
  • 2,452
  • 6
  • 27
  • 36
DanielBlazquez
  • 1,045
  • 1
  • 13
  • 22
1

variable height ,margin top and bottom auto

.black {background:rgba(0,0,0,.5);
width: 300px;
height: 100px;
display: -webkit-flex; /* Safari */
display: flex;}
.message{
background:tomato;
margin:auto;
padding:5%;
width:auto;
}
<div class="black">
<div class="message">
    This is a popup message.
</div>

variable height ,margin top and bottom auto

user3668456
  • 141
  • 1
  • 9
1

I think you can fix that with Flexbox

.black {
  height : 200px;
  width : 200px;
  background-color : teal;
  border: 5px solid rgb(0, 53, 53);
  /* This is the important part */
  display : flex;
  justify-content: center;
  align-items: center;
}

.message {
  background-color :  rgb(119, 128, 0);
  border: 5px solid rgb(0, 53, 53);
  height : 50%;
  width : 50%;
  padding : 5px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>
David Buck
  • 3,752
  • 35
  • 31
  • 35
1

.black {
    position:absolute;
    /*
        Replace with a one line inset property.
    top:0;
    bottom:0;
    left:0;
    right:0;
    */
    inset: 0;
    background:rgba(0,0,0,.5);
    /*
        Since no one has mentioned it yet,
        here it is the grid display and
        the place-content property.
    */
    display:grid;
    place-content: center;
}
.message {
    background:yellow;
    width:200px;
    /*
        There's no point here.
    margin:auto auto;
    */
    padding:10px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>
0
<div style="display:flex">
  <img src="" style="display:block !important; margin:auto">
</div>

To center an image in a div horizontally and vertically

Venkatesh A
  • 1,875
  • 1
  • 19
  • 23
-1
.black {
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    background:rgba(0,0,0,.5);
}
.message {
    position: absolute;
    top:50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background:yellow;
    width:200px;
    padding:10px;
}

 - 


----------


<div class="black">
<div class="message">
    This is a popup message.
</div>