I'm working on CSS and web development,but just face a something which i really don't understand it:
.header{
position: absolute;
width:60%;
top: 20%;
left: 50%;
transform: translateX(-50%);<------ executed after animation
text-align: center;
animation: moveUp 2s;
animation-fill-mode: backwards;
}
#keyframes moveUp{
0%{
opacity: 0;
transform:translateY(2rem);
}
100%{
opacity: 1;
transform: translateY(0rem);
}
}
so my problem here is the indicated line doesn't apply on ".header" until the animation gets applied in other word it applies animation first then translate -50% ,is there a priority of execution here or it is different thing?
Usually the styles are parsed from top to bottom, however this isn't the issue here.
What is happening in your case is the transform is being applied initially, but then it is being overridden by the animation. Once the animation is over, the element is reverting back to its default style which has the transform.
Essentially, even though the transform is applied at first, you don't see it until the element reverts to it after the end of the animation.
The only solution if you want to have the transform during the animation, is to include it in the animation itself.
#keyframes moveUp {
0 % {
opacity: 0;
transform: translate(-50%, 2rem);
}
100 % {
opacity: 1;
transform: translate(-50%, 0);
}
}
EDIT: To clarify, the order at which the styles are applied does not matter. Whether the animation or the transform is applied first, the result will be the same.
I think a source of your confusion is that the first transform is a translateX while the animation only does translateY. In both cases what is changing is the value of the transform property of the element. Therefore which axis the translation is on doesn't matter. First you set transform: translateX(-50%), but then once the animation kicks in, transform becomes translateY(2rem). The translateX part is removed from the transform, unless you include it in the animation like I have shown.
I am having an issue with Chrome (v. 67) at OSX and movement animations. I've prepared JS fiddle with it:
https://jsfiddle.net/5m173ghv/31/
If you open it at safari it is working very good. But, when you will use chrome it has little lags when moving.
I cannot describe it a bit more... You need to open it and try yourself on the big screen... Please look carefully at white box. You will see that this box has sometimes something like lags or small jumps(?)...
This is very weird. I've tried almost every answer from the internet (trust me ;) ).
I also tried:
Change transforms at animation into position (left)
Change animations into transitions
adding additional parameters (backface-visibility, perspective, will-change...)
Changing sequences of animation to have more steps (per 10%)
Debugging on chrome dev tools (~30-40fps)
Adding transforms like translateZ(0)
You think that this is chrome bug or maybe my fault? Do you have any solution for that?
Here you have code:
HTML
<span class="spark"></div>
SCSS
body {
background-color: black;
}
#keyframes left-to-right {
0% {
transform: translate3d(0,0,0);
}
100% {
transform: translate3d(50vw,0,0);
}
}
.spark {
position: absolute;
top: 30px;
width: 322px;
height: 500px;
background-color: white;
transform: translate3d(0,0,0);
backface-visibility: hidden;
perspective: 1000px;
animation: left-to-right 5s infinite linear;
will-change: transform;
pointer-events: none;
user-select: none;
}
I'd like a 60fps or better opacity transition and am testing with Chrome dev tools timeline. I've created a jsfiddle (http://jsfiddle.net/jnoody/Zt8nd/) to demonstrate, but basically it's just a div that has a class toggled every few seconds and transitions on opacity for the two states. It looks fine to the eye, but I've been led to believe 60fps should be achievable.
HTML:
<div id="fader"></div>
CSS:
#fader {
height: 1000px;
width: 1000px;
background-color: grey;
opacity: 1;
transition: 1s opacity;
}
#fader.fadeOut {
opacity: 0;
transition: 1s opacity;
}
JavaScript:
var fader = document.getElementById('fader');
setInterval(function () {
fader.classList.toggle('fadeOut');
}, 2000);
I've tried the null transform hack, too, but either way it appears to be in its own layer (using "render composited border layers").
Not really sure if that helps, but I do get 60fps in the fiddle, going full window (that is appending /show to the fiddle)
There is only one moment where the frame rate drops, but I believe it's when the javascript executes (so, nothing to do with posible GPU acceleration)
I have some CSS that on hover, a CSS transition effect will moves a div.
The problem, as you can see in the example, is that the translate transition has the horrible side effect of making the image in the div move by 1px down/right (and possibly resize ever so slightly?) so that it appears out of place and out of focus...
The glitch seems to apply the whole time the hover effect is applied, and from a process of trial and error I can safely say only seems to occur when the translate transition moves the div (box shadow and opacity are also applied but make no difference to the error when removed).
The problem only seems to happen when the page has scrollbars. So the example with just one instance of the div is fine, but once more identical divs are added and the page therefore requires a scrollbar the problem strikes again...
2020 update
If you have issues with blurry images, be sure to check answers from below as well, especially the image-rendering CSS property.
For best practice accessibility and SEO wise you could replace the background image with an <img> tag using object-fit CSS property.
Original answer
Try this in your CSS:
.your-class-name {
/* ... */
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1, 1);
}
What this does is it makes the division to behave "more 2D".
Backface is drawn as a default to allow flipping things with rotate
and such. There's no need to that if you only move left, right, up, down, scale or rotate (counter-)clockwise.
Translate Z-axis to always have a zero value.
Chrome now handles backface-visibility and transform without the -webkit- prefix. I currently don't know how this affects other browsers rendering (FF, IE), so use the non-prefixed versions with caution.
You need to apply 3d transform to the element, so it will get its own composite layer.
For instance:
.element{
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
or
.element{
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
More about layer creation criteria you can read right here: Accelerated Rendering in Chrome
An explanation:
Examples (hover green box):
Problem: Transition may cause blink effect on sibling elements (OSx Lion, Chrome 30)
Solution: An element on its own composite layer
When you use any transition on your element it cause browser to recalculate styles, then re-layout your content even if transition property is visual (in my examples it is an opacity) and finaly paint an element:
The issue here is re-layout of the content that can make an effect of "dancing" or "blinking" elements on the page while transition happens.
If you will go to settings, check "Show composite layers" checkbox and then apply 3d transform to an element, you will see that it gets it's own layer which outlined with orange border.
After element gets its own layer, browser just needs to composite layers on transition without re-layout or even paint operations so problem have to be solved:
Had the same problem with embeded youtube iframe (Translations were used for centering iframe element). None of the solutions above worked until tried reset css filters and magic happened.
Structure:
<div class="translate">
<iframe/>
</div>
Style [before]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
}
Style [after]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
filter: blur(0);
-webkit-filter: blur(0);
}
I recommended an experimental new attribute CSS I tested on latest browser and it's good:
image-rendering: optimizeSpeed; /* */
image-rendering: -moz-crisp-edges; /* Firefox */
image-rendering: -o-crisp-edges; /* Opera */
image-rendering: -webkit-optimize-contrast; /* Chrome (and Safari) */
image-rendering: optimize-contrast; /* CSS3 Proposed */
-ms-interpolation-mode: nearest-neighbor; /* IE8+ */
With this the browser will know the algorithm for rendering
Just found another reason why an element goes blurry when being transformed. I was using transform: translate3d(-5.5px, -18px, 0); to re-position an element once it had been loaded in, however that element became blurry.
I tried all the suggestions above but it turned out that it was due to me using a decimal value for one of the translate values. Whole numbers don't cause the blur, and the further away I went from the whole number the worse the blur became.
i.e. 5.5px blurs the element the most, 5.1px the least.
Just thought I'd chuck this here in case it helps anybody.
I cheated problem using transition by steps, not smoothly
transition-timing-function: steps(10, end);
It is not a solving, it is a cheating and can not be applied everywhere.
I can't explain it, but it works for me. None of another answers helps me (OSX, Chrome 63, Non-Retina display).
https://jsfiddle.net/tuzae6a9/6/
Scaling to double and bringing down to half with zoom worked for me.
transform: scale(2);
zoom: 0.5;
Try filter: blur(0);
It worked for me
I've tried around 10 possibly solutions. Mixed them up and they still didn't work correctly. There was always 1px shake at the end.
I find solution by reducing transition time on filter.
This didn't work:
.elem {
filter: blur(0);
transition: filter 1.2s ease;
}
.elem:hover {
filter: blur(7px);
}
Solution:
.elem {
filter: blur(0);
transition: filter .7s ease;
}
.elem:hover {
filter: blur(7px);
}
Try this in fiddle:
.blur {
border: none;
outline: none;
width: 100px; height: 100px;
background: #f0f;
margin: 30px;
-webkit-filter: blur(10px);
transition: all .7s ease-out;
/* transition: all .2s ease-out; */
}
.blur:hover {
-webkit-filter: blur(0);
}
.blur2 {
border: none;
outline: none;
width: 100px; height: 100px;
background: tomato;
margin: 30px;
-webkit-filter: blur(10px);
transition: all .2s ease-out;
}
.blur2:hover {
-webkit-filter: blur(0);
}
<div class="blur"></div>
<div class="blur2"></div>
I hope this helps someone.
For me, now in 2018. The only thing that fixed my problem (a white glitchy-flicker line running through an image on hover) was applying this to my link element holding the image element that has transform: scale(1.05)
a {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
transform: translateZ(0) scale(1.0, 1.0);
-webkit-filter: blur(0);
filter: blur(0);
}
a > .imageElement {
transition: transform 3s ease-in-out;
}
None of this worked, what worked for me is scaling image down.
So depending on what size you want the image or what resoultion your image is, you can do something like this:
.ok {
transform: perspective(100px) rotateY(0deg) scale(0.5);
transition: transform 1s;
object-fit:contain;
}
.ok:hover{
transform: perspective(100px) rotateY(-10deg) scale(0.5);
}
/* Demo Preview Stuff */
.bad {
max-width: 320px;
object-fit:contain;
transform: perspective(100px) rotateY(0deg);
transition: transform 1s;
}
.bad:hover{
transform: perspective(100px) rotateY(-10deg);
}
div {
text-align: center;
position: relative;
display: flex;
}
h3{
position: absolute;
bottom: 30px;
left: 0;
right: 0;
}
.b {
display: flex;
}
<center>
<h2>Hover on images</h2>
<div class="b">
<div>
<img class="ok" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Sharp</h3>
</div>
<div>
<img class="bad" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Blurry</h3>
</div>
</div>
</center>
The image should be scaled down, make sure you have a big image resoultion
I had a similar problem with blurry text but only the succeeding div was affected. For some reason the next div after the one that I was doing the transform in was blurry.
I tried everything that is recommended in this thread but nothing worked.
For me rearranging my divs worked. I moved the div that blurres the following div to the end of parents div.
If someone know why just let me know.
#before
<header class="container">
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
<div class="affected div">
</div>
</header>
#after
<header class="container">
<div class="affected div">
</div>
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
</header>
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration
I was helped by setting the value of transition duration .3s equal transition timing steps .3s
The blurring occurred for me in Chrome only (Windows and Mac) when animating 'transform' in a keyframe animation. For me, the -webkit-optimize-contrast setting only partially helped. For best results I also had to use a "magic value" for scaleX (slightly larger than 1 instead of 1).
Here's the code that worked:
img {
image-rendering: -webkit-optimize-contrast;
}
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1.000001);
opacity: 1;
}
}
Here's the code that didn't work (caused blurry images in Chrome):
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1);
opacity: 1;
}
}
In the end, the "working" code removed most of the blurring, but not all of it. Safari and Firefox were still clearer without any special settings.
Note also that just resizing the browser window cleared up the unwanted blurring, suggesting perhaps that something is causing Chrome to fail to execute a final render pass (?).
I have a case where I need an element to appear for a second and then disappear, and I must not use javascript for it, so I'm trying to make it work with CSS.
Here's an example:
#-webkit-keyframes slide-one-pager {
0% { left: 0; }
50% { left: 100px; }
100% { left: 0; }
}
So in this example the property will gradually transition from 0 to 100 and back to 0. However, I need to get rid of that transition, so the property stays at 0 and gets to 100 as soon as it hits 50%. It doesn't work if I say left: 0; at 49%, because there is still a transition.
Another example, slightly more different than my original question, but if I find a solution for it it will do as well:
#-webkit-keyframes slide-one-pager {
0% { display: none; }
50% { display: block; }
75% { display: block; }
100% { display: none; }
}
Here I want to show an element for a period of time. No, using opacity is not an option, because the element is still there and is still clickable, and I need access to elements below. Unfortunately the "display" property doesn't seem to accept animating. If anyone can think of a solution how to show and hide an element with an animation (without transition!) I will be extremely grateful.
Any ideas?
You can use step-start or step-end (graphs) in your animation configuration so the curve will act like a "steps" (not curvy) so there will be no visual transition between frames, thus the animation will just "jump" between frames.
Example CSS:
animation:1s move infinite step-end;
The above example will call the move keyframes (which I didn't write because it's irrelevant), and will loop on the frames endlessly with the "step" argument which was described earlier, without a transitioned curve.
#keyframes foo{
0%{ margin-left:0 }
50%{ margin-left:50% }
}
div{
width: 50px;
height: 50px;
background: black;
border-radius: 50%;
animation:1s foo infinite;
}
input:checked + div{
animation-timing-function: step-end;
}
<label>
<input type='checkbox' checked /> Disable Animation transition
<div></div>
</label>
👉 Cool demo using this technique
I searched the same thing as you actually.
You can set a greatful parameters in animation, called animation-timing-function allowing you to set perfectly and mathematicaly the animation : With bezier curve values or, if, like me, you're not that good mathematician, a parameter call "step()".
For an example, in none shorthand writing :
.hiding {
animation-name:slide-one-pager;
animation-duration:2s;
animation-timing-function:steps(1);
}
By default, the value of this parameter is set to 0, meaning no steps.
You can read more about this interesting feature here : https://developer.mozilla.org/en-US/docs/Web/CSS/timing-function
And here a shorthand notation for your animation:
.hiding {
animation:slide-one-pager 2s steps(1);
}
For me, it works fine at least on firefox 23.0.1.
Even if I think you solved the problem since one year, maybe could help some people like me here :)
I made it using the -webkit-animation-fill-mode: forwards; property, that stops the animation at 100% without returning the element to the original state. I made up a fiddle with a working example, you can check it out here.
Although in the fiddle you can find a better example, I basically did this (Assuming absolute positioned elements):
.hiding {
-webkit-animation: slide-one-pager 2s;
-webkit-animation-fill-mode: forwards;
}
#-webkit-keyframes slide-one-pager {
0% { left: 0; }
49% { left: 0; }
50% { left: -100px; }
100% { left: -100px; }
}​
It just jumps from 0 to -100 in the middle of the transition (49% -> 50% as you 'suggested' :P), and stays there at 100%. As said, with -webkit-animation-fill-mode: forwards; the element will stay as in 100% without going back to it's original state.
I don't know if it'll work in your scenario, but I believe there'd be an easy solution if it doesn't.
You can use this:
animation: typing 1s cubic-bezier(1,-1, 0, 2) infinite;