So I got this pen: https://codepen.io/tobiasglaus/pen/NedpxQ
Whenever it "clicks", a circle should be animated. There are 2 clicks in the animation, so I just added the animation 2 times, like this:
animation: circle .3s forwards, circle .3s forwards;
animation-delay: 1.7s, 4.9s;
The problem is, that the circle isn't a circle anymore, but a blurry square:
But it should look like this:
I can't replicate the problem in a SO-snippet, but since I need to provide a minimal code example, here's the snippet of how it should look.
Note: When I view the animation with the Chrome DevTools, the animation looks correct.
.circle:after{
content:"";
position:absolute;
top:20px;
left:20px;
width:50px;
height:50px;
border-radius:50%;
border:2px solid #222f3e;
animation:circle .3s forwards, circle .3s forwards;
animation-delay:0s, 1s;
opacity:0;
transform:scale(0);
}
#keyframes circle {
0%{
transform:scale(0);
}
50%{
opacity:1;
}
100%{
transform:scale(1);
opacity:0;
}
}
<div class="circle"></div>
You can make use of the animation-iteration-count property, like so:
animation: circle .3s forwards;
animation-iteration-count: 2;
Animation-iteration-count sets the number of times an animation cycle should be played before stopping. You want the click to happen twice, so we set the value to 2.
I still don't know why the circle rendered weirdly, but I managed to come up with a solution that works:
That's what I had:
animation: circle .3s forwards, circle .3s forwards;
animation-delay: 1.7s, 4.9s;
and the animation:
#keyframes circle {
0%{
transform:scale(0);
}
50%{
opacity:1;
}
100%{
transform:scale(1);
opacity:0;
}
}
Instead of calling the animation twice, I created one big animation:
animation: circle 3.5s forwards;
animation-delay:1.7s;
and that's the animation:
#keyframes circle{
0%{
transform:scale(0);
}
4%{
opacity:1;
}
8%{
transform:scale(1);
opacity:0;
}
92%{
transform:scale(0);
opacity:0;
}
96%{
opacity:1;
}
100%{
transform:scale(1);
opacity:0;
}
}
So the initial animation duration of 0.3s is now equal to 8% and the animation delay between the animations is equal to the 74% of nothing in the animation.
Related
I built a preloading screen for a website with a loading bar that is animated with CSS #keyframes. Works fine on Chrome and Firefox, but on macOS Safari it gets very discrete. Here is a video demo of how it looks on Safari: https://www.youtube.com/watch?v=ODV5lN2xZSI&feature=youtu.be
As you can see, loading bar background (gray line) and the bar itself (black line) twitch instead of going smoothly from 0% width to 100%. What could be a problem, is this known bug of Safari? Latest macOS and Safari.
#keyframes loading-wrapper-anim {
0% {
width:0%;
}
100% {
width:100%;
}
}
.preloader .loading_wrapper {
position:absolute;
width:0%;
height:1px;
background:#dbdbdb;
top:12rem;
animation: loading-wrapper-anim 1s;
animation-delay: 1s;
animation-fill-mode: forwards;
align-self:flex-start; /*this one is because of the parent element*/
}
.preloader .loading_wrapper .loading_bar {
height:100%;
width:0%;
height:100%;
background:#000;
animation: loading-wrapper-anim 3s;
animation-delay: 2s;
animation-fill-mode: forwards;
}
<div class="preloader">
<div class="loading_wrapper">
<div class="loading_bar">
</div>
</div>
</div>
Smooth animation is expected.
Thank you.
You can attempt to force the hardware acceleration by adding a translateZ on the animation.
.preloader .loading_wrapper {
position:absolute;
width:0%;
height:1px;
background:#dbdbdb;
top:12rem;
animation: loading-wrapper-anim 1s;
animation-delay: 1s;
animation-fill-mode: forwards;
align-self:flex-start;
/* Add this */
-webkit-transform: translateZ(0);
}
JSFiddle
Alternatively, you can look into using the will-change method as a last resort for smoother animations.
https://developer.mozilla.org/en-US/docs/Web/CSS/will-change
The way I fixed it is instead of trying to manipulate width of an element (which causes redrawing each time the width changes), did the following:
#keyframes loading-wrapper-anim {
0% {
transform:scaleX(0);
}
100% {
transform:scaleX(1);
}
}
.preloader .loading_wrapper {
position:absolute;
width:100%;
height:1px;
background:#dbdbdb;
top:12rem;
animation: loading-wrapper-anim 1s;
animation-delay: 1s;
animation-fill-mode: forwards;
align-self:flex-start; /*this one is because of the parent element*/
transform:scaleX(0);
transform-origin:0% 0%;
}
.preloader .loading_wrapper .loading_bar {
height:100%;
width:100%;
height:100%;
background:#000;
animation: loading-wrapper-anim 3s;
animation-delay: 2s;
animation-fill-mode: forwards;
transform:scaleX(0);
transform-origin:0% 0%;
}
I used transform:scaleX() in conjunction with transform-origin:0% 0% (this one sets center of transformation to the top left corner) to emulate width change without actually changing it.
Conclusion: use transform where/when possible. They are more efficient in terms of CSS animations and transitions.
I'm working with HTML5 banner having a lot of CSS3 animation. To make reusable keyframe animation I'm using multiple animation on single element. It's working perfectly except safari.
CSS:
.text1 {
-webkit-animation: fadeOutRight 1s 3s forwards;
animation: fadeOutRight 1s 3s forwards;
}
.text2 {
-webkit-animation: fadeInLeft 1s 4s both, fadeOutRight 1s 7s forwards;
animation: fadeInLeft 1s 4s both, fadeOutRight 1s 7s forwards;
}
.text3 {
-webkit-animation: fadeInLeft 1s 8s both;
animation: fadeInLeft 1s 8s both;
}
/* fadeInLeft */
#-webkit-keyframes fadeInLeft {
0% { -webkit-transform: translateX(-100px); opacity: 0; }
100% { -webkit-transform: translateX(0px); opacity: 1; }
}
#keyframes fadeInLeft {
0% { transform: translateX(-100px); opacity: 0; }
100% { transform: translateX(0px); opacity: 1; }
}
/* fadeOutRight */
#-webkit-keyframes fadeOutRight {
0% { -webkit-transform: translateX(0px); opacity: 1; }
100% { -webkit-transform: translateX(100px); opacity: 0; }
}
#keyframes fadeOutRight {
0% { transform: translateX(0px); opacity: 1; }
100% { transform: translateX(100px); opacity: 0; }
}
jsfiddle link
Workable solutions:
Wrap the element with another/more element & add single animation to each element. This solution needs extra styling for wrapper element.
Merge multiple animation into one & this solution increase the complexity of the keyframes rule and it's not easily maintainable for complex animation.
According to accepted answer of another stackOverflow post –
You cannot animate same attribute more than once, on a same element, the last one will overwrite other.
It’s only true for safari in my case & first animation is only running not
second one. If I don’t animate same property on multiple animation
then it’s also fine for safari(jsfiddle). This one is not
suitable for me because I will need to animate same property in
multiple animations.
Note:
Although I'm using multiple animation on same element but I'm not animating at same time, there is delay between each animation.
Question:
Is it possible to use multiple CSS3 animation on same element regardless of animating property?
For some reason, Safari does not read trough the shorthand method for describing the animation, for example:
animation: test 1s 2s 3 alternate backwards
It needs to be described more detailed with its separate properties listed:
.class{
animation-name: bounce;
animation-duration: 4s;
animation-iteration-count: 10;
animation-direction: alternate;
animation-timing-function: ease-out;
animation-fill-mode: forwards;
animation-delay: 2s;
}
I got an image
<div class="spin-image">
<img src="images/color-wheel.png" alt="" />
</div>
and its corresponding css
.spin-image {
-webkit-animation:spin 10s linear infinite;
-moz-animation:spin 10s linear infinite;
animation:spin 10s linear infinite;
-webkit-transition-duration: 2s; /* Safari */
transition-duration: 2s;
}
.spin-image:hover {
-webkit-animation:spin 2s linear infinite;
-moz-animation:spin 2s linear infinite;
animation:spin 2s linear infinite;
}
#-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
#-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
#keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
What I'm trying to do is to accelerate the image spinning on hover. The animation works, but the transition does not.
If you realise, this is like the animation and the hover animation are two different ones, and they reset to their virtual state of rotation in case they were running all the time you were or weren't hovering.
Unfortunatly, it is not posible to animate the transition between 2 different animation-durations.
Yet if you really really need a solution for this, you could program the animation using transition and a javascript interval that resets the positions for every turn. This way yo can reset the property and the duration of the transition at any time with javascript.
I made you a pen: http://codepen.io/vandervals/pen/aONmVL
This is the css you need:
.spin-image img{
transition: transform 2s linear;
transform: rotate(0deg);
}
.spin-image img.hover{
transition: transform 1s linear;
}
And the JS:
var vel = 2000;
var degs = 0;
var cat = document.querySelector("img");
function repeat(){
if(vel == 1000){
cat.classList.add("hover");
console.log("hover")
}else{
cat.classList.remove("hover");
console.log("nohover")
}
degs+=360;
cat.style.transform = "rotate("+degs+"deg)";
setTimeout(repeat, vel);
}
repeat();
document.querySelector("img").addEventListener("mouseenter",hovering);
function hovering(){
vel = 1000;
}
document.querySelector("img").addEventListener("mouseleave",nohovering);
function nohovering(){
vel = 2000;
}
If you look at my code and run it.
#-webkit-keyframes circle {
from { transform:rotate(0deg); }
to { transform:rotate(180deg); }
}
#-webkit-keyframes inner-circle {
from { transform:rotate(0deg); }
to { transform:rotate(-180deg); }
}
#one {
position: absolute;
left: 500px;
top: 200px;
width:100px;
height:100px;
border-radius: 50px;
background-color: #000000;
}
#two {
width:100px;
height:100px;
margin: 0px auto 0;
color:orange;
font-size:100px;
line-height:1;
transform-origin:50% 200px;
}
#one:hover > div {
animation: circle 1s linear infinite;
-webkit-animation: circle 1s linear infinite;
}
#one:hover > div > div {
animation: inner-circle 1s linear infinite;
-webkit-animation: inner-circle 1s linear infinite;
}
</style>
<div id="one">
<div id="two"><div id="three">☻</div></div>
</div>
you will notice that the smile face keeps on looping the animation of rotating 180deg. I don't want this. I only want it to do the animation once every time I hover over the black circle. How do I do this?
If you don't want the animation to occur infinitely, remove infinite from the animation shorthand.
In addition, you will also need to add forwards in order to to prevent the animation from resetting each time. When adding forwards to the animation shorthand, you are essentially changing the property animation-fill-mode from the default value of none to forwards.
From MDN:
The animation-fill-mode CSS property specifies how a CSS animation should apply styles to its target before and after it is executing.
#one:hover > div {
animation: circle 1s linear forwards;
-webkit-animation: circle 1s linear forwards;
}
#one:hover > div > div {
animation: inner-circle 1s linear forwards;
-webkit-animation: inner-circle 1s linear forwards;
}
Change all the infinite values to the amount of times you want the animation to loop. In your case it will be once so you want to change infinite to 1.
I was wondering how to make an image blink in CSS, if it is possible. I want to have it blink where it is.
I would also like to change the speed but mainly I want to make it blink.
CSS animations to the rescue!
#keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
img {
animation: blink 1s;
animation-iteration-count: infinite;
}
http://jsfiddle.net/r6dje/
You can make it a sharp blink by adjusting the intervals:
#keyframes blink {
0% {
opacity: 1;
}
49% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 0;
}
}
http://jsfiddle.net/xtJF5/1/
use setInterval method of Javascript use it as a reference of W3Schools and then change the css from visibility:visible to visiblity:hidden we will not use display:none as it will remove the space of the image as well but we do need the space for the image for the blinking thing to work.
You can do it with CSS easily. Just add below cross browser code in the CSS element of your image. You can set also timing if you change the digit in the code.
-webkit-transition:all 1s ease-in-out;
-o-transition:all 1s ease-in-out;
-ms-transition:all 1s ease-in-out;
transition:all 1s ease-in-out;
-webkit-animation:blink normal 2s infinite ease-in-out;
-ms-animation:blink normal 2s infinite ease-in-out;
animation:blink normal 2s infinite ease-in-out;