Jez
Jez

Reputation: 29993

Vertical alignment with CSS

Yeah, yeah, I know this is yet another question about vertical alignment with CSS and it's been done a million times before. Rest assured that I have come across this problem many times and I've already done the reading about various ways to centre vertically with CSS. I'm asking here because none of those ways do quite what I want to do, and I just want to make sure that my suspicion (that CSS vertical alignment is broken and will not do what I want it to do) is definitely correct.

First up, here's my test case: http://www.game-point.net/misc/testAlign/

Here's the criteria:

This seems to be impossible even in CSS3, let alone CSS2. The annoying thing is that I'm almost there; the position:absolute; top:-50%; DIV works to set the top of that DIV to halfway down the container DIV. The problem is that the inner DIV, with style position:relative; top:-50%; doesn't do anything to move the content up by half its height, to centre it fully, because CSS says that an absolutely positioned DIV doesn't have a height and therefore top:-50% is meaningless. As far as I can tell, this is just a fundamental flaw in CSS for no particular reason. An absolutely positioned element does have a height, and I don't know why CSS pretends it doesn't. I just wanted to ask whether anyone had any ideas as to how I could achieve the desired effect, pictured at the bottom, given the criteria I outlined above. Ironically IE6/7/8's 'broken' box model, in quirks mode, gives me this very effect. Shame they're 'fixing' it in IE9 so it won't anymore.

Upvotes: 9

Views: 2536

Answers (5)

Jez
Jez

Reputation: 29993

OK, my suspicion was indeed correct and this is not possible (I think it's a flaw in CSS and they should provide a means of vertical alignment within a DIV without specifying inner element heights).

The least bad solution I ended up with was this: specify the height of the 'middle' DIV - that is, the DIV which is displayed using position:absolute and contains the real content. I've added it to the test case page at http://www.game-point.net/misc/testAlign/ under the heading With line-height:100% and hardcoded 'middle' DIV height. This solution means that you must know the height of the content to be vertically centred in advance, which sucks because the browser calculates this and you shouldn't need to specify it, but it's the only way (until CSS gets its act together). I used ems to specify the height too, so that zooming text in and out doesn't ruin the vertical centring. Turns out that for the 2 lines of 'Centred text' I had, this height equates to exactly 2 ems (at least on my machine). If I were to change that content's height, or it were to change dynamically to say 3 lines or 1 line, the parent div's hardcoded em height would also have to change.

So, here's the code I finally ended up with if anyone's interested:

    <div style="border:1px solid black; padding-left:60px; width:250px; position:relative; word-wrap:break-word;">
        TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest
        <!-- Unfortunately, must set this DIV's height explicitly or the contained DIV's relative positioning won't work, as this DIV is considered to have NO implicit height -->
        <div style="position:absolute; display:block; top:50%; left:0px; height:2em;">
            <div style="position:relative; top:-50%; background-color:#00aa00; line-height:100%;">
                Centred text<br/>
                Centred text
            </div>
        </div>
    </div>

Upvotes: 5

Ruskin
Ruskin

Reputation: 6171

I have started to get somewhere with the following code ... though needs work.

Based on items found on http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

Note, your code runs in quirks mode, I have changed this to html 5

<!DOCTYPE HTML>
<html>
<head>
    <title>Vertical align test</title>
</head>

<style type="text/css">


#outer { overflow: hidden; position: relative; border: 1px solid red; }
#outer[id] {display: table; position: static;}

#middle {position: absolute; top: 50%;} /* for explorer only*/
#middle[id] {position: relative; display: table-cell; vertical-align: middle; width: 100%;}

#inner {position: relative; top: -50%; width: 100px} /* for explorer only */
/* optional: #inner[id] {position: static;} */

</style>

<body>
<h1>New test</h1>

<div id="outer">
  <div id="middle">
    <div id="inner">
      any text<br>
      any height<br>
      any content, for example generated from DB<br>
      everything is vertically centered
    </div>

  </div>

test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test 
</div>


</body>
</html>

Upvotes: 0

plebksig
plebksig

Reputation: 535

The thing is though that vertical handling of content is made that way for obvious reasons, which I'm sure you're already aware of. But you're sort of trying to solve an unsolvable problem, that's not really a problem. (makes sense when you know why things are like they are)

By using absolute position you are just taking content out of the natural flow. It's much better to make everything like it should be with floats and proper sizes or whatever is needed so it degrades nicely and appears ok looking in all devices. Then write two lines of code in jquery to check heights and align everything (which will also work on "all" devices). The 2-3% without JS will need to live with boring sites.

Upvotes: 2

ilyast
ilyast

Reputation: 21

Use margin-top: instead of top: like margin-top: -25%;

Upvotes: 2

jcubic
jcubic

Reputation: 66490

.item {
    height: 40px;
    top: 50%;
    margin-top: -20px;
}

position relative or absolute;

Upvotes: -3

Related Questions