Search code examples
csscss-positiontext-align

text-align: center on absolutely-positioned child behaves like left: 50%


If I have a position: absolute inline child inside a parent with text-align: center, the result is exactly as if I had written left: 50%, rather than actually centering the div.

Granted this is an unusual case since the two are not meant to be used together, and I'm not going to rely on them for production, but I'm trying to understand why this is the case.

CodePen

.centered,
.positioned {
  border: 1px solid blue;
  margin-bottom: 20px;
  height: 200px;
  position: relative;
}

.centered {
  text-align: center;
}

.centered .child,
.positioned .child {
  width: 100px;
  height: 100px;
  border: 1px solid red;
  position: absolute;
  display: inline-block;
}

.positioned .child {
  left: 50%;
  transform: translate(-50%, 0);
}
<div class="centered">
  <div class="child"></div>
</div>

<div class="positioned">
  <div class="child"></div>
</div>

When you use left: 50% you either need a negative margin-left equal to half the element's width, or you need a transform of -50%, because the dom is positioning the left edge at 50% of the parent, meaning the div is more right-aligned rather than centered.

What's odd is that text-align: center on the parent, and position: absolute on the child behave like this too. Is text-align: center not able to take into account the width of the child? Even if it's specifically set?


Solution

  • This is a known issue that appears to be deliberate, at least in Chrome:

    The breakage was caused by http://wkrev.com/126911 which fixed an earlier issue, and according to the commit (and commits/bugs it references) this is the intentional behavior, making this an error on the website itself.

    Talking to Robert Hogan, author of the patch, it's not entirely certain what should happen here, and I can't find where in CSS 2.1 this is defined. It boils down to whether absolutely positioned elements, which makes them block level per section 9.7 of CSS 2.1, should ever be laid out in a line. WebKit has quite some machinery for this, so the behavior definitely is deliberate.

    Furthermore, Firefox matches what Chromium does here, and shows the same result on http://m.csl-sofas.co.uk. I can test Opera and IE tonight. As we match other browsers I'd be inclined to say that the website should fix it, but I don't yet know where in the specification this is defined.

    While investigating this, John and I did find an interesting discrepancy in the computed style output, namely that while rendering of the block changed while flipping between display: block and inline-block, the computed style (rightfully) continued showing display: block, as is implied by position: absolute.

    Only IE behaves "as expected".

    I'm guessing that the reason this isn't defined in CSS is simply because CSS assumes that all absolutely positioned elements are blockified by the time their layout is determined since you can never have an absolutely positioned element inline — the computed value for display for any absolutely positioned element is always the block-level counterpart to its specified value.

    Since this behavior is interoperable across all browsers except IE (including Microsoft Edge), chances are that it will be special-cased in css-position (which currently makes the same assumptions as CSS2), css-text, css-display, or a combination thereof, instead of being corrected and potentially breaking any sites that have come to rely on it.