How to fadeout the play svgs

Currently, the play svg buttons don’t fadeout when clicking on them.
They only fade in.

I’m trying to create an example of the play svg’s fading out.

I did this all wrong,

How would it be written? https://jsfiddle.net/dy01nprb/

To do this, is display: block; needed?

.thePlay {
  animation: fadeInButtons 2s ease 0s forwards;
}

@keyframes fadeInButtons {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}

.fadingOut .thePlay {
  animation: fadeOutButtons 8s forwards;
  visibility: visible;
  opacity: 1;
}

@keyframes fadeOutButtons {
  99% {
    opacity: 1;
  }

  100% {
    opacity: 0;
  }
}

When the svg is clicked you immediately set it to display:none so there is nothing that you can fade. At the same time as you click the svg you start fading in the new background.

Therefore it seems you would have to delay the new background from fading in while you fade the svg page out. The svg could not be display:none as that is not amitable.

That is not a simple task as there is a lot going on in that code right now. You will need to hide the svg using the visibility method, or move them off screen or clip them to zero after the animation has finished. Then you need to delay the new background from fading in too soon.

My brain hurts just thinking about it :slight_smile:

2 Likes

Thank you for all that information.

Adding a delay here in the code does not work for some reason.

https://jsfiddle.net/z5mu4y8k/

body.bg1 {
  animation: fadeInBody 5s ease 0s forwards;
  animation-delay: 8s;
}

I tried doing this: https://jsfiddle.net/n4L2ty0w/

.inner-container {
  /*display: none;*/
  visibility: hidden;
}

.container.active .thePlay {
  /*display: none;*/
  visibility: hidden;
}

.container.active .inner-container.curtain {
  /*display: block;*/
  visibility: visible;
}

.hide {
  /*display: none;*/
  visibility: hidden;
}

That’s because the opacity:0 doesn’t get activated for 8 seconds so you see the new background. You would need to set the opacity to zero straight away.

e.g.


body.bg1 {
  animation: fadeInBody 5s ease 0s forwards;
  animation-delay: 8s;
  opacity:0;
}

@keyframes fadeInBody {

  100% {
    opacity: 1;
  }
}

You’d need to delay the new background from being shown while you fade out the play svg (which you won’t be able to use display:none to hide.).

I’m travelling for the next couple of days so can’t offer code but I suggest that you just write down on a bit of paper and work out what happens at each stage. If you can write it down then you can start to see where you can change it to do what you want.

There are so many fade ins and outs that unless you have a clear idea of what is happening and when you click something :slight_smile:

2 Likes

Maybe I shouldn’t be placing the fade-in animation to the .thePlay class as that, I believe means adding an animation to each of the 9 svgs separately, which I don’t know is a good idea.

Probably not good, right?

What would your opinion be on this?

I added a red background behind the play svgs to demonstrate the space/area of .outer.

.thePlay https://jsfiddle.net/xpdky1v9/

https://jsitor.com/Top_w2m6D

.thePlay {
  width: 90px;
  height: 90px;
  border-radius: 50%;
  cursor: pointer;
  border: none;
  fill: blue;
  background: transparent;
  padding: 0;
  filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
  animation: fadeInButtons 2s ease 0s forwards;
}

The only other 2 options would be placing the animation on either body or .outer, which would reduce the number of animations from 9 down to 1.

Unless if there might be a another way to do this, I am not sure.

body https://jsfiddle.net/jhmxzkut/

https://jsitor.com/TE6h-AAa5

body {
  background: #353198;
  animation: fadeInButtons 2s ease 0s forwards;
}

.outer https://jsfiddle.net/xojf3tku/

https://jsitor.com/Z5eL9nmQ8

.outer {
  display: flex;
  flex-wrap: wrap;
  min-height: 100%;
  width: 290px;
  box-sizing: border-box;
  justify-content: center;
  align-content: center;
  margin: auto;
  gap: 10px;
  background: red;
  animation: fadeInButtons 2s ease 0s forwards;
}

If you can avoid it then all the better.

Fading the body out would be easier as you just fade the one element. Then once faded out hide the play svg so they take up no space and then you’d need to fade the body in again with the new background.

Remember the playsvg are in the same containers as each of the videos. That’s why they were display none or one of them would show with the video etc.

It may be that you can do it all in one animation but the change of background image gradient half way through the animation could be problematic.

It’s worth experimenting and see what can be achieved more simply. I can’t offer any code as I am at the airport waiting for a plane:). I’ll be back online tomorrow evening.

1 Like

A delay is added here, what comes next?

https://jsfiddle.net/hdmfb6an/

body.bg1 {
  animation: fadeInBody 5s ease 0s forwards;
  animation-delay: 1s;
  opacity: 0;
}

@keyframes fadeInBody {
  100% {
    opacity: 1;
  }
}

If body is being used for the fade-in animation, what class would the fade-out animation be placed on? https://jsfiddle.net/hdmfb6an/

animation: fadeOutButtons;

@keyframes fadeOutButtons

I think the problem is that the body is fading out the old background but then you want it to fade in the new background. If it were two separate elements it would be easier perhaps to control but I believe the structure you have now was the only one that satisfied all your other requirements.

I’ll have another look and refresh my memory with the structure again:)

1 Like

The fade animation for the play svgs can be applied to:

body {} , .outer {} , or .thePlay {}

Which was demonstrated at post #5

animation: fadeInButtons;
@keyframes fadeInButtons;

animation: fadeOutButtons;
@keyframes fadeOutButtons;

I have been looking at this for the last hour or so and can’t see an easy solution.

The problem is as follows:

When you click the play button the JS adds a class to the body and to the outer but also adds the hide class to all the other containers and instantly removes all the play buttons.

Therefore what really needs to happen is that when you click the play button nothing at all needs to happen until the body animation has faded and then you let the js do what it was doing before and hide and show everything else.

This is similar to what you have done on returning using animationEnd to decide when to remove the class.

I think the approach you need using this structure is when the play button is clicked you add a new class to the body which simply fades out the whole body which will fade the background and the play buttons because they have not been hidden. If you detect for the end of that specific animation you can then remove that new class from the body and add proceed to add the current body and isOpen and hide classes etc…

I did have some success with using CSS only and trying to hide the elements without display:none but it required a number of extra animations and soon got so messy it was just spaghetti.

The simplest answer is to add a new class to the body on click and fade out the page as it stands… Then remove that class and carry on with what you had already. After all its only this first screen you want to fade and it seems silly to complicate everything else just to accommodate this.

If your intentions were known from the start then it would have made sense not to mix the play buttons in with the html for everything else but have them all in a separate container. Of course that is not as semantic as the code at present but would have been easier to manage from a css perspective but maybe more complicated from js as you would have to directly link the buttons to the content they refer to rather than finding them from their context.

1 Like

What do you mean my intentions?

Clicking on the play svgs and having them fade out.

That is all I was trying to have happen in the code.

Then, I need to do this:

The simplest answer is to add a new class to the body on click and fade out the page as it stands… Then remove that class and carry on with what you had already.

Thank you for explaining that all to me.

I mean when you decided to create the page it would have helped to know that there would be fade in animations between screens and in that way the page could have been constructed with that in mind to keep things simple.

If you want to fade one thing in and one thing out then you can’t just switch one off and one on which is basically how this was set up originally.

Yes that would be the simplest method but does mean its mostly a js solution but I believe you already have some sort of animation checking in place which you may be able to re-use.

e.g.
Use CSS like this:

body.initial-fade{
  animation:initial-fade 3s ease forwards;
}
@keyframes initial-fade{
to{opacity:0;}  
}

Then in the JS set up the class addition:

  function coverClickHandler(evt) {
   
   document.body.classList.add('initial-fade');
 // this is where you need to check for animation end of the initial fade and return if not finished   
 return;// needs to be checked

// if we haven't returned we carry on as normal.
    hideAll(config.containers);
    resetPage();
    markAsPlayed(evt.currentTarget);
    const cover = evt.currentTarget;
    showCovers(cover);
  }

The return should be in a function that checks for animation end of that new fade and if not completed then return. Once completed the page will continue as normal.

1 Like

I messed up somewhere:

My attempt: https://jsfiddle.net/6w2Ljbep/

I have no idea how you were able to get it to work.

I’m confused on how to get it to work.

Are you sure you’ve linked to the correct JSFiddle? That one doesn’t seem to have either the CSS or JavaScript additions which Paul suggested.

I improvised a little because I wasn’t able to figure it out.

It wasn’t working for me.

I got stuck here: https://jsfiddle.net/z4swhtnj/

I tried to improvise here: https://jsfiddle.net/6w2Ljbep/

It was only to show the fading out. You still had code to write :slight_smile:

Add the return here and you can see it fades out nicely.

  function coverClickHandler(evt) {

    document.body.classList.add('initial-fade');
    // this is where you need to check for animation end of the initial fade and return if not finished   
   return;

Now your task is to link to your animation end routine or create a new one if the one you have isn’t accessible from here.

e.g. where the return is you would test for the animationend and check if the classname is initial-fade.

You have something similar for resetfade()


 if (animationName === "initial-fade") {
     document.body.classList.remove('initial-fade');
      carryOn(evt);//
    }

That’s just pseudo code you have to write the function properly.


  function coverClickHandler(evt) {  
   document.body.classList.add('initial-fade');
   animationEndHandler(evt) ;  
 }
  
  function carryOn(evt) {
    hideAll(config.containers);
    resetPage();
    markAsPlayed(evt.currentTarget);
    const cover = evt.currentTarget;
    showCovers(cover);
  }

The above is not a woking example as you have to write it properly. You already have done similar so I assume you could follow the original pattern if you can’t use the original.

1 Like

I had attempted that at this link: https://jsfiddle.net/zx75wj4y/

The buttons fade out, then nothing happens after that.

  function animationEndHandler(evt) {

    const animationName = evt.animationName;

    if (animationName === "initial-fade") {
      fadeReset(evt);
    }
  }

  function fadeReset(evt) {
    body.classList.remove("fadeOutButtons");
    hideAll(config.containers);
    markAsPlayed(evt.currentTarget);
    const cover = evt.currentTarget;
    showCovers(cover);
    return;
  }

  function resetPage() {
    body.classList.add("fadeOutButtons");
  }

  function coverClickHandler() {
    resetPage();
  }

  function init(selectors) {
    config.containers = document.querySelectorAll(selectors.container);
    const playButtons = document.querySelectorAll(selectors.playButton);
    addClickToButtons(playButtons);
    body.addEventListener("animationend", animationEndHandler);
  }

That doesn’t look right there are active classes being added to the html element now.

I think you’ll need the help of the JS forum as I can’t follow the logic in the js anymore. :slight_smile:

I believe you will need a new animationend handler as I don’t think you can access the original (at least I don’t know hw to do it).

My logic would have been like this but it runs into the same issue as yours and is upsetting the active class which gets added to the html element.

/*jslint devel: true */

const manageCover = (function makeManageCover() {
  const config = {};
    const body = document.body;

  function show(el) {
    el.classList.remove("hide");
  }

  function hide(el) {
    el.classList.add("hide");
  }

  function hideAll(elements) {
    elements.forEach(hide);
  }

  function resetBackground(backgroundSelector) {
    const allBackgrounds = document.querySelectorAll(backgroundSelector);

    function hideBackground(background) {
      background.classList.add("bg1");
    }
    allBackgrounds.forEach(hideBackground);
  }

  function resetButtons(buttonSelector) {
    const allButtons = document.querySelectorAll(buttonSelector);

    function hideButton(button) {
      button.classList.add("isOpen");
    }
    allButtons.forEach(hideButton);
  }

  function resetPage() {
    resetBackground("body");
    resetButtons(".outer");

  }

  function markAsPlayed(played) {
    played.classList.add("played");
  }

  function showCovers(playButton) {
    const cover = playButton.parentElement;
    console.log(playButton)
    cover.classList.add("active");
    show(cover);
  }

  function coverClickHandler(evt) {
    body.classList.add('initial-fade');
  }

  function swapBackgrounds(evt) {
    body.classList.remove("initial-fade")
    hideAll(config.containers);
    resetPage();
    markAsPlayed(evt.currentTarget);
    const cover = evt.currentTarget;
    showCovers(cover);
  }


  function animationEndHandler2(evt) {

    const animationName = evt.animationName;

    if (animationName === "initial-fade") {
      swapBackgrounds(evt);
    }
  }

  function addClickToButtons(playButtons) {
    playButtons.forEach(function playButtonHandler(playButton) {
      playButton.addEventListener("click", coverClickHandler);
    });
  }

  function addCoverHandler(coverSelector, handler) {
    const cover = document.querySelector(coverSelector);
    cover.addEventListener("click", handler);
  }

  function init(selectors) {
    config.containers = document.querySelectorAll(selectors.container);
    const playButtons = document.querySelectorAll(selectors.playButton);
    addClickToButtons(playButtons);
    body.addEventListener("animationend", animationEndHandler2);
  }

  return {
    addCoverHandler,
    init
  };
}());

If the active class was added where it was originally I believe this would work but theres obviously something gravely wrong with that code :slight_smile:

1 Like