3

To sum it up, there are few approaches to align content vertically in container. These are main approaches (if you now some completely different way to do it, it would be very generous of you to provide example - I will incorporate it here)

  1. using position and transform properties - http://jsfiddle.net/EjV4V/3/ This one is nice, but as to me, is a little bit overkill, especially if we consider rendering optimization issues. Will work in all modern browsers, won't work in IE7.
  2. using display: inline-block property with one additional auxiliary block - http://jsfiddle.net/mmxm4/3/. Because of using additional DOM element don't think this approach is good. Won't work in IE7. It worth to mention also (thanks @nclenorton for mentioning this), that we can use :before or :after generated content. But, once again - not in IE7.
  3. using display: table and display: table-cell properties - http://jsfiddle.net/Ppk3p/2/. Sometimes this approach is neat, sometimes not. Note that, contrary to other example provided there is a problem with child cell width. Any way, won't work in IE7.
  4. using display: box - http://jsfiddle.net/9Phgg/9/ - this is the most sexy way to handle things, but as all we know, spec is not 100% completed. Moreover, Opera does not support flex box. And yes, of course, don't even think about trying something like this in IE7.

    My question is: "Regarding the fact that all of abovementioned approaches will fail in IE7, what is the most general, elegant, simple and right way to center elements vertically in all modern browsers and IE7?".

    I have a strong feeling that, helas, though it is year 2012, using table layout is still the answer. I've seen some exotic approaches, using, for example position: absolute or even javascript expressions, but this is far from elegant and simple.

Seasoned html-developers, correct me if I'm wrong.

UPD: Actually, there is one more approach, but I find it radically wrong and unsuable for many reasons. But it worth to mention. Anything in button is centered vertically by default, so behold - http://jsfiddle.net/s5nz4/3/. This will work in IE7, but we are all adult people here, I hope, to understand that this is inappropriate )))

shabunc
  • 23,119
  • 19
  • 77
  • 102
  • If you want to support IE7 you can't have "Elegant and simple"; this is as simple as it gets: http://jsfiddle.net/EjV4V/4/ – Ivan Castellanos Jul 04 '12 at 16:09
  • @IvanCastellanos the pink box should be positon: absolute; on there, but that relies on knowing the exact width and height of an object. If you don't know the height of an element, you can grab it using a simple JS function, and then from there you could set the negative margin to offset the block. – Chad Jul 04 '12 at 16:14
  • @Ivan your solution doesn't works in chrome – Pedro L. Jul 04 '12 at 16:23
  • i forgot to save the "position" attributes; here is fixed http://jsfiddle.net/EjV4V/16/ – Ivan Castellanos Jul 04 '12 at 16:30
  • @IvanCastellanos, your solution depends on knowing block dimensions, so it is actually can be considered a contrived example of positioning. See thirdyot's answer, for example. – shabunc Jul 05 '12 at 05:23
  • This question is complete useless; you are asking for a way to do something in any other way than the normal way; supporting an old platform (IE7) that is prone to failure. – Ivan Castellanos Jul 05 '12 at 20:05
  • 1
    Comment to completely useless question most likely is even more useless )))) Actually, you are really, really wrong. Whether we like it or not, still millions (literally) use IE7. – shabunc Jul 05 '12 at 20:09

5 Answers5

3

If I need IE7 support, I tend to go for the "display: inline-block with an extra element" method. This does work in IE7 with a small change, here's an example.

If I don't need IE7 support, I usually use the display: table-cell method.

Sometimes, I can't use the display: table-cell method, typically when I need to use absolutely position something at the bottom of the element with display: table-cell. position: relative doesn't work on table cells, at least in Firefox. In those cases, I use the display: inline-block method, except that the "extra element" is inserted via :before, which keeps the HTML clean.

Community
  • 1
  • 1
thirtydot
  • 224,678
  • 48
  • 389
  • 349
  • My answer assumes that the height of the element you're trying to vertically center is unknown. If the height *is* known, there are simpler alternatives. – thirtydot Jul 04 '12 at 16:19
  • Missed that. This one is nice indeed. Need time to collect and analyze all the answers, but it looks like this is the yes answer yet. – shabunc Jul 04 '12 at 21:19
1

If you know the height of what you are centering you can use absolutely position the box 50% from the top and then use a negative margin half the height of the box to center it. It's annoyingly complex getting it to work it ie7 but it does work.

http://css-tricks.com/snippets/css/exactly-center-an-imagediv-horizontally-and-vertically/

Example:

.center {
    width: 300px;
    height: 300px;
    position: absolute;
    left: 50%;
    top: 50%; 
    margin-left: -150px;
    margin-top: -150px;
}
Jordan Shute
  • 169
  • 3
  • this is nice, but @thirtydot's fix is nicer - we don't need to now blocks height. – shabunc Jul 05 '12 at 05:35
  • @shabunk I've always disliked cluttering up my html with unnecessary elements. Just a preference thing. His solution is definately the way to go if you don't know the div height. – Jordan Shute Jul 05 '12 at 07:53
1

Not the best way to do it, but you could use two divs to force the pink box to always be centered, with one "pushing" the other:

http://jsfiddle.net/EjV4V/25/

This approach should work with IE7, though you would always have to use fixed margins.

Ana Ameer
  • 671
  • 11
  • 30
  • well, when we know all dimensions - and all dimensions are absolute - of course we can position element as we need. But this is not a vertical alignment, it's just that a positioning which happens to seem like centered alignment. The idea is not to now dimensions. – shabunc Jul 04 '12 at 21:23
1

While it won't work in IE7, using pseudo element instead of 'spreader' should work in all major browsers: http://jsfiddle.net/mmxm4/6/

As for the IE <= 7, adding.htc behavior that creates an element with the after class wouldn't really be a crime, I suppose. At least, no more than using PIE.

Here's the code (tested over several projects):

<PUBLIC:COMPONENT lightWeight="true">
<!-- saved from url=(0014)about:internet -->

    <PUBLIC:ATTACH EVENT="oncontentready" FOR="element" ONEVENT="append_after()" />
    <PUBLIC:ATTACH EVENT="ondocumentload" FOR="element" ONEVENT="append_after()" />

    <script type="text/javascript">
        function append_after() {
            if (!this.after) {
                var el = element,
                    doc = el.document,
                    aft_el = doc.createElement('div');

                this.after = "true";
                aft_el.setAttribute('class', 'after');
                this.appendChild(aft_el);
                aft_el.outerHTML = aft_el.outerHTML;

                this.runtimeStyle.behavior = "none";
            }
        }
    </script>

</PUBLIC:COMPONENT>

If you are using conditional classes, just add something like this:

.lte-ie7 .parent {
  behavior: url(/path/from/the/site/root/after.htc);
}

And then, for both inline-block elements, add display: inline; zoom: 1; to the styles. The more elegant solution, though, will be using the "Cross-browser inline-block" technique: define a global class for your inline blocks and use it wherever you need it:

.inline-block {
    display: -moz-inline-box;
    display: inline-block;
    vertical-align: top;
}

.lte-ie7 .inline-block {
    display: inline;
    zoom: 1;
}
unclenorton
  • 1,605
  • 11
  • 19
  • thank you for this answer. Upvoted for going into details, but this never can be the answer, because invoking javascript is hardly the easiest way ) – shabunc Jul 04 '12 at 21:22
0

The CSS3 solution to this is box-align

http://www.w3schools.com/cssref/tryit.asp?filename=trycss3_box-pack

But it isn't supported by some browsers so I would use some jQuery plugin like:

http://www.nealgrosskopf.com/tech/thread.php?pid=37

Pedro L.
  • 7,376
  • 3
  • 25
  • 27