, ,

Centering an element that also has  position: absolute;  set in it is a headache. Chrome 20 beta will (buggy-shly?) obey text-align: center; on such elements but no other browsers will.

I was trying to make (a row of) tiles of product categories that have category image and category name; and they should be aligned in a sensible manner even if the image dimensions vary. In this case all images are automatically generated thumbnails (via GD) with maximum size 138px*138px, meaning images may be tall (138px*any) or wide (any*138px).

The obvious way to make this look good is to make a wrapping div for the image that always has 138px height, and position the image at its bottom.

A quick googling will give results that mention using this on the img element:

left: 50%
margin-left: -<half of image width>px;

That cannot apply here since the images are generated somewhere else. *

(* actually, the <img …>  is generated via an external function call that makes and stores thumbnails etc etc, and I would have to modify it to extract the width, and then use that on inline style on each <img…> element, but I already had the <img …> element! … bad idea, right? )


Anything with position: absolute; is a pain to center horizontally, as today proved to me; So an extra div is needed that will take care of the positioning at bottom, and it needs to be 100% width so that the image inside it can align itself in the center of that.


<td align="center" width="33%" valign="top">
  <div class="tile">
    <div class="bottom">
      <a href="...">
      <img src="...">
  <a href="...">Category Name</a>

and the CSS:

.tile {
  position: relative;
.tile .bottom {
  width: 100%;
  bottom: 0px;
  position: absolute;
.tile img {
  text-align: center;
  margin-left: auto;
  margin-right: auto;
/* your reset.css probably has something like this in it already: */
td {
  vertical-align: top;

You’ll also need another text-align: center; for the td itself
e.g. for a table with class=”tileTbl” on it:

 table.tileTbl td {text-align: center;}

That extra div.bottom took me all day to figure out! *groan*…