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.
Related
The two blocks behave differently when applying tailwind's "rotate(**deg)" and vanilla css "transform: rotate(**deg)". Please just hover the blue blocks to reproduce.
https://play.tailwindcss.com/Rgf2GJ6mim
Since I sometimes use css in #layer utilities to write nested styles, so could someone please help me understand this? Big Thanks!!
Despite it looks like both examples do the same thing it's not quite true. Let's find out the difference. All classes in your example are same but the last one
hover:[transform:rotate(1020deg)] generates this
.hover\:\[transform\:rotate\(1020deg\)\]:hover {
transform: rotate(1020deg);
}
while hover:rotate-[1020deg] this
.hover\:rotate-\[1020deg\]:hover {
--tw-rotate: 1020deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
Or if you fill in Tailwind variables with its values it all comes to comparison between
.hover\:\[transform\:rotate\(1020deg\)\]:hover {
transform: rotate(1020deg);
}
// and
.hover\:rotate-\[1020deg\]:hover {
transform: translate(0, 0) rotate(1020deg) skewX(0) skewY(0) scaleX(1) scaleY(1);
}
We're forgot about one VERY important class - rotate-0. It actually sets the starting point of CSS transition
.rotate-0 {
--tw-rotate: 0deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
Just remove rotate-0 from both of your examples and now there is no difference in transition. So what is happening?
It all comes in CSS transition from state 1 to state 2. (Let's remove last
parts with skew and scale)
First example - from translate(0, 0) rotate(0deg) to rotate(1020deg)
Second - from translate(0, 0) rotate(0deg) to
translate(0, 0) rotate(1020deg)
MDN says
The transform functions are multiplied in order from left to right, meaning that composite transforms are effectively applied in order from right to left.
See example: red square just rotating. Yellow - rotates but returns back to default position even on hover we do NOT changing translate property. We're assuming it will left the same but this is not how CSS transition works. When there are multiple transform occurrence the last one will override previous. That's why translate is not applied anymore on hover - we're "erasing" it. In order to fix it we need to keep translate on hover (blue example)
.example {
width: 60px;
height: 60px;
margin: 40px;
transition: 1000ms;
}
.example-1 {
background-color: red;
transform: rotate(0);
}
.example-2 {
background-color: yellowgreen;
transform: translate(100px) rotate(0deg);
}
.example-3 {
background-color: blue;
transform: translate(100px) rotate(0);
}
.example-1:hover {
transform: rotate(45deg);
}
.example-2:hover {
transform: rotate(45deg);
}
.example-3:hover {
background-color: blue;
transform: translate(100px) rotate(45deg);
}
<div class="example example-1"></div>
<div class="example example-2"></div>
<div class="example example-3"></div>
And that's exactly what happening in your example - you are missing translate function in compiled CSS and changing the default state of transformed object (it is not transitioning anymore - it just places the new state). We need to keep the order of the chaining functions in transform property to ensure everything will work as expected
So, few ways to fix it in Tailwind keeping initial state (rotate-0 class), both requires to change hover:[transform:rotate(1020deg)] class
First - add missing translate function - change class into hover:[transform:translate(0,0)_rotate(1020deg)]
Second - not so obvious - change --tw-rotate variable value, basically convert class into hover:[--tw-rotate:1020deg]
And finally as I said - just remove initial state (rotate-0) but sometimes it is not an option
See examples
It's not the best explanation but I tried to point you in some direction where the difference comes from
How to create this kind of css animation where element fades in from the bottom but appears like clipped with overflow:
http://fr.creasenso.com/ (see the breadcrumb text)
I've tried all the basics but not going anywhere with translateY. Do I need to go to libraries or is it achievable with css only?
The wording of your question could use some improvement. But besides that, I think this is what you are looking for:
https://jsfiddle.net/5ws33c8s/
You need a parent element which has a overflow: hidden. Followed by the childs which are moved out using translate: translateY().
I then used css keyframes to move it back in:
animation: fadeInText 300ms 0ms forwards;
#keyframes fadeInText {
from {
transform: translateY(30px);
opacity: 0;
} to {
transform: translateY(0);
opacity: 1;
}
}
This animation is set up as follows; fadeInText is the keyframes name, 300ms is the duration of the animation, 0ms is the delay of said animation and forwards remembers the final state of the animation, and leaves the element as such. Without it, the element would jump back to its original values.
I then used a delay on each child element.
span:nth-child(2) {
animation-delay: 150ms;
}
I'm trying to combine several parts of animation together by clicking a button. Here's an example:
.element {
background-color: black;
display: block;
width: 160px;
height: 160px;
border-radius: 80%;
}
.one {
animation: one 1.5s ease 1 forwards;
}
.two {
animation: two 1s forwards;
}
#keyframes one {
from {
transform: scale(0.25);
opacity: 0;
}
25% {
opacity: 0.5;
}
to {
transform: scale(1);
opacity: 0.5;
}
}
#keyframes two {
from {
opacity: 0.5;
}
to {
opacity: 0;
}
}
I'm trying to combine these two animation: one and two. My way of doing this was to use JS: classList.add('.two') when I clicked the button. But the problem was: at the moment I added the class, the element changed to its default opacity which was 1.
To solve this, I added a new class contained styles which were actually clones of final styles of the first animation. And after the second part was finished, I had to remove the class list to prepared for the first animation to be played.
So my question is, is there a better way of doing this?
Here is a CodePen Demo
I just realised a problem with this: If I start the second animation before the first one was finished, there would be a discontinuity (the circle would just turns to a larger one all of a sudden).
The demo can be found from the above link, thanks!
Can I combine these two animations?
I assume by combine you mean producing forward (on click of add animation) and reverse (on click of remove animation) animations using the same keyframe rules. It's possible to achieve but for that both the forward and reverse animations should be exactly the same (but in opposite directions). When it is same, we can use animation-direction: reverse to achieve reverse effect with same keyframes.
Here, the forward animation has a transform change whereas the reverse doesn't and hence adding animation-direction: reverse would not produce the same effect as the original snippet. Moreover, coding it is not as easy as just adding a property also, a lot of work is needed like mentioned here.
What is the reason for the other two issues?
The reason for both the issues (that is, the element getting opacity: 1 immediately when the remove button is clicked and element getting full size when remove button is clicked while forward animation is still happening) are the same. When you remove the animation on an element (by removing the class) it immediately snaps to the size specified outside of the animation.
For the first case, the size is the one that is mentioned under .element (as .one is removed) and its opacity is default 1 because there is no opacity setting in it. For the second case, when the .one is removed and .two is added, the animation is removed and so the element's size is as specified in .element and the opacity is as specified in .two (because that is later in CSS file).
So what else is the alternate?
When both forward and reverse effects are required and the animation doesn't have any intermediate states (that is, there is only a start state and an end state) then it is better to use transitions instead of animations. The reason is because transitions automatically produce the reverse effect on removal of the class (unlike animations where the reverse animation needs to be written as a separate keyframe and added to the element).
Below is a sample snippet showing how you can achieve a similar effect using just one class without the need for writing keyframes.
var theBut = document.getElementById('butt');
var theBut2 = document.getElementById('butt2');
theBut.addEventListener('click', function a() {
document.querySelector('.element').classList.add('one');
});
theBut2.addEventListener('click', function b() {
document.querySelector('.element').classList.remove('one');
});
.element {
background-color: #d91e57;
display: block;
width: 160px;
height: 160px;
border-radius: 90%;
transform: scale(0.25);
opacity: 0;
transition: opacity 2s, transform .1s 2s;
}
.one {
transform: scale(1);
opacity: 0.5;
transition: all 2s;
}
<div class="element">
</div>
<button id="butt">add animation</button>
<button id='butt2'>remove animation</button>
Question: Why does my CPU register ~30% when blur is applied versus ~6% when no blur is applied to an animated object?
Details:
I have a set of randomly generated items on a page that have a CSS animation assigned (in a CSS file) and randomly generated values for width, height, and importantly, blur, applied inline.
CSS file styles looks like:
animation-name: rise;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: 1;
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform: translate3d(0,0,0);
transform: translateZ(0);
width, height and blur are applied inline via style attribute.
<div class="foo" style="width:99px;height:99px;
filter:blur(2px);
-webkit-filter:blur(2px) opacity(0.918866247870028);
-moz-filter:blur(2px) opacity(0.918866247870028);
-o-filter:blur(2px) opacity(0.918866247870028);
-ms-filter:blur(2px) opacity(0.918866247870028);"></div>
With the blur enabled my CPU usage is ~30%. When I disable the blur, CPU usage goes down to ~6%.
What's happening here? Is chrome only able to GPU accelerate when no blur is applied? If so, why?
Update 1:
The animation rise looks as follows:
#keyframes rise {
0% {
transform: translateY(0px);
}
100% {
transform: translateY(-1000px);
}
}
I don’t think the blur is actually causing your issues, it just seems to make it more noticeable than before. The problem is that the transform: translateY in your animation is overwriting the transform: translateZ(0) you’re using to force GPU acceleration.
This is a timeline recording for the the code you’re running right now, notice how there’s all this activity on the main and raster threads:
Now compare this to a recording where I applied will-change: transform to the .foo:
No activity on the main and raster whatsoever.
There’s two steps to applying this fix:
Apply will-change: transform to .foo. This will let the browser know you intend to change that property and have it render that element on the GPU to account for this.
No versions of Edge and IE support will-change at the moment. Therefore we’ll use transform: translate3d(0, -1000px, 0); in the animation to force GPU acceleration. Note this is a hack, so we’ll detect support for will-change and use transform: translateY in browsers that support it.
Final code:
#keyframes rise {
0% {
transform: translate3d(0, 0, 0);
}
100% {
transform: translate3d(0, 1000px, 0);
}
}
#supports (will-change: transform) {
#keyframes rise {
0% {
transform: translateY(0px);
}
100% {
transform: translateY(1000px);
}
}
}
div {
width: 100px;
height: 100px;
background: #f00;
animation: rise forwards 2s linear infinite;
will-change: transform;
}
See here for a working version: http://jsbin.com/mosuvikoto/edit?html,css,output
Don't blur it in inline styles. Put your blur in the style file.
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;