3

I am not looking for a different solution to the question of centering elements; I am looking for an explanation why the solution presented here doesn’t work.

Consider the following jsFiddle:

Here’s the HTML/CSS code for reference:

HTML

<div class='outer'>
    <div class='middle'>
        <div class='inner'>
            Text should be centered
        </div>
    </div>
</div>

CSS

.outer {
    position: absolute;
    left: 200px;
    top: 50px;
    width: 100px;
    height: 100px;
    border: 2px solid #00f;
    border-radius: 10px;
}

.middle {
    position: absolute;
    left: 50%;
    top: 50%;
    line-height: 1em;
}

.inner {
    position: relative;
    left: -50%;
    top: -50%;
    width: 5em;
}

The element inspector in both Chrome and Firefox tell me that both middle and inner have the correct width and height, and indeed the horizontal positioning is working correctly, but for some reason the top: -50% rule is ignored. However, it is only ignored if .middle doesn’t have an explicit height — if you add one, it works, even if the effective height is the same as what it is already. Why is this?

Timwi
  • 65,159
  • 33
  • 165
  • 230
  • possible duplicate of [What's The Best Way of Centering a Div Vertically with CSS](http://stackoverflow.com/questions/396145/whats-the-best-way-of-centering-a-div-vertically-with-css) – poke Jun 22 '14 at 14:53
  • @poke: That’s not a duplicate. My question is not what the best way is, but why my solution isn’t working. – Timwi Jun 22 '14 at 15:02
  • I think this is a well-known problem when setting property of children relative to the ***height*** of the parent. The `height` should be explicitly set. It's not easy to answer why, it's just how CSS is designed. – King King Jun 22 '14 at 15:04
  • The inner div is centered vertically as if it were 3em tall like the middle div. – Roman Starkov Jun 22 '14 at 15:08
  • It's not centered, because in div.inner you calculate 50% from the height of the div.middle and not from the div.outer. – Denis V Jun 22 '14 at 15:10
  • @DenisV: Both element inspectors (Chrome and Firefox) show the same height for those two elements. – Timwi Jun 22 '14 at 15:12
  • @Timwi well, you've changed the link to jsfiddle, but still div.middle height is 32, div.outer is 80. – Denis V Jun 22 '14 at 15:17
  • @DenisV: Sorry, I misread. Yes, it *should* be the height of div.middle. But it doesn’t, it behaves like top:0. – Timwi Jun 22 '14 at 15:20

2 Answers2

2

This is the behavior as as specified in the old CSS 2 specification (emphasis mine):

<percentage>

The offset is a percentage of the containing block's width (for 'left' or 'right') or height (for 'top' and 'bottom'). For 'top' and 'bottom', if the height of the containing block is not specified explicitly (i.e., it depends on content height), the percentage value is interpreted like 'auto'.

In the current CSS 2.1 specification that restriction was removed, so I’d say it’s a cross-browser bug now. Firefox has a very old bug on this here that was marked as invalid because of the original spec; and there is a newer bug here could use some votes to get more attention.

poke
  • 369,085
  • 72
  • 557
  • 602
  • 1
    Yes, and it does not appear to be an accident - http://www.w3.org/TR/CSS21/changes.html#q54 – BoltClock Jun 22 '14 at 15:20
  • @BoltClock Thanks, I was looking for that change description and couldn’t find it! – poke Jun 22 '14 at 15:22
  • There is a "new" Firefox bug for this: [Relative positioning with percentages inside auto-height containing block does not work](https://bugzilla.mozilla.org/show_bug.cgi?id=260348). Filed 10 years ago. – Roman Starkov Jun 22 '14 at 15:30
  • @romkyns I added that link 9 minutes ago to my answer ^^ – poke Jun 22 '14 at 15:35
-1

For those coming after me try to add display:grid; on the parent of container

<div style="display: grid;">
    <div _ngcontent-serverapp-c11="">
        <video _ngcontent-serverapp-c11="" onloadedmetadata="this.muted=true" autoplay="" loop="" muted="" playsinline="" class="lazy vid-mobi"><source _ngcontent-serverapp-c11="" src="https://cdn3.blablabla.com/gtb/videos/intro_lg.mp4" type="video/mp4"> 
        </video>
    </div>
</div>

It works for me

Fractal Mind
  • 405
  • 4
  • 10