8

I'm currently redesigning my website from a table layout to CSS. I'm having some problems with what seemed like a very simple task.

The site is simple. A box in the middle of the screen that contains several links.

The old site used <td valign="center"> to center all the links in the box. CSS seems to have no equivalent. I've been centering elements using negative margins like so:

div {
    height: 200px;
    position: absolute;
    top: 50%;
    margin-top: -100px;
}

This works fine when you know exactly how big the element you're centering is, but I need to be able to center the links without knowing how much vertical size the links take up. I just want the aligning in the box to act like text-align: center. Only vertically too.

Current website designed with tables
Current progress on the CSS version

j08691
  • 204,283
  • 31
  • 260
  • 272
user1730358
  • 103
  • 4

2 Answers2

6

You have 4, possibly 5 solutions one added to the bottom since it's a combination of different css from your original and js to set height:

  • Use a table cell and center it's content vertically
  • Use display: table-cell; vertical-align: middle; as css for your div
  • Update margin-top every time the div's height changes via javascript
  • Use css3 flexbox (you need to use vendor-specific extensions so it won't work on some older browsers)

Simple example using old-style flexbox - chrome version - add a wrapper div and set it's styling to this:

#wrapper { display: -webkit-box; -webkit-box-align: center; }
#wrapper > div { margin: auto; }

fiddle for this http://jsfiddle.net/gK7YU/

New style flexbox - also chrome version, you'll have to add the other vendor prefixes as well as the version without any prefixes in the final product.

#wrapper { display: -webkit-flex; }
#wrapper > div { margin: auto; }

fiddle for this: http://jsfiddle.net/LeHRD/

The fiddles contain a few more css properties so you can see what is happening easily.

Oh, sorry, you don't need the wrapper div, you can just center vertically any content with flexbox... well, anyway the solution I proposed can be combined with display: table-cell; so it works in older browsers as well.

You can also use absolute positioning with specified height jsfiddle.net/N28AU/1

#wrapper { possition:relative }
#wrapper > div { position:absolute;top:0;right:0;bottom:0;left:0;margin: auto;}

you can calculate height from the contained elements and update it via js if you want to avoid negative margins.

xception
  • 4,241
  • 1
  • 17
  • 27
  • You can also use `display: table-cell` on the div: http://stackoverflow.com/a/9561360/557612 – steveax Oct 09 '12 at 02:27
  • True, with your permission I'd like to add that to my answer as well. So whoever sees this doesn't have to also read the coments for a compelete list. – xception Oct 09 '12 at 02:32
  • I had no idea about the flexbox. Very interesting. I'd rather not use experimental features. Thanks though! – user1730358 Oct 09 '12 at 02:44
  • @user1730358 you can combine them, you know... use the display: table-cell; for browsers who don't know about the other stuff, and than declare the rest for modern browsers, sure, your css will be a bit bigger in the end... but I always like looking towards the future, css rules will be ignored when a browser doesn't recognize their values so only the last one recognized will be used. – xception Oct 09 '12 at 02:48
  • You could add this: Set `#wrapper` `possition:relative`, and `#wrapper > div { position:absolute;top:0;right:0;bottom:0;left:0;margin: auto;}` http://jsfiddle.net/N28AU/1/ – MiniGod Oct 09 '12 at 02:53
  • Very nice one :) didn't know about this solution so far - thanks for posting it! – xception Oct 09 '12 at 02:59
  • @MiniGod I included it separately since he wanted a solution that would work with height: auto; but it's still better than the negative margin version in my opinion. – xception Oct 09 '12 at 03:05
4

I've been to your website and copied the html here.

You can do this:

<style>
#box{
    display: table;
}
#box > div {
    display: table-cell;
    vertical-align: middle;
}
</style>

<!-- Your html part -->
<div id="box">
    <div>
        <a href="#">Link A</a>
        <a href="#">Link B</a>
        <a href="#">Link C</a>
        <a href="#">Link D</a>
    </div>
</div>

You must wrapped a div element inside #box because display: table-cell property won't work properly if you don't have a wrapper element that is set to display: table.

Your example here: jsfiddle

VKen
  • 4,964
  • 4
  • 31
  • 43
  • This is exactly what I'm looking for. Shame you have to use another div, but it works. Thank you! – user1730358 Oct 09 '12 at 02:45
  • @user1730358 You're most welcomed. Yeah, it's a shame. As web devs, we've worked with browsers quirks ever since the old IE vs Netscape days. This is just one of many, sigh... But if you want it to be semantic, there's another way using `
      ` and `
    • ` but you still have to wrap them with a `
      `.
    – VKen Oct 09 '12 at 02:48