1

In the following code, "Example A" does not animate, while "Example B" does.

The only difference is that A used to not be displayed, and B used to be hidden.

document.getElementById('set').onclick = function() {
  document.getElementById('a').classList.add('clicked');
  document.getElementById('b').classList.add('clicked');
};

document.getElementById('reset').onclick = function() {
  document.getElementById('a').classList.remove('clicked');
  document.getElementById('b').classList.remove('clicked');
};
.example {
  background: blue;
  transition: opacity 2000ms ease;
}

.example.clicked {
  opacity: 0;
}

.example:not(.clicked) {
  opacity: 1;
}

#a:not(.clicked) {
  display: none;
}

#b:not(.clicked) {
  visibility: hidden;
}
<button id="set">Show and fade out</button>
<button id="reset">Reset</button>

<div id="a" class="example">Example A</div>
<div id="b" class="example">Example B</div>

Why the two different behaviors? Why doesn't opacity always animate?

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • Interestingly, if I'm inspecting the `#a` element in Chome's browser console, the transition works. But only while it's selected in the element inspector. – showdev Jun 07 '19 at 07:48
  • These seem relevant: [Transitions on the display: property](https://stackoverflow.com/questions/3331353/transitions-on-the-display-property) and [CSS transition works only if Chrome Dev Tools open](https://stackoverflow.com/questions/50265094/css-transition-works-only-if-chrome-dev-tools-open). It seems that transitions won't work on elements where the `display` property is changed: "... if the display: property changes at all, then ALL of your transitions will not work... " But I'd still like to know more about *why*. – showdev Jun 07 '19 at 08:04
  • It seems that a reflow must be triggered. The classes are changed "prior to the browser adding the div to the DOM render tree" -- [Triggering reflow for CSS3 transitions](https://semisignal.com/triggering-reflow-for-css3-transitions/). Here's a [demonstration](https://jsfiddle.net/1wqgkv9o/). [This answer](https://stackoverflow.com/a/27114874/924299) is informative. Also [this one](https://stackoverflow.com/a/49270029/924299). – showdev Jun 07 '19 at 08:27

2 Answers2

0

Use height: 0 and height: auto instead of display: none.

Check this answer out: Transitions on the display: property

EDIT: display: none and display: block apply instantly, so I don't think the transition is able to work. Using setTimeout, it can work though.

document.getElementById('set').onclick = function() {
  document.getElementById('a').style.display = "block";
  document.getElementById('a').style.opacity = 0;

  setTimeout(()=>{
    document.getElementById('a').style.opacity = 1;
  }, 0);
};

document.getElementById('reset').onclick = function() {
  document.getElementById('a').style.opacity = 0;
  setTimeout(()=>{
    document.getElementById('a').style.display = "none";
  }, 2000);
};
.example {
  background: blue;
  transition: opacity 2000ms ease;
  overflow: hidden;
  display: none;
}

.example.clicked {
  opacity: 1;
}

.example:not(.clicked) {
  opacity: 0;
}

#b:not(.clicked) {
  height: 0;
}
<button id="set">Show and fade out</button>
<button id="reset">Reset</button>

<div id="a" class="example">Example A</div>
<div id="b" class="example">Example B</div>
Gaurav Punjabi
  • 153
  • 1
  • 6
-1

You should change the display: none on #a:not(.clicked) to visibility: hidden and then it works.

display: none means that the tag wont appear. While visibility: hidden means that there is space allocated for the tag. It's rendered but just not visible.

document.getElementById('set').onclick = function() {
  document.getElementById('a').classList.add('clicked');
  document.getElementById('b').classList.add('clicked');
};

document.getElementById('reset').onclick = function() {
  document.getElementById('a').classList.remove('clicked');
  document.getElementById('b').classList.remove('clicked');
};
.example {
  background: blue;
  transition: opacity 2000ms ease;
}

.example.clicked {
  opacity: 0;
}

.example:not(.clicked) {
  opacity: 1;
}

#b:not(.clicked), #a:not(.clicked) {
  visibility: hidden;
}
<button id="set">Show and fade out</button>
<button id="reset">Reset</button>

<div id="a" class="example">Example A</div>
<div id="b" class="example">Example B</div>
JensW
  • 442
  • 2
  • 12
  • 1
    Right, but as soon as the button is clicked, the .clicked class is added and the display:none is removed, just like the visibility:hidden is removed. – Paul Draper Jun 07 '19 at 07:36
  • https://stackoverflow.com/questions/133051/what-is-the-difference-between-visibilityhidden-and-displaynone this might clear things up – JensW Jun 07 '19 at 07:38