1

There are div elements with child p elements that repeatedly go from hidden to shown states. Both display and opacity attributes are used for this. The opacity attribute has a 1 second transition time.

The cycle is as follows:

  1. Change display: none to display: initial
  2. Wait 50 milliseconds for document reflow (which should happen on its own)
  3. Change opacity: 0 to opacity: 1
  4. Wait 2 seconds
  5. Change opacity: 1 to opacity: 0
  6. Wait 1 second for transition to finish
  7. Change display: initial to display: none
  8. Wait 1 second
  9. Repeat

This works perfectly fine in FireFox, but in Google Chrome it only works in certain cases, demonstrated in the code snippet.

  • In the simple case it doesn't work.
  • If the child p is set to inline-block it works.
  • If the inline-block element is a grandchild instead of a child it doesn't work.
  • If the position of the child is set to fixed it works.

The curious thing is that the transition in step 5 also fails, which has nothing to do with the display attribute, so this does not seem to be due to reflow failures.

var flag = true;
var elements;

window.onload = init;

function init() {
    elements = document.getElementsByClassName("foo");
    cycleQuotes();
    setInterval(cycleQuotes, 2000);
}

function cycleQuotes() {
    if(flag) {
        for(var i = 0; i < elements.length; i++) {
            elements[i].style.display = "initial";
        }
        setTimeout(function() {
            for(var i = 0; i < elements.length; i++) {
                elements[i].style.opacity = 1;
            }
        },50);
    } else {
        for(var i = 0; i < elements.length; i++) {
            elements[i].style.opacity = 0;
        }
        setTimeout(function() {
            for(var i = 0; i < elements.length; i++) {
                elements[i].style.display = "none";
            }
        },1000);
    }
    flag = !flag;
}
.foo {
    display: none;
    opacity: 0;
    transition: opacity 1s;
}

.inline-block {
    display: inline-block;
}

#fixed {
    position: fixed;
    left: 100px;
    top: 0px;
}
<div class="foo">
  <p>normal</p>
</div>

<div class="foo">
  <p class="inline-block">inline-block</p>
</div>

<div class="foo">
  <div>
    <p class="inline-block">inline-block but grandchild</p>
  </div>
</div>

<div class="foo">
  <p id="fixed">fixed</p>
</div>
RaminS
  • 2,208
  • 4
  • 22
  • 30

2 Answers2

1

I was able to isolate the issue outside of the animation. For some reason I don't understand, Google Chrome doesn't propagate opacity to children of an element with display: initial.

div {
  background: red;
  display: initial;
  opacity: 0;
}
<div>
  text inside div
  <p>text inside paragraph</p>
</div>

On Firefox you see nothing, on Chrome you see text inside paragraph and nothing else. Very odd.

RaminS
  • 2,208
  • 4
  • 22
  • 30
Domino
  • 6,314
  • 1
  • 32
  • 58
  • 1
    ...unless the child is `inline-block` or has a `position: fixed` (and probably some other cases too). Nice find in either case; this is probably a big piece of the puzzle. – RaminS Feb 14 '19 at 00:19
  • @Gendarme Another fix is to put the opacity and the display styles on different wrappers. That seems to work too. – Domino Feb 14 '19 at 00:52
0

@jacquegoupil discovered that this is caused by the combination of display: initial and the opacity attribute.

Further research brought me to this answer which states that initial does not mean "default", meaning that it does not set the value of the attribute to the one that is default for the element. What it does it to set the attribute to the value that it defined as "initial" in the spec. In the case of the display attribute, initial means inline.

According to MDN, inline elements cannot contain block elements, and since p elements have display: block by default.

RaminS
  • 2,208
  • 4
  • 22
  • 30
  • 1
    The HTML in the question is not invalid. MDN's description there is based on an archaic definition of "inline" and "block" that blurs the line between HTML and CSS. While it is not possible for a block box to be contained within an inline box, 1) [CSS contains provisions for that sort of situation](https://stackoverflow.com/questions/22290281/what-goes-wrong-when-a-displayinline-custom-element-contains-displayblock-elem/24000067#24000067) 2) it doesn't change the nature of the HTML elements and therefore does not affect the validity of the HTML. – BoltClock Feb 14 '19 at 02:52
  • So it is a bug in Google Chrome, then? @BoltClock – RaminS Feb 14 '19 at 02:56
  • I suppose [this](https://stackoverflow.com/questions/23642290/ie-offsetting-and-ignoring-height-width-of-anchor-focus-outlines/23644188#23644188) sort of answers the question. – RaminS Feb 14 '19 at 02:58
  • 1
    [Looks like it.](https://bugs.chromium.org/p/chromium/issues/detail?id=764011) This used to affect Firefox as well [once upon a time](https://bugzilla.mozilla.org/show_bug.cgi?id=660682), additional discussion [here](https://bugzilla.mozilla.org/show_bug.cgi?id=1399527). Not sure if the underlying cause in Chrome is related for both cases. – BoltClock Feb 14 '19 at 03:03