I have the following code to show/hide buttons on a carousel based on css classes. Everything works as intended, except on hideButton, the display is not set to "none" after the animation is done.
The effect is that although the button fades, it's still on top of underlying items and prevents clicks from hitting them.
.pills-tab-carousel__button {
position: absolute;
top: 0;
height: 100%;
line-height: 100%;
width: 64px;
animation: showButton .5s forwards;
}
.pills-tab-carousel__button--hidden {
animation: hideButton .5s forwards;
}
#keyframes hideButton {
0% {
opacity: 1;
display: block;
}
100% {
opacity: 0;
display: none;
}
}
#keyframes showButton {
0% {
opacity: 0;
display: none;
}
1% {
opacity: 0.01;
display: block;
}
100% {
opacity: 1;
display: block;
}
}
Why not to use visibility: hidden; since your element is already position absolute so you don't need to worry about layout.
Check out the fiddle I just created:
https://jsfiddle.net/uvxeqaLn/
You cannot animate the display property.
As an alternative you can set the property pointer-events: none; which will allow clicks to pass through the hidden element.
Just be aware that this is not supported in any IE versions prior to IE11.
Related
I'm trying to make a div that appear and disappear on touch, like the navigation bar of android phones.
Should I use transition for this or is animation ok? In the fiddle example i use the mouse click and the setTimeout to simulate the touches and the auto disappear if you dont touch the screen for some seconds.
.custom-row{
position: fixed;
width: 100%;
height: 50px;
bottom: -100px;
left: 0px;
background-color: yellow;
opacity: 0;
}
.slidein {
animation: slidein 1s ease-in forwards;
}
.slideout {
animation: slideout 1s ease-in forwards;
}
#keyframes slidein {
0% {
}
100% {
bottom: 0px;
opacity: 1;
}
}
#keyframes slideout {
0% {
bottom: 0px;
opacity: 1;
}
100% {
bottom: -100px;
opacity: 0;
}
}
https://jsfiddle.net/1rm64q8z/1/
For this use case, transition seems to be a better solution. With animation, alerting position is a compute-intensive approach. The CSS will also be much more readable and scalable with transitions in this case.
const bar = document.getElementById("bottom-bar");
bar.addEventListener("click", (el) => {
el.target.classList.toggle("slide-out");
setTimeout(() => {
el.target.classList.toggle("slide-out");
el.target.classList.toggle("slide-in");
}, 2000)
})
body {
overflow: hidden;
}
#bottom-bar {
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
background: yellow;
padding: 16px;
text-align: center;
transform-origin: bottom;
transition: transform 0.4s ease-in-out;
}
.slide-in {
transform: translateY(0%);
}
.slide-out {
transform: translateY(100%);
}
<div id="bottom-bar">
Hello
</div>
The performance of CSS transitions and animations should be almost the same as they are both hardware accelerated so on most modern browsers the behaviour should be the same.
Animations are often used to create a more complex series of movements and they do not lift the rendering process to the GPU and resulting in being slower than transitions.
This article gives a great breakdown of when to use animations vs transitions.
Please can you help troubleshoot the transition in this CSS? My browser can see the code in the inspector but no transition is taking place. I have tried operating the transition on different properties including width and position but nothing works.
#header-image {
position: absolute;
top: 30px;
right: 30px;
background: transparent;
width: 250px;
margin-left: 10px;
opacity: 1;
transition: opacity 2s linear 1s;
}
I know I'm probably being thick so apologies in advance.
In order for the transition to work.. the property value should change. only then it will trigger the transition.
i.e) lets say #header-image initially has opacity: 0; width: 50px;.
but when you hover it you want to increase the opacity and width opacity: 1; width: 250px;
so your css will look like..
#header-image {
position: absolute;
top: 30px;
left: 30px;
background: blue;
width: 100px;
height: 100px;
margin-left: 10px;
animation: fadeIn 2s linear;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="header-image"></div>
Then your transition will work. So basically transition will work only when there is a change in the value. But in your case you are setting the opacity:1 initially by default.
If you want to add this effect on page load then you have to use css animation or javascript. Below I have given an example snippet on how it can be achieved using css animation.
However if you are planning to use many animations then I recommend to use some popular libraries like Animista, Animate.css, wow.js
I'm trying to have a span appear from the bottom by css I wrote the following code that'snot working,
span {
display: inline !important;
background-color: transparent !important;
overflow: hidden;
animation: from-btm 1s !important;
#keyframes from-btm {
from {
margin-bottom: -5%;
}
to {
margin-bottom: 0%;
}
}
}
Use position: relative and bottom for the animation positioning (margin-bottom won't apply to an inline element). The overflow: hidden needs to be on a parent container and the keyframes rule needs to be outside the CSS rule for the span:
span {
position: relative;
display: inline !important;
background-color: transparent !important;
animation: from-btm 1s !important;
}
#keyframes from-btm {
from {
bottom: -80%;
}
to {
bottom: 0%;
}
}
.container {
background: yellow;
overflow: hidden;
}
<div class="container">
<span>The Span</span>
</div>
There are two issues in your code. First, the span has to be inline-block secondly keyframes are to be declared outside span selector in CSS.
span {
display: inline-block !important;
background-color: transparent !important;
overflow: hidden;
animation: from-btm 1s !important;
}
#keyframes from-btm {
from {
margin-bottom: -5%;
}
to {
margin-bottom: 0%;
}
}
<span>ABCD</span>
Working Fiddle code
You need to write your keyframe outside of your style. It should be like that:
span {
display: inline !important;
background-color: transparent !important;
overflow: hidden;
animation: from-btm 1s !important;
}
#keyframes from-btn {
0% {
margin-bottom: -5%;
}
100% {
margin-bottom: 0%;
}
}
Your #keyframes property should be outside the span element. It should stay outside the span element because it is it's own element. Like This:
span {
display: inline !important;
background-color: transparent !important;
overflow: hidden;
animation: from-btn 1s ease 0s 1;
}
#keyframes from-btm {
from {
margin-bottom: -5%;
}
to {
margin-bottom: 0%;
}
}
Also you animation shorthand is not "that properly written" it should be animation: "animation-name" "animation-duration" "animation-display(ease, ease-in, ease-out, linear)" "animation-delay" animation-count(any number or even infinite); as seen above.
Also for performance reasons you should consider animate the position using the transform element like this: eg.
#keyframes from-btm {
from {
transform: translateY(200%);
}
to {
transform: translateY(10%);
}
}
Also when using transform make sure to add a position propery to your element span for example position: absolute or position: relative
Context:
According to the Animation Spec:
If a ‘0%’ or ‘from’ keyframe is not specified, then the user agent
constructs a ‘0%’ keyframe using the computed values of the properties
being animated. If a ‘100%’ or ‘to’ keyframe is not specified, then
the user agent constructs a ‘100%’ keyframe using the computed values
of the properties being animated.
This can lead to two different interpretations:
A) Declare the property in the class and not in the 0% or from keyframe.
B) Declare the property in the class and in the 0% or from keyframe.
Simplified Example:
p:first-of-type {
opacity: 0;
animation: a 3s linear infinite alternate;
}
#keyframes a {
100% {
opacity: 1;
}
}
p:last-of-type {
opacity: 0;
animation: b 3s linear infinite alternate;
}
#keyframes b {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<p>
A) Declare the property in the class <strong>and not</strong> in the `0%` or `from` keyframe.
</p>
<p>
B) Declare the property in the class <strong>and </strong> in the `0%` or `from` keyframe.
</p>
While both have the same end result, following the Don't Repeat Yourself (DRY) principle, A) could vastly reduce code for all the animations that use more than one property.
Complex Example:
/*
Layout
*/
* {
box-sizing: border-box;
}
body {
margin: 0;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-around;
counter-reset: list-item;
}
.container > li {
position: relative;
counter-increment: list-item;
}
.container > li::before {
content: counter(list-item, upper-alpha);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: flex-end;
font-size: 1.5em;
background-color: moccasin;
}
.container > li::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 100%;
transform: translateY(-50%);
height: 2px;
background-color: gold;
}
/*
SVG
*/
.svg-spritesheet {
display: none;
}
.svg__icon {
display: inline-block;
vertical-align: middle;
width: 1em;
height: 1em;
}
.svg__icon--square {
font-size: 5em;
color: dodgerblue;
}
/*
Question Related
*/
.container > li:first-of-type .svg__icon--square {
opacity: 0;
transform: scale(.5) rotate(45deg);
animation: animationA 5s linear infinite alternate;
}
.container > li:nth-child(2) .svg__icon--square {
opacity: 0;
transform: scale(.5) rotate(45deg);
animation: animationB 5s linear infinite alternate;
}
#keyframes animationA {
to {
opacity: 1;
transform: translateX(500px) scale(1) rotate(90deg);
}
}
#keyframes animationB {
from {
opacity: 0;
transform: scale(.5) rotate(45deg);
}
to {
opacity: 1;
transform: translateX(500px) scale(1) rotate(90deg);
}
}
<ul class="container">
<li>
<svg class="svg__icon svg__icon--square">
<use xlink:href="#svg-icon-square"></use>
</svg>
</li>
<li>
<svg class="svg__icon svg__icon--square">
<use xlink:href="#svg-icon-square"></use>
</svg>
</li>
</ul>
<svg class="svg-spritesheet">
<symbol id="svg-icon-square" viewBox="0 0 32 32">
<title>Demo Square</title>
<rect width="32" height="32" fill="currentColor" />
</symbol>
</svg>
Question:
Is it safe to remove a property from the 0% keyframe of a CSS animation if it is already declared in the class the animation is applied to?
Is doing this:
.el {
opacity: 0;
animation: example 1s;
}
#keyframes example {
100% {
opacity: 1;
}
}
considered safe across browsers? Or is it to be expected that user agents render different results or performance?
TESTS:
Rendering the same result:
Windows 10 / 64-bit
Chrome 54.0.2840.71 m (64-bit)
FireFox 49.0.2
Edge 25.10586.0.0
The computed value of a property can vary depending on what CSS rules are applying to a given element, the specificity of these rules, whether the element has an inline style declaration for that property, whether a script is modifying the value of that property at runtime, etc.
If you want an animation to start from a predictable, and fixed, value, you will need to specify this value in the 0% keyframe so that it doesn't start animating from what the computed value happens to be at the time the animation starts instead.
You can leave out the 0% keyframe if you can guarantee that the computed value for that element at the time the animation is started is always a constant value. You must leave out the 0% keyframe if you want the animation to always start from whatever the computed value happens to be at the time, if it can change.
Similar rules apply to the 100% keyframe: if the animation needs to end with a fixed value regardless of what the computed value may be, you will need to specify the 100% keyframe; otherwise, if it needs to end with the same value as the computed value, you will need to leave it out.
It can work in both way, as the specification point out.
Regarding safeness, this should be ok in the following browsers:
IE 11
Edge 14
Firefox from 47 to 52
Chrome from 49 to 57
Safari from 9.1 to 10
Keeping the 0% in my opinion could make your code more readable specially if you have complex animation, but in case you want avoid repetition you could use some CSS pre-processor, for example LESS using animation keyframes mixin or other techniques.
I am building a lightbox based on the CSS3 selector :target which selects an element based on the hash in the url. I want to animate the target element on the :target event, but this doesn't seem to work.
Let's say we have a div #banana which is shown when a link to #banana is pressed.
#banana {display: none;}
#banana:target {display: block;}
This works fine. But when trying to animate the element, that doesn't work. See this fiddle.
div#banana {
display: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 5s linear 1s;
}
div#banana:target {
display: block;
opacity: 1;
}
The element won't fade in. It is as if the browser skips the animation and immediately triggers the end result.
The problem is that you are changing the display property. The display property can't be transitioned since you can't really animate an element turning from nothing into a block.
The display property can be left out altogether. You will however need to give your element visibility: hidden so that it will not prevent the link from being clicked, then transition it to visibility: visible:
div#banana {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 5s linear 1s;
visibility: hidden;
}
div#banana:target {
opacity: 1;
visibility: visible;
}
Updated fiddle
It's not possible to animate display property. There is simply no gradual stages between none and block.
In your case you can "hide" element by using huge negative top position and revert it back to 0 on target event. Actual transition will be handled by changing opacity.
div#banana {
position: fixed;
left: 0;
top: -1000px;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
opacity: 0;
transition: opacity 1s linear;
}
div#banana:target {
top: 0;
opacity: 1;
}
<div id="banana">
close
</div>
Do you want a banana? Click me!