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:
The user clicks on a button
An ajax call is done and while waiting for the response the page fades out (opacity: 0)
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
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?
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:
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;
}
This does not work in IE 9 and below.
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; }
}
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.
Pretty sure I can't be done with CSS alone. You could look in to the JavaScript's transitionend.
You could look in to CSS animations rather than transitions as well. I know you can't transition visibility: hidden; but you might be able to set up an animation key frame at 100% to do this.
If your only intent is to disable interaction, you could use pointer-events: none (IE11+) on your page, or have a floating blocker over the top, like;
.page.loading {
position: relative;
}
.page.loading:after {
content: ' ';
display: block;
position: relative;
background: white;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Related
For this example, I'll use a simple box that, as an animation, pops into view using opacity and transform: translate().
I can do this in two ways:
Set the box's initial CSS to opacity: 0 and transform: translate(10px), then write a keyframes that just sets the to property. Then, persist the end state of the animation using animation-fill-mode: forwards (specified in the shorthand).
.animation {
width: 100px;
height: 100px;
background: green;
animation: slide-in .5s ease-in-out forwards;
opacity: 0;
transform: translateY(10px);
}
#keyframes slide-in {
to {
opacity: 1;
transform: translateY(0);
}
}
<div class="animation"></div>
The second way to do this is to specify the initial state in the keyframes instead, and not on the element itself. I specify a from and a to state, and leave everything to the animation.
.animation {
width: 100px;
height: 100px;
background: green;
animation: slide-in .5s ease-in-out;
}
#keyframes slide-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
<div class="animation"></div>
Both ways seem to work well and so my question is:
Is one of these options better than the other?
I don't see any advantages/disadvantages that aren't based on opinion, so I'm looking for factual advantages (performance?, accessibility?)
If a user has disabled transitions and/or animations, using the first approach the element would be not visible at all because you defined opacity: 0 as a property of the element and not inside the keyframes.
So, the second approach at least ensures that the element is always visible, even when the animation can't run because of user's settings.
Note that this is not strictly related to the animation-fill-mode property, since you could still use it by slightly changing the CSS of the first snippet:
.animation {
width: 100px;
height: 100px;
background: green;
animation: slide-in .5s ease-in-out forwards;
}
#keyframes slide-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
<div class="animation"></div>
I'm trying to create a visual transition between content changes in a toy SPA I'm writing. To that end, I define a simple class for animating the opacity of an element.
.fade {
transition: opacity 1.5s;
}
In my render function, I now change the opacity of my outlet div after content changes like so:
function render(content) {
var outlet = document.getElementById("outlet");
outlet.classList.remove("fade");
outlet.style.opacity = 0;
outlet.innerHTML = content;
outlet.classList.add("fade");
outlet.style.opacity = 1;
}
Unfortunately, the animation never fires. When I delay changing the opacity to 1 via setTimeout for 10ms, say, it works sometimes if I don't change the content again while the animation is still running, indicating a timing issue/race condition.
I used a similar approach in the past to fade out messages, but there I intentionally delayed changing the opacity by a few seconds so users could read the message before it starts fading out.
Pure CSS animation fadeIn
li {
position: absolute;
top: 50%;
left: 50%;
margin-top: -75px;
}
.logo {
width: 300px;
height: 150px;
background: red;
margin-left: -150px;
z-index: 30;
-webkit-animation: fade-in-slogan 4s .2s ease-in forwards;
-moz-animation: fade-in-slogan 4s .2s ease-in forwards;
animation: fade-in-slogan 4s .2s ease-in forwards;
}
.menu {
width: 600px;
height: 150px;
background: blue;
margin-left: -300px;
opacity: 0;
-webkit-animation: fade-in-menu 3s 4s ease-out forwards;
-moz-animation: fade-in-menu 3s 4s ease-out forwards;
animation: fade-in-menu 3s 4s ease-out forwards;
}
#-webkit-keyframes fade-in-slogan {
0% { opacity: 0; }
30% { opacity: 1; }
50% { opacity: 1; }
70% { opacity: 1; }
100% { opacity: 0; }
}
#-webkit-keyframes fade-in-menu {
0% { display: block; opacity: 0; }
30% { display: block; opacity: .3; }
60% { display: block; opacity: .6; }
80% { display: block; opacity: .8; }
100% { display: block; opacity: 1; }
}
<ul class"main">
<li class="logo"></li>
<li class="menu"></li>
</ul>
Try this, I hope this will solve the issue
.fade{
animation-name: example;
animation-duration: 4s;}
#keyframes example {
from {opacity:1}
to {opacity:0;}
}
div{
width:200px;
height:200px;
background:#000;
}
<html>
<head>
</head>
<body>
<div class="fade"></div>
</body>
</html>
I've solved it now inspired by Muhammad's answer. I defined the fade class as follows:
.fade {
animation-name: fadein;
animation-duration: 1.25s;
#keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
Then in the render function, I do
function render(content) {
outlet.classList.remove("fade");
outlet.innerHTML = "";
setTimeout(() => {
outlet.classList.add("fade");
outlet.appendChild(content);
}, 100);
}
Even though this adds an additional delay before the new content actually starts to fade in, it seems the most elegant and concise solution to me.
My page has an overlapped div, which it will be hided after 5 seconds. However, I realize that the buttons behind the div cannot be pressed due to the div is still there after 5 seconds.
To remove the div, I have tried with display:none but it does not work.
Here are my css:
.ox-messages {
-webkit-animation: seconds 1.0s forwards;
-webkit-animation-iteration-count: 1;
-webkit-animation-delay: 5s;
animation: seconds 1.0s forwards;
animation-iteration-count: 1;
animation-delay: 5s;
position: relative;
}
#-webkit-keyframes seconds {
0% {
opacity: 1;
}
100% {
opacity: 0;
left: -9999px;
//display: none;
}
}
#keyframes seconds {
0% {
opacity: 1;
}
100% {
opacity: 0;
left: -9999px;
//display: none;
}
}
The problem looks like this:
The alert messages (in green) are overlapping the buttons (the note-plus icon).
Please help and thanks.
EDIT: I change position:relative to position:absolute, which it does not block the buttons but the messages stack together.
Please feel free to copy and paste this code in any html editor (or press code snippet below) and you will see that the JavaScript function will indeed remove the div. In this example, no text will be displayed in the website, because we removed the div in which the text is contained by using JavaScript:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<div id="div_we_want_to_remove">
<!-- We will not see the following text on the webpage if we execute the the JavaScript code that I included -->
<p1> It is possible to get rid of this text using javascript</p1>
</div>
<script>
//this is the JavaScript code that's needed to get rid of that div
function remove_div() {
var elem = document.getElementById('div_we_want_to_remove');
elem.parentNode.removeChild(elem);
return false;
}
//remove_div literally will remove the div
remove_div();
</script>
</html>
you can set pointer-events: none; on that div when you hide it, and it won't get in the way anymore
Set the visibility: hidden then the element will be hidden from the document. Making the button behind it clickable.
.ox-messages {
-webkit-animation: seconds 1.0s forwards;
-webkit-animation-iteration-count: 1;
-webkit-animation-delay: 5s;
animation: seconds 1.0s forwards;
animation-iteration-count: 1;
animation-delay: 5s;
position: relative;
height: 200px;
width: 500px;
background: red;
position: absolute;
top: 0;
}
#-webkit-keyframes seconds {
0% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
#keyframes seconds {
0% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
<button>TEST</button>
<div class="ox-messages"></div>
I am trying to implement some animation onLoad without Javascript. JS is easy, CSS is ... not.
I have a div which should be on display: none; and should be display: block; after 3 secondes. Lots of resources told me animate does not work with display, but should with visibility (which I use often in my transition).
Right know I have this terrible javascript function :
<script type="text/javascript">
$(document).ready(function(){
$(".js_only").hide();
setTimeout(function () {
$(".js_only").show();
}, 3000);
});
</script>
I tried some animation in CSS but no result ... nothing seems to work.
I have few animation in my page, but just struggling with the display: none; on animation.
#-moz-keyframes showEffect {
0% { display: none; visibility: hidden; }
100% { display: block; visibility: block; }
}
#-webkit-keyframes showEffect {
0% { display: none; visibility: hidden; }
100% { display: block; visibility: block; }
}
#keyframes showEffect {
0% { display: none; visibility: hidden; }
100% { display: block; visibility: block; }
}
.css_only {
-moz-animation-name: showEffect;
-moz-animation-iteration-count: 1;
-moz-animation-timing-function: ease-in;
-moz-animation-duration: 2.3s;
-webkit-animation-name: showEffect;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in;
-webkit-animation-duration: 2.3s;
animation-name: showEffect;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 2.3s;
}
It is important as hidden, this element does not take space at all. I created a JSFiddle to make quite tests.
My main concerne is SEO ... I don't think the JS option is really nice for that which is why I would like a pure CSS alternative. Also interested to test those animations and see where are those limits (Am I seeing one right now ?). Kinda having fun on such challenge.
Thanks for reading, hope someone has an answer.
You are correct in thinking that display is not animatable. It won't work, and you shouldn't bother including it in keyframe animations.
visibility is technically animatable, but in a round about way. You need to hold the property for as long as needed, then snap to the new value. visibility doesn't tween between keyframes, it just steps harshly.
.ele {
width: 60px;
height: 60px;
background-color: #ff6699;
animation: 1s fadeIn;
animation-fill-mode: forwards;
visibility: hidden;
}
.ele:hover {
background-color: #123;
}
#keyframes fadeIn {
99% {
visibility: hidden;
}
100% {
visibility: visible;
}
}
<div class="ele"></div>
If you want to fade, you use opacity. If you include a delay, you'll need visibility as well, to stop the user from interacting with the element while it's not visible.
.ele {
width: 60px;
height: 60px;
background-color: #ff6699;
animation: 1s fadeIn;
animation-fill-mode: forwards;
visibility: hidden;
}
.ele:hover {
background-color: #123;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
visibility: visible;
opacity: 1;
}
}
<div class="ele"></div>
Both examples use animation-fill-mode, which can hold an element's visual state after an animation ends.
Use animation-delay:
div {
width: 100px;
height: 100px;
background: red;
opacity: 0;
animation: fadeIn 3s;
animation-delay: 5s;
animation-fill-mode: forwards;
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
Fiddle
You can play with delay prop of animation, just set visibility:visible after a delay, demo:
#keyframes delayedShow {
to {
visibility: visible;
}
}
.delayedShow{
visibility: hidden;
animation: 0s linear 2.3s forwards delayedShow ;
}
So, Where are you?
<div class="delayedShow">
Hey, I'm here!
</div>
Unfortunately you can't animate the display property. For a full list of what you can animate, try this CSS animation list by w3 Schools.
If you want to retain it's visual position on the page, you should try animating either it's height (which will still affect the position of other elements), or opacity (how transparent it is). You could even try animating the z-index, which is the position on the z axis (depth), by putting an element over the top of it, and then rearranging what's on top. However, I'd suggest using opacity, as it retains the vertical space where the element is.
I've updated the fiddle to show an example.
Good luck!
you can't animate every property,
here's a reference to which are the animatable properties
visibility is animatable while display isn't...
in your case you could also animate opacity or height depending of the kind of effect you want to render_
fiddle with opacity animation
I have a div which I need to animate it's opacity from 1 - 0, and THEN hide it, as some of you may know, adding display properties just override transitional values and hide the element straight away, so I'm wondering if there's a way with css to animate it's opacity, and THEN hide it?
Here's what I've tried:
#keyframes infrontAnimation {
0% {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 1;
}
50% {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
}
100% {
display: none;
}
}
This doesn't work, it just hides straight away, it also doesn't stay at the 100% value:
Using it like this:
animation: infrontAnimation 1s 2s ease-out;
So my question is, is it possible to hide something, but only after a certain animation is finished?
Rather than setting the height or width of an element, I found a different approach, that to me, isn't as dodgy as forcing the height at 99.9%. Here's what I came up with:
First, Rather than using display to hide & show it, I used visibility, seeing as it's still something that can interrupt our animation and ultimately cause it to fail, I setup our transition properties initially:
Note: I'll keep other prefixes out for this demo:
.item {
transition: visibility 0s linear 0.7s, opacity 0.7s ease-in-out;
}
So what we're doing is setting the transition of the visibility attribute to 0, but delaying it by the time it takes to complete the fade out (opacity);
So when we want it to be visible, we add the class of visilble:
.item.visible {
transition-delay: 0s;
visibility: visible;
opacity: 1;
}
So we're setting our delay to 0 here so that we can override the state when it transitions in, obviously we dont' want to delay the visibility, we want to set that straight away and then animate our opacity;
Then when we want to hide it:
.item.hidden {
opacity: 0;
visibility:hidden;
}
Then all this is doing is transitioning our opacity back to 0, and leaving our delay at 0.7 so that it doesn't actually 'dissappear' in the dom until the opacity has finished.
Detailed Working Example
Fist of all, I've created a Fiddle to show what can be done. The red bars represent other content, like text.
Say, if you want to hide it in a way that it first fades, then shrinks, you could use
#-webkit-keyframes infrontAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
height: 200px;
}
100% {
opacity: 0;
height: 0;
}
}
#keyframes infrontAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
height: 200px;
}
100% {
opacity: 0;
height: 0;
}
}
animation: infrontAnimation 1s 2s forwards ease-out;
-webkit-animation: infrontAnimation 1s 2s forwards ease-out;
Note that both #keyframes as #-webkit-keyframesare used.
If you need to hide it without shrinking animation, you might want to use this
#-webkit-keyframes infrontAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
99.9% {
opacity: 0;
height: 200px;
}
100% {
opacity: 0;
height: 0;
}
}
#keyframes infrontAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
99.9% {
opacity: 0;
height: 200px;
}
100% {
opacity: 0;
height: 0;
}
}
You need to set animation-fill-mode: with the value forwards so it ends on the last frame of the animation.
See: http://dev.w3.org/csswg/css-animations/#animation-fill-mode