44

How do I align a <div> which contains an image (or flash) vertically with CSS. Height and width are dynamic.

Sparky
  • 98,165
  • 25
  • 199
  • 285
Oleg Tarasenko
  • 9,324
  • 18
  • 73
  • 102

9 Answers9

45

This is a pure CSS2 solution for horizontally and vertically centering without known sizes of either container nor child. No hacks are involved. I discovered it for this answer and I also demonstrated it in this answer.

The solution is based on vertical-align: middle in conjunction with line-height: 0, which parent has a fixed line-height.

The HTML:

<span id="center">
    <span id="wrap">
        <img src="http://lorempixum.com/300/250/abstract" alt="" />
    </span>
</span>

And the CSS:

html,
body {
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
    overflow: hidden;
}
#center {
    position: relative;
    display: block;
    top: 50%;
    margin-top: -1000px;
    height: 2000px;
    text-align: center;
    line-height: 2000px;
}    
#wrap {
    line-height: 0;
}
#wrap img {
    vertical-align: middle;
}

Tested on Win7 in IE8, IE9, Opera 11.51, Safari 5.0.5, FF 6.0, Chrome 13.0.

The only caveat is IE7, for which the two innermost elements have to declared at one line, as demonstrated in this fiddle:

<span id="center">
    <span id="wrap"><img src="http://lorempixum.com/300/250/abstract" alt="" /></span>
</span>

Note that the span's are also required for IE7. In every other browser, the span's may be div's.

Community
  • 1
  • 1
NGLN
  • 43,011
  • 8
  • 105
  • 200
  • Nicely done. This is exactly what many people are looking for, including myself. Definitely the cleanest workaround for people who need to support ie7 [sigh] I edited your fiddle to show another practical example . http://jsfiddle.net/ryanore/R7szX/2/ – Ryan Ore Sep 23 '12 at 14:14
  • wait how is this an answer.... so basically I get to vertically align, but I lose the ability to scroll my page (overflow: hidden on html,body) – Rey Mar 15 '13 at 14:58
  • @xckpd7 Of course it doesn't have to be the body; you can use this solution on any container element as [shown here](http://jsfiddle.net/NGLN/t8VUL/323/). – NGLN Mar 16 '13 at 08:47
  • 1
    Thanks! I made some alterations which (1) make textual content look okay (2) center the content in respect to an element besides the body (3) use classes instead of ids so it's reusable. http://jsfiddle.net/sparebytes/q9sfQ/ – sparebytes Apr 18 '13 at 20:03
  • http://jsfiddle.net/sparebytes/q9sfQ/1/ - Added an animation to show its behavior – sparebytes Apr 18 '13 at 20:10
  • Useless for aligning block elements as pop-ups. – Tomáš Zato Jan 21 '14 at 23:43
  • @NGLN why did you use `height` and `line-height` `2000px`? – Rupam Datta Sep 21 '15 at 08:31
  • 1
    @Rupam That's an arbitrary value. It would be the "maximum" height a device could display. – NGLN Sep 21 '15 at 20:12
12

You can do this by using inline-blocks, one with height: 100% (and same heights for HTML and BODY) and vertical-align: middle.

Example 1: http://jsfiddle.net/kizu/TQX9b/ (a lot of content, so it's full width)

Example 2: http://jsfiddle.net/kizu/TQX9b/2/ (an image with any size)

In this example I use spans, so It would work in IE without hacks, if you'd like to use divs, don't forget to add in Conditional Comments for IE .helper, .content { display: inline; zoom: 1; }, so inline-blocks would work for block elements.

kizu
  • 42,604
  • 4
  • 68
  • 95
  • Quite nice, but when the browser window narrows, the content moves to the "next line". Any idea how to solve that? – NGLN Sep 03 '11 at 13:20
  • Ah, yeah, since it's `inline-blocks`, you can use `white-space: nowrap` to prevent this: http://jsfiddle.net/kizu/TQX9b/3/ – kizu Sep 03 '11 at 15:53
  • Nice! You can also skip the `html` and `body` styles if you use another wrapper with `height: 100%;` and `position: absolute;` http://jsfiddle.net/TQX9b/256/ and `position: fixed;` http://jsfiddle.net/TQX9b/257/, which gives a bit more flexibility on working this into layouts. Tested in FF, IE7-10... – user56reinstatemonica8 Oct 18 '13 at 09:14
  • This might actually be the only way to get `vertical-align` working in a `position: absolute` element: all my other attempts using `table-cell` don't pick up the height. Best answer on the page I reckon! – user56reinstatemonica8 Oct 18 '13 at 09:22
  • One more note: you can use this with any `display:block` content in place of the image, and it also all works when nested inside responsive fixed-aspect-ratio elements. [Here's an example of both of these](http://stackoverflow.com/a/20196938/568458) that also demonstrates another possible approach to multiple-line wrapped text. Downside: the markup starts to get a bit complicated... – user56reinstatemonica8 Nov 25 '13 at 15:42
  • Buddy, you saved my day big time! :) This sounds like the best solution without all those crappy margin hacks.. Great job! – Andrey Popov May 22 '14 at 12:43
  • Hmmm... that helper div seems to be critical. Why is that? PS: This is amazing! So much easier than any other way of doing this. – Costa Michailidis Jul 16 '14 at 20:34
  • Ahhh... whitespace, damn you. I always forget about inline-block and whitespace. – Costa Michailidis Jul 16 '14 at 22:04
9

In addition to the other answers here, the CSS3 flexible box model will, amongst other things, allow you to achieve this.

You only need a single container element. Everything inside it will be laid out according to the flexible box model rules.

<div class="container">
    <img src="/logo.png"/>
</div>

The CSS is pretty simple, actually:

.container { 
    display: box;
    box-orient: horizontal;
    box-pack: center;
    box-align: center;
}

I've omitted vendor-prefixed rules for brevity.

Here's a demo in which the img is always in the centre of the page: http://jsfiddle.net/zn8bm/

Note that Flexbox is a fledgling specification, and is only currently implemented in Safari, Chrome and Firefox 4+.

Chris
  • 9,994
  • 3
  • 29
  • 31
4

I would recommend this solution by Bruno: http://www.brunildo.org/test/img_center.html

However, I ran into a problem w/ his solution w/r/t webkit. It appears that webkit was rendering a small space at the top of the div if the empty span was allowed to be there. So, for my solution I only add the empty span if I detect the browser to be IE (If someone figures out how to get rid of the space, let me know!) So, my solution ends up being:


HTML:

<div class="outerdiv">
    <img src="..." /> 
</div>

CSS:

.outerdiv {
    display: table-cell;
    width: 200px;
    height: 150px;
    text-align: center;
    vertical-align: middle;
}
.ie_vertical_align * {
    vertical-align: middle;
}
.ie_vertical_align span {
    display: inline-block;
    height: 150px;
    width: 0;
}

And if I detect the browser to be IE I add an empty span element before the img tag and a css style so it looks like:

<div class="outerdiv ie_vertical_align">
    <span></span>
    <img src="..." /> 
</div>

Here's a JSFiddle with this code.

rcl
  • 954
  • 10
  • 18
  • I am a bit confused. You're using width: 200px; height: 150px; where these numbers come from? What to do if I don't know the size of the image? – Oleg Tarasenko Aug 30 '11 at 13:04
  • Well, those numbers are just arbitrary bounds for the outer container. Looking at your site, the numbers would probably be the size of the window, i.e. width: 100%, height: 100%. – rcl Aug 30 '11 at 22:59
2

Dušan Janovský, Czech web developer, has published a cross-browser solution for this some time ago. Read http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

duri
  • 14,991
  • 3
  • 44
  • 49
  • This either requires IE hacks or multiple nested `div`s. Which all suck. – Madara's Ghost Aug 29 '11 at 16:05
  • +1 - @Rikudo Sennin, the article was written in 2004 and updated in 2008. I haven't tested it, but I think with IE8/9 those hacks are no longer necessary. – Richard JP Le Guen Aug 29 '11 at 16:49
  • Only IE7 and 6 are unfortunately not gone yet, and the OP hasn't stated whether he wanted those or not. – Madara's Ghost Aug 29 '11 at 16:50
  • 3
    @Rikudo Sennin The need of nested elements and some CSS hacks for older browsers is, more or less, expected limitation. No simpler code/markup can be used to meet all the OP's requirements. If support for IE6/IE7 is not necessary, the hacks can simply be omitted (just a reminder: it was *you* who said that the reasonable way should be cross-browser); with the use of conditional comments or so, your CSS can validate. Please think about whether your -1 are legitimate. It's not about that I'm interested in what reputation I have, but you can confuse OP by marking suitable answers as "not useful". – duri Aug 29 '11 at 17:34
1

If you don't care about IE7 and below, you don't have to use multiple nested divs. If you have a div that you want to align vertically, that div is within some container (even if the container is your <body>). Therefore, you can specify display: table-cell and vertical-align: middle on the container, and then your div will be vertically centered.

However, if you do care about IE7 and below, you will need an additional container to make it work (yes, via a hack).

Take a look at this fiddle. It displays correctly in IE6-9 and other major browsers. #container2 is present solely for IE7 and below, so if you don't care about them, you can remove it as well as the IE-specific conditional styles.

Artyom
  • 1,599
  • 12
  • 22
0

Set the image as background of the div and align it center

Ben
  • 13,297
  • 4
  • 47
  • 68
0

try the 50% padding trick:

<html>

<body style="width:50%; height: 50%;">
<div style="display:block; display:inline-block; layout-grid:line; 
     text-align:center; vertical-align:bottom; 
     padding: 50% 0 50% 0">test</div>
</body>

</html>
RetroCoder
  • 2,597
  • 10
  • 52
  • 81
-1

This is possible if you know the height of the image or flash object to be centered. You don't need to know the container's height/width, but you do need to know the contained height/width.

It's possible using float, clear and negative margins. Example: www.laurenackley.com homepage.

html

<div id='container'><!-- container can be BODY -->
  <div id='vertical-center'>&nbsp;</div>
  <div id='contained-with-known-height'>
    <p>stuff</p>
  </div>  
</div>

css

#vertical-center{
  height:50%;
  width:1px;
  float:left;
  margin-bottom:-50px;/** 1/2 of inner div's known height **/
}

#contained-with-known-height{
  height:100px;
  clear:left;
  margin:0 auto;/** horizontal center **/
  width:700px;
  text-align:left;
}
#container{/** or body **/
  text-align:center;
  /** width and height unknown **/
}

If you don't know the inner elements width/height. You are out of luck with <div>. BUT -- table cells (<td>) do support vertical-align:middle; If you can't get it done with the div stuff above, go with a table inside the container, and put the div you are centering inside a td with vertical-align middle.

tmsimont
  • 2,651
  • 2
  • 25
  • 36
  • Read the question. He doesn't want to align the contents within the div, he wants to align the div itself. – Madara's Ghost Aug 29 '11 at 16:00
  • i did read the question, the "div itself" in this example would be #contained-with-known-height -- assuming that the contents are of known height, and the container is the unknown. the question and comments do not clarify which is the unknown or if its both. which is why i addressed that underneath the example. read my answer. – tmsimont Aug 29 '11 at 16:05
  • 2
    but he stated he **doesn't know the width or the height** so that solution is practically useless. – Madara's Ghost Aug 29 '11 at 16:06
  • i'd disagree with that. tables serve a purpose, and you don't have to be a purist with divs. how about a table within a div layout?? sounds like that vertical align property might come in handy, no? – tmsimont Aug 29 '11 at 16:07
  • if he doesn't know the width or the height of the container, this solution is perfect. if he doesn't know the width or height of the contained, then he should use a table, or javascript. as stated above, the unknown was not clarified, even though kizu asked, there was no clarification given – tmsimont Aug 29 '11 at 16:08
  • 1
    tables are there for one thing, to present data that comes in a table, not to layout your code because it's easier. It's not semantic, and it might effect the page's performance and search engine ranking. – Madara's Ghost Aug 29 '11 at 16:16
  • considering he's looking for help on a flash page, i really doubt search engine ranking is relevant, and a single table with 1 cell is hardly going to "effect the page's performance" -- besides, table discussion is hardly relevant anyway, since judging by the example page he gave, he does seem to know the flash object's height/width at page load, and could therefore utilize the 1st CSS soultion i've offered. – tmsimont Aug 29 '11 at 16:25