Placeing a css loader on the curtain then having it fade out

I want to place the loader centered on the curtain.

Next, I want the loader to fade out to opacity 0 after it is done.

Next, then the curtain goes up.

That should occur for those 3 videos.

Here is my video code:
https://jsfiddle.net/t0av79u8/

Here is the loader:
https://jsfiddle.net/gpuyaesn/3/

From here: https://css-loaders.com/progress/

The loader is in the css here: https://jsfiddle.net/amoLtq0c/

I don’t know where I am placing it in the html:
<div class="loader"></div>

<div class="outer-containerA">
  <div class="video-containerA">
    <button class="exitA" type="button" title="Exit" aria-label="Exit"></button>
    <div class="ratio-keeper">
      <div class="video playA"></div>
      <div class="curtain"></div>
    </div>
    <div class="playA"></div>
  </div>
  <div class="video-containerB hide">
    <button class="exitB" type="button" title="Exit" aria-label="Exit"></button>
    <div class="ratio-keeper">
      <div class="video playB"></div>
      <div class="curtain"></div>
    </div>
    <div class="playB"></div>
  </div>
  <div class="video-containerC hide">
    <button class="exitC" type="button" title="Exit" aria-label="Exit"></button>
    <div class="ratio-keeper">
      <div class="video playC"></div>
      <div class="curtain"></div>
    </div>
    <div class="playC"></div>
  </div>
</div>

css

.outer-containerA {
  background: #15202b;
}

.outer-containerA,
.outer-containerB,
.modal {
  display: flex;
  position: fixed;
  inset: 0;
  overflow: auto;
  /* Enable scroll if needed */
}

.video-containerA,
.video-containerB,
.video-containerC {
  flex: 1 0 0;
  margin: auto;
  max-width: 640px;
  position: relative;
}

.ratio-keeper {
  height: 0;
  padding-top: 56.25%;
  overflow: hidden;
  position: relative;
  background: #000;
}

.ratio-keeper iframe {
  /*position: absolute;
  top: 0;
  left: 0;*/
  width: 100%;
  height: 100%;
}

.ratio-keeper iframe,
.curtain {
  position: absolute;
  inset: 0;
}

.curtain {
  /*position: absolute;
  height: 100%;
  width: 100%;
  inset:0;*/
  --wide: 8.8%;
  --angle1: 0;
  --angle2: -90;
  background: repeating-linear-gradient(calc(var(--angle1) * 1deg),
      #ffffff00 0,
      #ffffff00 var(--wide),
      #ffffff1a calc(var(--wide) + 1px),
      #0000004d calc(var(--wide) + 2px),
      #ffffff00 calc(var(--wide) + 5px)),
    repeating-linear-gradient(calc(calc(var(--angle2) + 90) * 1deg),
      #ffffff00 0,
      #ffffff00 var(--wide),
      #ffffff1a calc(var(--wide) + 1px),
      #0000004d calc(var(--wide) + 2px),
      #ffffff00 calc(var(--wide) + 5px));
  background-color: #222;
  border-bottom: 2px solid #191919;
  background-repeat: no-repeat;
  overflow: hidden;
}

.video-containerA.slide .curtain {
  transition: 8s ease-in-out;
  transition-delay: 2.2s;
  transform: translateY(-100%);
}

@keyframes slide {
  to {
    transform: translateY(-100%);
  }
}

.video-containerB.slide .curtain,
.video-containerC.slide .curtain {
  animation: slide 8s ease-in-out forwards;
  animation-delay: 2.2s;
}

css loader:


.loader {
  width: 60px;
  aspect-ratio: 1;
  border-radius: 50%;
  -webkit-mask: linear-gradient(0deg, #000 55%, #0000 0) bottom/100% 18.18%;
  background:
    linear-gradient(#f03355 0 0) bottom/100% 0% no-repeat #ddd;
  animation: l8 3s steps(7);
}

@keyframes l8 {
 100% {
    background-size: 100% 115%;
  }
}

For the initial one you can change the css to this:

.loader {
  position:fixed;
  z-index:999;
  display:flex;
  inset: 0 0 0 0;
  width: 60px;
  margin:auto;
  aspect-ratio: 1;
  border-radius: 50%;
  -webkit-mask: linear-gradient(0deg, #000 55%, #0000 0) bottom/100% 18.18%;
  background:
    linear-gradient(#f03355 0 0) bottom/100% 0% no-repeat #ddd;
  animation: l8 3s steps(7) forwards;
  pointer-events:none;
}

@keyframes l8 {
 100% {
    background-size: 100% 115%;
    opacity:0;
  }
}

The html can stay where it was.

Of course that will run straight away which may be too quick if stuff is still loading.

The other ones would need to be triggered by the js in some way.

1 Like

You can leverage the slide class to trigger the animation but will need 3 keyframes.

Here’s the revised css:

.loader {
  position: fixed;
  z-index: 999;
  display: flex;
  inset: 0 0 0 0;
  width: 60px;
  margin: auto;
  aspect-ratio: 1;
  border-radius: 50%;
  -webkit-mask: linear-gradient(0deg, #000 55%, #0000 0) bottom/100% 18.18%;
  background:
    linear-gradient(#f03355 0 0) bottom/100% 0% no-repeat #ddd;
  animation: l8 3s steps(7) forwards;
  pointer-events: none;
}

@keyframes l8 {
  0% {
    opacity: 1;
  }

  100% {
    background-size: 100% 115%;
    opacity: 0;
  }
}

@keyframes l9 {
  0% {
    opacity: 1;
  }

  100% {
    background-size: 100% 115%;
    opacity: 0;
  }
}

@keyframes l10 {
  0% {
    opacity: 1;
  }

  100% {
    background-size: 100% 115%;
    opacity: 0;
  }
}

.loader:has(+ .outer-containerA .video-containerB.slide) {
  animation: l9 3s steps(7) forwards;
}

.loader:has(+ .outer-containerA .video-containerC.slide) {
  animation: l10 3s steps(7) forwards;
}
1 Like

I added a spinner instead.
This works fine it seems.

I didn’t need to add any js.

If I were to leverage the slide class, I would be adding slide in which would do what exactly in the code that it is not already doing?

https://jsfiddle.net/941ogwrs/3/

.spinner {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  inset: 0;
  margin: auto;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  cursor: pointer;
  border: 9px solid;
  background: transparent;
  filter: drop-shadow(3px 3px 3px #000000b3);
  pointer-events: none;
}

.spinner {
  animation: rotate 2s linear forwards, fadeOut 1s 2s forwards;
  border-color: red transparent red transparent;
}

@keyframes rotate {
  50% {
    transform: rotate(360deg);
    border-color: red transparent red transparent;
  }

  100% {
    transform: rotate(720deg);
    border-color: red transparent red transparent;
  }
}

@keyframes fadeOut {
  to {
    opacity: 0;
  }
}

Would the idea here be for the curtain to go up after the spinner is done?

This doesn’t seem to work: https://jsfiddle.net/L8gvmzy7/2/

.spinner:has(+ .outer-containerA .video-containerB.slide) {
  animation: rotate 2s linear forwards, fadeOut 1s 2s forwards;
  border-color: red transparent red transparent;
}

.spinner:has(+ .outer-containerA .video-containerC.slide) {
  animation: rotate 2s linear forwards, fadeOut 1s 2s forwards;
  border-color: red transparent red transparent;
}

@keyframes rotate {
  50% {
    transform: rotate(360deg);
    border-color: red transparent red transparent;
  }

  100% {
    transform: rotate(720deg);
    border-color: red transparent red transparent;
  }
}

@keyframes fadeOut {
  to {
    opacity: 0;
  }
}

How do I have the exit button fade in after the curtain is up?

https://jsfiddle.net/96fm3rhv/2/

window.onload = function() {
  const container = document.querySelector(".video-containerA");
  const spinner = document.querySelector(".spinner");

  spinner.addEventListener("animationend", function() {
    container.classList.add("slide");
  });

  const exitButton = document.querySelector(".exitA");
  container.addEventListener("animationend", function() {
    exitButton.classList.add("visible");
  });
};

You added three spinners where I used only one for all of them. You don’t need any extra js because the spinner is hidden by the parent which is display:none. When you reveal the parent as you already do the spinner within that section will just start automatically.

Of course not. You don’t have any of those elements as siblings of the spinner now that you moved the spinner inside each element.

For that css to work you would need this structure:

<div class="spinner"></div>
<div class="outer-containerA">
 <div class="video-containerB.slide">
    ..stuff ...
 </div>
</div>

How does addressing the spinner affect when the curtain goes up?

You need to delay the curtain going up until animation end on the spinner. the code for the curtain will have nothing to do with the spinner code.

I don’t see why you just don’t add an animation delay to the curtain in css that is the same duration as the spinner.

Someone said this:

In your showContainer function, you are trying to add the slide class to the container element when the animation of the spinner ends. However, the slide class is supposed to transition the container upwards, but it seems it’s not being applied correctly.

I still don’t know how to fix that in the code, but it is being applied correctly, what is wrong?

It should work the same way as:

How this one works:

window.onload = function() {
  const container = document.querySelector(".video-containerA");
  const spinner = document.querySelector(".spinner");
  const exitButton = document.querySelector(".exitA");

  spinner.addEventListener("animationend", function() {
    container.classList.add("slide");
  });

  container.addEventListener("transitionend", function() {
    exitButton.classList.add("visible");
  });
};

After clicking the exit button the curtain should go up.

After it is up, exit button should be visible

How do I fix this: https://jsfiddle.net/96fm3rhv/10/

I am confused here.

The curtain is not going up.

I don’t understand, it should be working.

function showContainer(containerSelector, spinnerSelector, exitSelector) {
    const container = document.querySelector(containerSelector);
    const exitButton = document.querySelector(exitSelector);

    container.classList.remove("hide");

    const spinner = document.querySelector(spinnerSelector);
    spinner.addEventListener("animationend", function() {
      container.classList.add("slide");
    });

    container.addEventListener("animationend", function() {
      exitButton.classList.add("visible");
    });
}

  function resetPage() {
    hideContainer(".video-containerA");
    showContainer(".video-containerB", ".spinner", ".exitB");
    removePlayer();
  }

That’s one spinner and you have three! I already mentioned this.

Which spinner are you waiting to finish spinning?

I think that this:

showContainer(".video-containerB", ".spinner", ".exitB");

Should be this:

showContainer(".video-containerB", ".video-containerB .spinner", ".exitB");

1 Like

After clicking the exit button.

The exit button should fade in after the curtain is up.

It’s not doing that: https://jsfiddle.net/fup36ga8/1/

  function showContainer(containerSelector, spinnerSelector, exitSelector) {
    const container = document.querySelector(containerSelector);
    const exitButton = document.querySelector(exitSelector);

    container.classList.remove("hide");

    const spinner = document.querySelector(spinnerSelector);
    spinner.addEventListener("animationend", function() {
      container.classList.add("slide");
    });

    container.addEventListener("animationend", function() {
      exitButton.classList.add("visible");
    });
  }

  function removePlayer() {
    videoPlayer.destroyPlayers();
  }

  function resetPage() {
    hideContainer(".video-containerA");
    showContainer(".video-containerB", ".video-containerB .spinner", ".exitB");
    removePlayer();
  }

I’m guessing because the spinner has finished animation you add the visible class. It doesn’t look like you are waiting for a specific animation but any animation of that container.

If you look in devtools you can see that the visible class is added at the exact time the spinner finishes animating. You should be looking for the animation end on the curtain before you fade in the button.

As I said before I don’t know why you are using JS for all these when you could chain them together in css. You know how long each thing is animated so you just set the appropriate delay before the next one. Then all you have to do is reveal the element and the chain of events happens.

I don’t think this is what you meant:

showContainer(".video-containerB", ".video-containerB .spinner", ".curtain .exitB");

Yes that’s exactly what I plugged into your code and it worked. Obviously you’ll have to do similar if you have multiple buttons. As mentioned before you are using multiple js routines to do exactly the same thing so you keep forgetting to follow through will all the changes.

You really should start from scratch each time you do a major rewrite rather than hacking together bits of code from routines built for some other cause.

Maybe you need to be more specific and check for the slide animation before revealing the button.


        if (event.animationName !== 'slide') {
         return;
       }

Here for example:


    container.addEventListener("animationend", function() {      
        if (event.animationName !== 'slide') {
         return;
       }
      exitButton.classList.add("visible");
    });
1 Like