Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide element after fade out using only CSS

I have a one pager that shows one page at a time and that uses animation when transitioning from one page to the next. It works like this:

  1. The user clicks on a button
  2. An ajax call is done and while waiting for the response the page fades out (opacity: 0)
  3. If the server does not respond within 500 msec after the fade out finishes a spinner fades in and stays there until the ajax call finishes
  4. When receiving the response the spinner is faded out and the new page fades in.

I currently use a CSS 3 transition animation on the opacity of the page. This issue is however that during the time the spinner is visible the user can still interact with the (invisible) form of the page that just faded out (it's not gone, it's just invisible using opacity).

So I would like to have a CSS only solution that sets the page to visibility: hidden at the end of the transition (I cannot use display: none). What would be the way to go here?

like image 486
Koen Peters Avatar asked May 05 '15 23:05

Koen Peters


2 Answers

Based on the answer of @Rev I created a proof of concept. It works nicely (see fiddle).

When you add the class 'fadeOut' to the div it'll fade out and end with a visibility: hidden state. Remove the class and it fades in again. You can tell that it is really hidden by hovering your mouse over it: if hidden it will no longer give the "text selection" mouse pointer.

HTML

<div class="page">
    Lorem ipsum etc etc etc. 
</div>

CSS

  .page {
      -moz-animation-name: fadeIn;
      -webkit-animation-name: fadeIn;
      -ms-animation-name: fadeIn;
      animation-name: fadeIn;
      -moz-animation-duration: 1s;
      -webkit-animation-duration: 1s;
      -ms-animation-duration: 1s;
      animation-duration: 1s;
      -moz-animation-timing-function: ease-in-out;
      -webkit-animation-timing-function: ease-in-out;
      -ms-animation-timing-function: ease-in-out;
      animation-timing-function: ease-in-out;
      -moz-animation-fill-mode: forwards;
      -webkit-animation-fill-mode: forwards;
      -ms-animation-fill-mode: forwards;
      animation-fill-mode: forwards;  
    }

    .page.fadeOut {
      -moz-animation-name: fadeOut;
      -webkit-animation-name: fadeOut;
      -ms-animation-name: fadeOut;
      animation-name: fadeOut;
    }

    @-moz-keyframes fadeIn { 0% { opacity: 0; visibility: hidden; } 100% { opacity: 1; visibility: visible; }}
    @-webkit-keyframes fadeIn { 0% { opacity: 0; visibility: hidden; } 100% { opacity: 1; visibility: visible; }}
    @-ms-keyframes fadeIn { 0% { opacity: 0; visibility: hidden; } 100% { opacity: 1; visibility: visible; }}
    @-keyframes fadeIn { 0% { opacity: 0; visibility: hidden; } 100% { opacity: 1; visibility: visible; }}

    @-moz-keyframes fadeOut { 0% { opacity: 1; visibility: visible; }  100% { opacity: 0; visibility: hidden; }} 
    @-webkit-keyframes fadeOut { 0% { opacity: 1; visibility: visible; }  100% { opacity: 0; visibility: hidden; }} 
    @-ms-keyframes fadeOut { 0% { opacity: 1; visibility: visible; } 100% { opacity: 0; visibility: hidden; }} 
    @-keyframes fadeOut { 0% { opacity: 1; visibility: visible; } 100% { opacity: 0; visibility: hidden;  }} 

Some additional remarks:

  1. If you have child elements in the .page element that have explicitly visibility: visible set on them then they will react to interaction via mouse. This is because hey are not hidden just invisible due to the opacity: 0. The twitter bootstrap collapse plugin does this for instance. You can solve this by setting their visibility to inherit instead of visible. This will cause them to only be visible if their parent is. For instance the collapse plugin can be made to behave using this additional css:

    .page .collapse { visibility: inherit; }

  2. This does not work in IE 9 and below.

  3. You need the browser prefixes as seen in my code to make this work. I tested this without the prefixes and both the latest chrome (42) and firefox (37) did not work without them. This is ugly but can be made easier by using something like SASS with Compass. Here's the same code using that approach:

SASS with Compass

.page { 
  @include animation(fadeIn 1s ease-in-out forwards); 
}

.page.fadeOut { 
  @include animation-name(fadeOut); 
}

@include keyframes(fadeIn) {
  0% { opacity: 0; visibility: hidden; }
  100% { opacity: 1; visibility: visible; }
}

@include keyframes(fadeOut) {
  0% { opacity: 1; visibility: visible; }  
  100% { opacity: 0; visibility: hidden; }
}
like image 122
Koen Peters Avatar answered Oct 19 '22 01:10

Koen Peters


Not completely JS-only, but when you start the fade animation, also add a class to the form container with the following CSS:

.disableMouse * {
  pointer-events: none;
}

This will disable clicks (but it won't disable scrolling). Works in all current browsers, but IE support was only added in version 11. So this may not be the best option for you if you need to support IE10 and earlier.

like image 31
Jeff Clarke Avatar answered Oct 19 '22 00:10

Jeff Clarke