Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!doctype html>
<head>
  <style>
    button {
      margin: 0.5rem;
    }
    .opacity-0 {
      opacity: 0;
    }
    .opacity-100 {
      opacity: 1;
    }
    .container {
      font-family: monospace;
      border: 1px solid black;
      padding: 0.25rem 0.75rem;
      margin: 0.5rem;
      transition: opacity linear 1s;
    }
  </style>
</head>
<body>
  <div id="wrapper">
    <button>Toggle</button>
    <div id="c1" class="container">getComputedStyle: Never,&nbsp; Disconnect from DOM: No</div>
    <div id="c2" class="container" data-compute-before>
      getComputedStyle: Before, Disconnect from DOM: No
    </div>
    <div id="c3" class="container" data-compute-after>
      getComputedStyle: After,&nbsp; Disconnect from DOM: No
    </div>
    <div id="c4" class="container" data-disconnect>
      getComputedStyle: Never,&nbsp; Disconnect from DOM: Yes
    </div>
    <div id="c5" class="container" data-compute-before data-disconnect>
      getComputedStyle: Before, Disconnect from DOM: Yes (this is the broken one)
    </div>
    <div id="c6" class="container" data-compute-after data-disconnect>
      getComputedStyle: After,&nbsp; Disconnect from DOM: Yes
    </div>
    <div id="c7" class="container">
      getComputedStyle: Never,&nbsp; Disconnect from DOM: No; read from subtree
      <span data-subtree></span>
    </div>
    <div id="c8" class="container" data-compute-before>
      getComputedStyle: Before, Disconnect from DOM: No; read from subtree
      <span data-subtree></span>
    </div>
    <div id="c9" class="container" data-compute-after>
      getComputedStyle: After,&nbsp; Disconnect from DOM: No; read from subtree
      <span data-subtree></span>
    </div>
    <div id="c10" class="container" data-disconnect>
      getComputedStyle: Never,&nbsp; Disconnect from DOM: Yes; read from subtree
      <span data-subtree></span>
    </div>
    <div id="c11" class="container" data-compute-before data-disconnect>
      getComputedStyle: Before, Disconnect from DOM: Yes; read from subtree (this is the broken one)
      <span data-subtree></span>
    </div>
    <div id="c12" class="container" data-compute-after data-disconnect>
      getComputedStyle: After,&nbsp; Disconnect from DOM: Yes; read from subtree
      <span data-subtree></span>
    </div>
  </div>
  <script>
    let wrapper = document.querySelector("#wrapper");
    let containers = Array.from(document.querySelectorAll(".container"));
    let show = true;
    let compute = false;
    let disconnect = false;
    function play(el) {
      let from = show ? "opacity-0" : "opacity-100";
      let to = show ? "opacity-100" : "opacity-0";
      // 1. Add element to DOM (if needed)
      wrapper.append(el);
      // 2.a Read a computed property value _before_ adding the class
      // This one is the broken case
      if ("computeBefore" in el.dataset) {
        let subtree = el.querySelector("[data-subtree]");
        window.getComputedStyle(subtree ? subtree : el).getPropertyValue("z-index");
      }
      // 3. Add a class representing the current state of the element
      // e.g. if we're showing the element then it starts out hidden (opacity-0)
      // otherwise it starts out visible (opacity-100)
      el.classList.add(from);
      // Normally an element has 0 animations at this point
      // However, if we read a computed property value _before_ adding the class
      // the element will have 1 animation
      console.log("Element %s has %d animation(s)", el.id, el.getAnimations().length);
      // 2.b Read a computed property value _after_ adding the class
      // This one is totally fine
      if ("computeAfter" in el.dataset) {
        window.getComputedStyle(el).getPropertyValue("z-index");
      }
      requestAnimationFrame(() => {
        // 4. Change the class list to trigger the transition
        el.classList.remove(from);
        el.classList.add(to);
        // Normally an element has 1 animation at this point
        // However, if we read a computed property value _before_ adding the class
        // the element will have 0 animations
        console.log("Element %s has %d animation(s)", el.id, el.getAnimations().length);
        el.addEventListener(
          "transitionend",
          () => {
            if (!("disconnect" in el.dataset)) return;
            // Reset the element's state
            el.classList.remove(to);
            // Remove element from DOM (if needed)
            show || el.remove();
          },
          { once: true },
        );
      });
    }
    // Log when animations are done or cancelled for debugging purposes
    containers.forEach((el) => {
      el.addEventListener("transitionrun", () => console.log(el, "transitionrun"));
      el.addEventListener("transitionstart", () => console.log(el, "transitionstart"));
      el.addEventListener("transitionend", () => console.log(el, "transitionend"));
      el.addEventListener("transitioncancel", () => console.log(el, "transitioncancel"));
    });
    // Start animation(s)
    document.querySelector("button").addEventListener("click", () => {
      show = !show;
      containers.forEach(play);
    });
  </script>
</body>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers