Forum How do I...?

Anyone figured out the vertical centering problem?

David J Prokopetz
Heya, folks.

Quick question: has anyone had figured out how to vertically centre an inline element of arbitrary dimensions within an absolutely positioned containing block element? I couldn't manage it with 5.x, but I'm hoping (perhaps optimistically) that 6.0 might offer a viable solution.

I've already tried the old browser-based trick of setting the containing block's display type to "table-cell" and using "vertical-align: middle", but Prince doesn't react to that the same way a web browser does.

(Just as a point of clarification, the inline element is of unpredictable length, and may contain linebreaks, so setting fixed padding values or what-have-you is probably out.)

Thanks,

-David Prokopetz.
tarquinwj
Indeed, I have only been able to confirm this problem, not come up with a solution. Normally, I would expect this to work:

Make sure that any ancestors use 100% height, and make an ancestor with display:table that is also set to 100% (height and width). Then the inner element can use display:table-cell, and vertical align should work. The reason you need to use the display:table is because otherwise it will only generate an anonymous table, which will shrink to fit, and not assume 100% height.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>...</title>
<style type="text/css">
html, body, div { height: 100%; width: 100%; margin: 0; padding: 0; }
body > div { display: table; }
div div { display: table-cell; vertical-align: middle; text-align: center; }
</style>
<body>
<div>
<div>
test
</div>
</div>
</body>
</html>


This does not work in Prince. I suspect this is a bug. Basically, it seems that elements with display:table will ignore percentage height.

Same in this alternative - the table is too short:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>...</title>
<style type="text/css">
html, body { height: 100%; width: 100%; border: 1px solid red; }
body > div { position: absolute; top: 0; bottom: 0; left: 0; right: 0; border: 1px solid blue; }
body > div > div { display: table; height: 100%; width: 100%; border: 1px solid green; }
body > div > div > div { display: table-cell; vertical-align: middle; text-align: center; border: 1px solid orange; }
</style>
<body>
<div>
<div>
<div>
test
</div>
</div>
</div>
</body>
</html>
David J Prokopetz
Thanks, tarquinwj - with help from your comments, I think I've found a solution. First, to illustrate the problem in more detail, consider the following XML:

<PARENT>
  <BLOCK>
    For dark is the suede that moves like a harvest.
  </BLOCK>
</PARENT>

... and this CSS:

BLOCK
{
  display: table-cell;
  position: relative;
  
  height: 200pt;
  width: 75pt;
  vertical-align: middle;
  
  padding: 5pt;
  
  border: solid black 1pt;
}


This produces the expected result - the text is vertically centred within the containing block. However, change "position: relative" to "position: absolute" (while leaving the rest of the CSS unchanged), and the vertical centring no longer works - the text ends up right at the top of the containing block.

I'm not sure if this is how it's supposed to work or not - I'm not sufficiently familiar with the CSS2 spec to say. However, the following should suffice to work around it:

<PARENT>
  <ABSBLOCK>
    <RELBLOCK>
      For dark is the suede that moves like a harvest.
    </RELBLOCK>
  </ABSBLOCK>
</PARENT>


ABSBLOCK
{
  display: block;
  position: absolute;
  
  height: 300pt;
  width: 75pt;
  
  padding: 5pt;
  
  border: solid red 1pt;
}

RELBLOCK
{
  display: table-cell;
  position: relative;
  
  height: 300pt;
  width: 75pt;

  vertical-align: middle;
  
  border: solid black 1pt;
}

That is, by placing a relatively positioned block of identical dimensions immediately within the absolutely positioned block, the usual vertical centring trick ("display: table-cell; vertical-align: middle;") operates as expected.

It's a bit of a pain that you have to specify the same dimensions twice - as tarquinwj correctly notes, percentile heights don't seem to work in this situation - but it's otherwise functional.
tarquinwj
However, change "position: relative" to "position: absolute" (while leaving the rest of the CSS unchanged), and the vertical centring no longer works - the text ends up right at the top of the containing block.


http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo

That is to be expected, since setting position:absolute on a table-cell will implicitly convert it to display:block, so the vertical-align will not be applied.

In any case, if you are using fixed dimensions (which you can use if you know the size of your paper), no need for all the positioning schemes. This is enough:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>vertical centring</title>
<style type="text/css">
div {
height: 300pt; 
width: 75pt; 
vertical-align: middle;
display: table-cell;
background: lime;
}
</style>
</head>
<body>
 <div>
  foo
 </div>
</body>
</html>


I reported the percentage table height bug here:
http://www.princexml.com/bb/viewtopic.php?p=2165
David J Prokopetz
tarquinwj wrote:
In any case, if you are using fixed dimensions (which you can use if you know the size of your paper), no need for all the positioning schemes.

Oh, there's still a need - using fixed dimensions doesn't necessarily imply that you want the block to appear within the normal document flow, after all. Note that I specified an absolutely positioned containing block in the topic post; I didn't do so just for kicks. ;)

As for the intended behaviour, that's kind of irritating, but I suppose it's only to be expected; as I understand it, CSS2 makes no provision whatever for vertical positioning within block elements, with the behaviour of vertical-align with respect to table-cells being a kludge to preserve presentational compatibility with existing HTML documents. I guess it's a bit silly to expect straightforward behaviour in this scenario. :)