I'm creating a CSS keyframe animation to have an element appear as if it is casually/slowly floating around a bit. It's nested in parents, one which uses translateX() to slowly move it left and right, and one which uses translateY() to slowly and independently move it up and down.
Chrome and Safari render this perfectly, giving it a gradual swaying movement. It smooths the animation (perhaps using sub-pixel smoothing?) so that everything appears very smooth. Firefox however, animates it pixel by pixel, so rather than smoothly swaying about, you can see it jump at every pixel.
View the JSFiddle in Chrome and FireFox to view the difference: http://jsfiddle.net/gonygdfz/6/
Is there any way to make FireFox render this smoothly rather than having it jumping pixel by pixel? It's extremely noticeable in the actual application for this.
The Markup:
<div id="parent">
<div id="move-x">
<div id="move-y">
<div id="child"></div>
</div>
</div>
</div>
The CSS:
#parent {
width: 400px;
height: 326px;
background-color: yellow;
background: url(http://paint.net.amihotornot.com.au/Features/Effects/Plugins/Render/Grid_CheckerBoard_Maker/Grid_CheckerBoard_Maker.Paint.NET.001.png) top center repeat;
}
#child {
position: absolute;
top: 75px;
left: 150px;
width: 100px;
height: 100px;
background-color: black;
animation: range-y 10s infinite ease;
}
#move-x {
animation: range-x 10s infinite ease;
-webkit-animation: range-x 10s infinite ease;
}
#move-y {
animation: range-y 15s infinite ease;
-webkit-animation: range-y 15s infinite ease;
}
#keyframes range-x {
0% {
transform: translateX(0);
}
30% {
transform: translateX(-8px);
}
50% {
transform: translateX(1px);
}
65% {
transform: translateX(6px);
}
80% {
transform: translateX(0px);
}
89% {
transform: translateX(-3px);
}
100% {
transform: translateX(0);
}
}
#keyframes range-y {
0% {
transform: translateY(0);
}
20% {
transform: translateY(13px);
}
35% {
transform: translateY(-1px);
}
70% {
transform: translateY(-14px);
}
90% {
transform: translateY(2px);
}
100% {
transform: translateY(0);
}
}
#-webkit-keyframes range-x {
0% {
transform: translateX(0);
}
30% {
transform: translateX(-8px);
}
50% {
transform: translateX(1px);
}
65% {
transform: translateX(6px);
}
80% {
transform: translateX(0px);
}
89% {
transform: translateX(-3px);
}
100% {
transform: translateX(0);
}
}
#-webkit-keyframes range-y {
0% {
transform: translateY(0);
}
20% {
transform: translateY(13px);
}
35% {
transform: translateY(-1px);
}
70% {
transform: translateY(-14px);
}
90% {
transform: translateY(2px);
}
100% {
transform: translateY(0);
}
}
The rendering engines for each browser is obviously different. Firefox does not implement an anti-aliasing effect on CSS animations. This does not inherently make it better or worse, it just depends on what you are animating. Linear transitions can appear undesirably blurred in Chrome for example.
It appears what you would like to achieve is to have an anti-aliased/sub-pixel smoothed transitions. We can't change the way the engine renders but we can manipulate the animation to appear softer to the end user.
ALL IS NOT LOST
I have modified your answer and rendered a smoother version next to your original. This should appear softer when viewed in Firefox.
CLICK FOR COMPARISON
Techniques used for this effect:
Linear transitions instead of ease.
Box-shadow on animated object. (Softened edge helps create fake AA effect).
Rotate object. Adding the smallest rotate helps to better utilised the rendering engine.
CSS
#parent {
width: 50%;
float:left;
height: 326px;
background-color: yellow;
background: url(http://paint.net.amihotornot.com.au/Features/Effects/Plugins/Render/Grid_CheckerBoard_Maker/Grid_CheckerBoard_Maker.Paint.NET.001.png) top center repeat;
}
#child {
position: absolute;
top: 75px;
left: 150px;
width: 100px;
height: 100px;
background-color: black;
box-shadow:0 0 1px rgba(0,0,0,0.7);
animation: range-y 10s infinite linear;
-webkit-animation: range-y 10s infinite linear;
}
#move-x {
animation: range-x 10s infinite linear;
-webkit-animation: range-x 10s infinite linear;
}
#move-y {
animation: range-y 15s infinite linear;
-webkit-animation: range-y 15s infinite linear;
}
#keyframes range-x {
0% {transform: translateX(0);}
30% {transform: translateX(-8px) rotate(0.02deg);}
50% {transform: translateX(1px) rotate(0deg);}
65% {transform: translateX(6px) rotate(0.02deg);}
80% {transform: translateX(0px) rotate(0deg);}
89% {transform: translateX(-3px) rotate(0.02deg);}
100% {transform: translateX(0) rotate(0deg);}
}
#keyframes range-y {
0% {transform: translateY(0);}
20% {transform: translateY(13px) rotate(0.02deg);}
35% {transform: translateY(-1px) rotate(0deg);}
70% {transform: translateY(-14px) rotate(0.02deg);}
90% {transform: translateY(2px) rotate(0deg);}
100% {transform: translateY(0) rotate(0.02deg);}
}
#-webkit-keyframes range-x {
0% {transform: translateX(0);}
30% {transform: translateX(-8px) rotate(0.02deg);}
50% {transform: translateX(1px) rotate(0deg);}
65% {transform: translateX(6px) rotate(0.02deg);}
80% {transform: translateX(0px) rotate(0deg);}
89% {transform: translateX(-3px) rotate(0.02deg);}
100% {transform: translateX(0) rotate(0deg);}
}
#-webkit-keyframes range-y {
0% {transform: translateY(0);}
20% {transform: translateY(13px) rotate(0.02deg);}
35% {transform: translateY(-1px) rotate(0deg);}
70% {transform: translateY(-14px) rotate(0.02deg);}
90% {transform: translateY(2px) rotate(0deg);}
100% {transform: translateY(0) rotate(0.02deg);}
}
FINAL WORD
You can still tweak the effects a little either way to fit your requirements.
It's not perfect but I hope it helps soften the end effect for your actual animation.
Use a small amount of rotation with the transformation. This forces Firefox to avoid the optimization and resample the image on every frame.
#keyframes optimized {
0%{
transform: translateX(0%);
}
100%{
transform: translateX(200px);
}
}
#keyframes subpixel {
0%{
transform: translateX(0%) rotate(0.1deg);
}
100%{
transform: translateX(200px) rotate(0.1deg);
}
}
div{
width:5px;
height:50px;
background-color: red;
animation-duration:30s;
animation-iteration-count: infinite;
animation-direction:alternate;
animation-timing-function:linear;
}
.optimized{
animation-name: optimized;
margin-bottom:1px;
}
.subpixel{
animation-name: subpixel;
}
<div class="optimized">
</div>
<div class="subpixel">
</div>
Related
I currently have an image "floating". So it moves up and down over 10 seconds. But what I'd really like it to do is to do is slide in right from off canvas over 10 seconds and then float infinitely.
The code I have now just makes it float up and down and I'm struggling to add the slide in part. I'm new to CSS animation so I'd appreciate any help.
This is what I have so far.
.shake-vertical {
-webkit-animation: shake-vertical 15s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite both;
animation: shake-vertical 15s cubic-bezier(0.455, 0.030, 0.515, 0.955) infinite both;
}
#-webkit-keyframes shake-vertical {
0%,
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
10%,
30%,
50%,
70% {
-webkit-transform: translateY(-8px);
transform: translateY(-8px);
}
20%,
40%,
60% {
-webkit-transform: translateY(8px);
transform: translateY(8px);
}
80% {
-webkit-transform: translateY(6.4px);
transform: translateY(6.4px);
}
90% {
-webkit-transform: translateY(-6.4px);
transform: translateY(-6.4px);
}
}
#keyframes shake-vertical {
0%,
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
10%,
30%,
50%,
70% {
-webkit-transform: translateY(-8px);
transform: translateY(-8px);
}
20%,
40%,
60% {
-webkit-transform: translateY(8px);
transform: translateY(8px);
}
80% {
-webkit-transform: translateY(6.4px);
transform: translateY(6.4px);
}
90% {
-webkit-transform: translateY(-6.4px);
transform: translateY(-6.4px);
}
}
Considering your image has a class of ball. You can add this CSS to your Existing CSS:
#keyframes slide-in {
from{
margin-right: -100px;
}
to{
margin-right: 0;
}
}
.ball{
width: 100px;
height: 100px;
border-radius: 50%;
background-color: red;
float: right;
animation: slide-in 10s forwards,/*forwards keeps the ball at final position*/
shake-vertical 15s infinite 10s both;
/*
* Two animations applied
* comma separated
* shake-vertical has a 10 second delay specified by '10s'
* the delay should be same as the duration of first animation
*/
}
I have added comments for explanation but if you need more, feel free to comment.
You can set the object with a slidein animation for 10 seconds and on the animationend event change its class to your shake animation.
Add CSS something like this:
#keyframes slidein {
0% {
transform: translateX(100vw);
}
100% {
transform: translateX(50vw);
}
}
.slidein {
animation-name:slidein;
animation-duration:10s;
animation-fill-mode: follow;
}
.shake {
animation-name: shake-vertical;
animation-duration: 10s;
animation-iteration-count: infinite;
}
}
and JavaScript something like this
obj.addEventListener("animationend", function () {
obj.classList.remove('slidein');
obj.classList.add('shake');
});
Example with a simple sliding square in the Snippet.
<!DOCTYPE html>
<html>
<head>
<style>
#keyframes slidein {
0% {
transform: translateX(100vw);
}
100% {
transform: translateX(50vw);
}
}
#keyframes shake-vertical {
0%,
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
10%,
30%,
50%,
70% {
-webkit-transform: translateY(-8px);
transform: translateY(-8px);
}
20%,
40%,
60% {
-webkit-transform: translateY(8px);
transform: translateY(8px);
}
80% {
-webkit-transform: translateY(6.4px);
transform: translateY(6.4px);
}
90% {
-webkit-transform: translateY(-6.4px);
transform: translateY(-6.4px);
}
}
#obj {
position: relative;
width: 50px;
height: 50px;
top: 50px;
background-color:magenta;
animation-delay:0s;
}
.slidein {
animation-name:slidein;
animation-duration:10s;
}
.shake {
left: 50vw;
animation-name:shake-vertical;
animation-duration: 10s;
animation-iteration-count: infinite;
}
</style>
</head>
<div id="obj" class="slidein"></div>
<script>
var obj = document.getElementById('obj');
obj.addEventListener("animationend", function () {
obj.classList.remove('slidein');
obj.classList.add('shake');
});
</script>
</html>
I have a gear image rotating using keyframe spin of CSS. but I want to resize the width of the image less than the height like in the image (see gear image below).
Demo gear rotating
.gear {
position: absolute;
top: 10%;
left: 10%;
width: 120px;
height: 120px;
-webkit-animation: spin 4s linear infinite;
-moz-animation: spin 4s linear infinite;
animation: spin 4s 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);
}
}
<img class="gear" src="https://i.imgur.com/v1eydp4.png">
You can make use of the ScaleX transform value at various keyframe steps. It resizes at the last step to show you the difference in the size of it.
.gear {
position: absolute;
top: 10%;
left: 10%;
width: 120px;
height: 120px;
-webkit-animation: spin 4s linear infinite;
-moz-animation: spin 4s linear infinite;
animation: spin 4s linear infinite;
}
#-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
#-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: scaleX(0.5) rotate(360deg);
}
50% {
transform: scaleX(0.5) rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
<img class="gear" src="https://i.imgur.com/v1eydp4.png">
#m4n0's answer works well. An alternate approach to timing rotations is to simply wrap .gear with another element, and transform the containing element:
<div class="gear__wrapper">
<img class="gear" />
</div>
.gear__wrapper {
transform: scaleX(0.5);
}
It might be handy but if you are expecting something else, you might need to time the rotations and all.
I have only added the simple, please other prefixes.
.gear {
position: absolute;
top: 10%;
left: 10%;
width: 120px;
height: 120px;
-webkit-animation: spin 4s linear infinite;
-moz-animation: spin 4s linear infinite;
animation: spin linear 4s 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) scaleX(1);
}
50%{ transform: rotate(180deg) scaleX(0.5);
}
<img class="gear" src="https://i.imgur.com/v1eydp4.png">
I want an element to be animated like a swaying plant. I am looking to animate a div in the following manner.
Fix the bottom
Move the head back and forth
Looking for full css solution.
I have tried this,
#keyframes wiggle {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(-1deg);
}
50% {
transform: rotate(2deg);
}
75% {
transform: rotate(-0.4deg);
}
100% {
transform: rotate(1deg);
}
}
You can set transform-origin property to bottom.
.el {
margin: 30px 50px;
width: 0;
height: 0;
border-style: solid;
border-width: 150px 50px 0 50px;
border-color: #007bff transparent transparent transparent;
animation: wiggle infinite 3s alternate;
transform-origin: bottom;
}
#keyframes wiggle {
0% {transform: rotate(0deg);}
25% {transform: rotate(-3deg);}
50% {transform: rotate(5deg);}
75% {transform: rotate(-1deg);}
100% {transform: rotate(2deg);}
}
<div class="el"></div>
I have the following snippet of CSS:
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg);}
100% { -webkit-transform: rotate(360deg);}
}
#-moz-keyframes spin {
0% { -moz-transform: rotate(0deg);}
100% { -moz-transform: rotate(360deg);}
}
#-o-keyframes spin {
0% { -o-transform: rotate(0deg);}
100% { -o-transform: rotate(360deg);}
}
#-ms-keyframes spin {
0% { -ms-transform: rotate(0deg);}
100% { -ms-transform: rotate(360deg);}
}
#-keyframes spin {
0% { transform: rotate(0deg);}
100% { transform: rotate(360deg);}
}
header .spinner {
position: absolute;
width: 100%;
text-align: center;
margin: 0 auto;
left: 0;
-webkit-animation:spin 1s ease-out .5s;
-moz-animation:spin 1s ease-out .5s;
animation:spin 1s ease-out .5s;
transform-origin: 50%;
}
the animation runs fine, however the origin is slightly wrong making it look like the img is jumping when rotating.
I tried and wrote this code but it have a problem, first issue is text inside div will be fuzzy (fluffy)! and second scale animation not play softly, all i want is play animation softly, scale once then rotate infinite on hover.
#-webkit-keyframes socialspin {
from {
-webkit-transform: scale(2) rotate(0deg);
-moz-transform: scale(2)rotate(0deg);
-ms-transform: scale(2) rotate(0deg);
-o-transform: scale(2) rotate(0deg);
transform: scale(2) rotate(0deg);
}
to {
-webkit-transform: scale(2) rotateY(90deg);
-moz-transform: scale(2) rotateY(90deg);
-ms-transform: scale(2) rotateY(90deg);
-o-transform: scale(2) rotateY(90deg);
transform: scale(2) rotateY(90deg);
}
}
Here is JSFiddle Demo
The best way to have a smooth result is not to have a zoom in (scale=2) but a zoom out (scale=0.5), but of course in the opposite state.
And I don't believe that what you want can be achieved with a single animation. I have used 2 elements, and one handles the rotation and the other the scale
#container {
width: 400px;
height: 400px;
}
#container:hover {
-webkit-animation: socialspin 5s linear 0s infinite alternate;
}
#-webkit-keyframes socialspin {
from { -webkit-transform: rotate(0deg); }
to { -webkit-transform: rotateY(90deg); }
}
#keyframes socialspin {
from { transform: rotate(0deg); }
to { transform: rotateY(90deg); }
}
#base {
width: 400px;
height: 400px;
background: yellow;
transform: scale(0.5);
transition: transform 5s;
transform-origin: top left;
font-size: 200%;
}
#container:hover #base {
transform: scale(1);
}
<div id="container">
<div id="base">
<br>
<br>
<br>
HELLLLOOOO!!!
</div>
</div>
We cannot, as of yet, completely make the font clear. This is because you are using an animation. If there was no spinning, the text would not be fuzzy. However, we can try using several font smoothing properties to try and combat this. None of them are very good but they do improve legibility slightly.
Regardless, here is the fix for the second part:
I found a hack. This will remove the blur during the rotation but not during the scaling up.
.square {
width:100px;
height: 100px;
background-color:black;
margin: 50px;
}
p {
-webkit-font-smoothing: antialiased;
color:white;
text-align: center;
padding-top: 35px;
}
.square:hover {
-webkit-animation: scale 1s linear 0s 1, spin 1s linear 1s infinite alternate;
}
.square:hover p{
-webkit-animation: scaletext 1s linear 0s 1;
}
#-webkit-keyframes scale {
from {transform: scale(1); }
to{transform: scale(2);}
}
#-webkit-keyframes scaletext {
from {transform: scale(1); }
to{transform: scale(1);}
}
#-webkit-keyframes spin {
from {transform: rotateY(0deg) scale(2) ;}
to {transform: rotateY(90deg) scale(2);}
}
<div class="square">
<p>Some text</p>
</div>
(I removed the prefixes to condense the answer)
here is the example and the point is first to describe all features in the main div as defaults because animation uses main elements rules to calculate time etc.
and second point here you used 90 degrees to turn but a complete turning back can be done by 180 degrees which is the angle of a line
here is the code
--update--
here is the exxample you can see scale animates the problem was in your animation scaling started from 2 and ended by 2 so there was no animation for that
--update--
here we go if you run transition first and by the time while transition is running make animation wait by delay time of animation it works fine you can see here
div {
width: 200px;
height: 200px;
background: yellow;
-webkit-transform:scale(1) rotate(0);
transform:scale(1) rotate(0);
margin-left:200px;
margin-top:50px;
transition:-webkit-transform .5s linear;
transition:transform .5s linear;
}
div:hover {
-webkit-transform:scale(2) rotate(0);
transform:scale(2) rotate(0);
-webkit-animation: socialspin 5s linear .5s infinite alternate;
-moz-animation: socialspin 5s linear .5s infinite alternate;
}
#-webkit-keyframes socialspin {
from {
-webkit-transform: scale(2) rotate(0deg);
transform:scale(2) rotate(0deg);
}
to {
-webkit-transform: scale(2) rotateY(180deg);
transform: scale(2) rotateY(180deg);
}
}