I have an external style sheet that contains transitions. When the page loads the transitions animate.
When I move the transitions from the external style sheet and place them in the header of my html file, the animations don't animate on page load (Which is what I want).
What can I do to stop the transitions from animating when placed in an external style sheet?
Here is some example css:
label {
font-size: 18px;
transition: all 0.2s ease-in-out;
}
When this is in a css file, the font goes from the page size to the css file size.
When this is in the header in a <style> tag it doesn't do anything.
This is because the stylesheets are loading synchronously, while the external sheets load asynchronously. When they load synchronously, transitions aren't triggered because the DOM only has to draw once; There's nothing to transition from. Meanwhile, the few milliseconds it takes to load a stylesheet externally requires the DOM to be redrawn again once it loads.
In this case, you should be using animations, not transitions. Animations will run on start no matter what.
#keyframes slide-in {
from {
opacity: 0;
width: 0%;
}
to {
opacity: 1;
width: 100%;
}
}
.animate-me {
background: red;
height: 100px;
color: white;
animation: slide-in 1s ease-in-out;
}
<div class="animate-me">animate me on load</div>
If you really do need transitions, you'll need some javascript to apply a class after at least one frame delay.
setTimeout(function() {
// apply class to elements
}, 0);
Related
I am animating a button. A class is assigned depending on my app state. This is actually implemented in Svelte as follows:
<div class="default"
class:run-animation="{$animate === true}">
But the equivalent in vanilla javascript without Svelte is:
let element = document... (find element)
element.classList.add("run-animation")
... later ...
element.classList.remove("run-animation)
For the sake of a minimum reproducible example, the classes I'm trying to animate/transition between look like this:
.default {
top: 20px;
color: white;
}
#keyframes button-animation {
from {
top: 20px;
color: white;
}
20% {
top: 23px;
color: white;
}
25% {
color: red;
}
100% {
top: 23px;
color: red;
}
}
.run-animation {
animation-name: button-animation;
animation-duration: 2s;
/* Preserve the effect of the animation at ending */
animation-fill-mode: forwards;
}
I add the class to the element, and the button animates just like I want it to. My problem arises when I remove the class. I want the button to transition smoothly back to the default CSS. I have tried adding the animation to the run-animate class:
.run-animation {
animation-name: ... ;
top: 23px;
color: red;
}
I have come across many people stating the transition upon class removal will apply if I add a transition property to the default class. I have tried this as follows:
.default {
...
transition: all 3s linear;
}
But it isn't working. The animation runs smoothly when it is added but the styling immediately reverts to the default when the class is removed (no smooth transition).
MY GOAL: I want to smoothly transition away from the end-state of the animation to the default class when the animate class is removed. Is this possible?
Ideally, I'm adding the class with the Svelte logic at the top so the animation should not be triggered in javascript but rather naturally occur as a result of class assignment.
(My code in practice is a little more complicated than shown, the button has another class with styles not being animated at all and the animation includes more styles such as box-shadow and text-shadow. Still, I don't see why this should be more problematic than just color and top included above)
// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {position: absolute; left: 120px}
div.default {
position: absolute;
width: 100px;
height: 100px;
background: darkgreen;
}
/* Above code to make a visible working example */
div.default {
top: 20px;
color: white;
transition: top 0.4s, color 0.1s 0.4s;
}
#keyframes define-animation {
from {
top: 20px;
color: white;
}
}
div.default.animation {
animation-name: define-animation;
animation-duration: 2s;
top: 24px;
color: red;
}
<div class="default">I'm colourful</div>
<button>Toggle ".animation"-class</button>
Above is a working snippet with an animation running on class addition and no reverse transition on class removal. I have tried setting animation direction to opposite values in .default and .animation. I have tried defining the .animate end state properties in the class and/or in the keyframes to attributes.
EDIT: It works now! How?
You cannot apply:
animation-fill-mode: forwards;
The end-attributes need to be defined in the animate class not in the keyframe.
The animation plays when the class is added. Transition timings are used when the class is removed (if the animation has completed).
To get a transition effect, you can use the transition-property.
The transition-property can be used here, since every property you want to animate only has a start- and end-value.
Translating animation-percentages to seconds
To translate the percentages of your CSS Animation button-animation to seconds, you just calculate 'percentage' * 'animation-duration'.
This works for both the transition-duration-property as well as for the transition-delay-property.
Example:
color is being animated from 20% to 25%, which is a duration of 5% with a delay of 20%.
All in all, the animation should take 2 seconds.
So we calculate for:
transition-duration: 5% * 2s = 0.1s
transition-delay: 20% * 2s = 0.4s
With that, we can add transition: color 0.1s 0.4s to the .default-class.
Why add it to .default, and not to .animation?
If we were to add the transition-property to .animation, the following would happen:
When adding .animation, there will be a transition-effect, since the element now has a transition-property defined.
But when removing .animation, the element would no longer have a transition-property defined, meaning there would be no transition.
Now, we want to transition on both adding and removing .animation, meaning we want to have a transition-property defined both when .animation is present and when it is not. That means, transition should not be defined in .animation.
// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {align-self: center}
div.default {
position: relative;
border: 2px solid black;
width: 100px;
height: 100px;
background: darkgreen;
}
/* Above code to make a visible working example */
div.default {
top: 20px;
color: white;
transition: top 0.4s, color 0.1s 0.4s;
}
div.default.animation {
top: 23px;
color: red;
}
<div class="default">Some text to see the "color"-property</div>
<button>Toggle ".animation"-class</button>
Why does it behave differently...
...when placing the properties inside the to-section of the animation, than when placing them inside .animation itself?
That is, because the properties are not directly applied to the element itself, but rather the element is stopped in its animation (right at the very end), giving only the appearance of the properties being actually applied.
Removing animation-fill-mode: forwards shows the actually applied properties after the animation has played. Those actually applied properties will be the start-values for transition after .animation is removed.
When defining these properties in .animation, they will inherently be the to-values for the animation (if not defined otherwise in animation itself), and be the applied properties of the element.
That means, when removing .animation, the transition will start from there.
CSS transitions animate back to the previous state, following the transition rules in reverse. But animations don't. They just go back to the original state abruptly (eg., when :hover or the class is removed). Is there a way to make animations behave like transitions (like the code below).
.box {
width: 50px;
height: 50px;
}
.box.transition {
background-color: green;
transition: 500ms linear all;
}
.box.transition:hover {
width: 100px;
height: 100px;
}
.box.animation {
background-color: red;
animation-duration: 500ms;
animation-fill-mode: both;
animation-timing-function: linear;
}
.box.animation:hover {
animation-name: zoom;
}
#keyframes zoom {
to {
width: 100px;
height: 100px;
}
}
<!-- If I "unhover" .box.animation, it goes back to the original state abruptly -->
<div class="box transition"></div>
<div class="box animation"></div>
Animation like transitions
Yes and no you can make them behave similarly but not identical, but not with :hover.
The hover state ends when you stop hovering an element. So when you stop hovering it, the css rule that targets :hover will instantly be removed.
Transition define what to do when there are changes to different states.
Animation go from one state to another defined by an animation.
Setting the animation direction will make it look closer to a transition.
animation-direction: alternate; will loop over an animation from start to finish and backagain.
I want to make a cursor that when you click, will change to one frame, then 0.5 seconds later, to the next, then back to how it before you clicked. The reason I need it to be css is that I am working on a css only project. I have tried using transition-delay, but you can't have multiple delays on the same property. I can make a cursor change to one frame when clicked, but no more. Here is the code for that:
body {
cursor: url(https://lh3.googleusercontent.com/BlETOnm98yPP5xCHbkFiFREFHNTQqucd_kFkfkYNKKnNohHvvnM7NTlLFq3rAukha0q-JEkouEgvfZnHkrhrzGIaps33RSJOuDV-_NiaPwSfn_cYbp5ayvFkYo4idwDkm-yb1G_jEwpY1zbrNtunux_oGFV-ADsdBVkK5qFqxj5OXMt3Qyw5GDkLgf5cdBHCK91go-7TkV8gT3zwbSWT8gi5tgFkY3UhyTM_X8E0FOU7uLOYBYDlTrEiIuIgqPEWOaj5MbH0j1j871KiLY65x4UsadJDzkpjT3mbfXgoMfDu4p3bE_I9a3Ck2MZq76RxKTH4iDHNwyz2hA0E0BXh2tsoq3mBQEH0h5ywIEDpNqMMQQ1HD33jfqX6TxZT48R6dGso6s4yGruWrMhn4CEwbvuNhOQYEO_r9e8WsIurKqU9bZ7Uiy3YdEtzgKG-sXHV5wJZQv8G0sr-utR9Cu8EzoYBHNdC2Yh-2eE8MAM0yS_15zKp-7igRo9RNhA_0TUkDgb8c4DQ4nC91VfylAA-elZKZtxDySI9U1ZCou1F8q42HJdD8A62CODQ2tlLJ3GMILtXQMM-T_JLhKzzg7gaTk8o9-E3pC5WVyh-yN9dSS-7sUqDBtUUF4bPWgg1WN2CbcJKXzDre_fBkw8hQ5Hzy_2Gp2LoMeSFB1c=s25-no), auto;
}
body:active {
cursor: url(https://lh3.googleusercontent.com/pg5NgqvH-ljQhDjHXV3EHSdX9jYo3_DP2S5r72qH53KZgHjLXBWZb5exYINk7zGA0Xl05TJ4vRdj6Yx1M4gNwLy4jDCjZ_ihsnmO_qDIh5GSxdemoWioqsNjBuR2dyhHy72bToMwv4XRm8a9Rul2hkh9WgpcFRgA8UDPV_D_wCOvxVw6QN6bR472ZQdjCy0QKvHmuzCbuTFnrMCScHJf8OiqJcjhlk04yvaeigm_TJgM8AAgcqtiMJ1MYH5ebI9O34-8HxSPrME47y_9jEN_RSgTPbKD77izoxx531jwIkYbJ5_bSD6NMFDsrub1hlmzexjblGs9bkoC8rbINmCHuUo-zHZaRW3cWkpx-tI4-XjVIgEeoDcwaL0IDOZop2t9aUfbmZQxng-kYVlNzSRwfkWwjAqwJJsS_68T7e7-W_mF1qbdL2BVbihpf8Vy7-8uXYlvHZbiqeiFfEsofThcGWopj8QwXN7Wqo4I8qX0bC7zJrao3UAFVwQ9ox80sWqeIXwJL4NoJs71x_v2GBPdFF74tyMptSL23oLv0c3PNREa2wkqxL1TFpg2VhwTFJRf=s25-no), auto;
}
I dont know what you exactly tried to achieve but this may help with what you try to do:
I basically used a keyframe to animate the other cursor and made the animation 2s so that it will turn back again to the state before.
body {
cursor: url(https://lh3.googleusercontent.com/BlETOnm98yPP5xCHbkFiFREFHNTQqucd_kFkfkYNKKnNohHvvnM7NTlLFq3rAukha0q-JEkouEgvfZnHkrhrzGIaps33RSJOuDV-_NiaPwSfn_cYbp5ayvFkYo4idwDkm-yb1G_jEwpY1zbrNtunux_oGFV-ADsdBVkK5qFqxj5OXMt3Qyw5GDkLgf5cdBHCK91go-7TkV8gT3zwbSWT8gi5tgFkY3UhyTM_X8E0FOU7uLOYBYDlTrEiIuIgqPEWOaj5MbH0j1j871KiLY65x4UsadJDzkpjT3mbfXgoMfDu4p3bE_I9a3Ck2MZq76RxKTH4iDHNwyz2hA0E0BXh2tsoq3mBQEH0h5ywIEDpNqMMQQ1HD33jfqX6TxZT48R6dGso6s4yGruWrMhn4CEwbvuNhOQYEO_r9e8WsIurKqU9bZ7Uiy3YdEtzgKG-sXHV5wJZQv8G0sr-utR9Cu8EzoYBHNdC2Yh-2eE8MAM0yS_15zKp-7igRo9RNhA_0TUkDgb8c4DQ4nC91VfylAA-elZKZtxDySI9U1ZCou1F8q42HJdD8A62CODQ2tlLJ3GMILtXQMM-T_JLhKzzg7gaTk8o9-E3pC5WVyh-yN9dSS-7sUqDBtUUF4bPWgg1WN2CbcJKXzDre_fBkw8hQ5Hzy_2Gp2LoMeSFB1c=s25-no), auto;
}
body:active {
animation: cursor 2s;
}
#keyframes cursor{
from{
}
to{
cursor: url(https://lh3.googleusercontent.com/pg5NgqvH-ljQhDjHXV3EHSdX9jYo3_DP2S5r72qH53KZgHjLXBWZb5exYINk7zGA0Xl05TJ4vRdj6Yx1M4gNwLy4jDCjZ_ihsnmO_qDIh5GSxdemoWioqsNjBuR2dyhHy72bToMwv4XRm8a9Rul2hkh9WgpcFRgA8UDPV_D_wCOvxVw6QN6bR472ZQdjCy0QKvHmuzCbuTFnrMCScHJf8OiqJcjhlk04yvaeigm_TJgM8AAgcqtiMJ1MYH5ebI9O34-8HxSPrME47y_9jEN_RSgTPbKD77izoxx531jwIkYbJ5_bSD6NMFDsrub1hlmzexjblGs9bkoC8rbINmCHuUo-zHZaRW3cWkpx-tI4-XjVIgEeoDcwaL0IDOZop2t9aUfbmZQxng-kYVlNzSRwfkWwjAqwJJsS_68T7e7-W_mF1qbdL2BVbihpf8Vy7-8uXYlvHZbiqeiFfEsofThcGWopj8QwXN7Wqo4I8qX0bC7zJrao3UAFVwQ9ox80sWqeIXwJL4NoJs71x_v2GBPdFF74tyMptSL23oLv0c3PNREa2wkqxL1TFpg2VhwTFJRf=s25-no), auto;
}
}
Maybe playing around with this will help you find your way to what you want to make.
I'm trying to make an image spin with a css transition. I have a transition: 2s transform linear; and transform: rotateY(720deg);.
You can see an attempt in this JSFiddle.
CSS
h1 {
font-size: 0px;
transition: 10s font-size;
transition: 2000s transform linear;
}
div {
position: relative;
top: 50%;
transform: translateY(-50%);
text-align: center;
}
HTML
<body background>
<div><img id="text" src="http://raritea.com/raritea/images/logo.ico"/></div>
</body>
JS
var init = function(){
document.getElementById('text').style.transform = 'rotateY(360000deg)';
}
This is a total stab in the dark, but as is often the case with these issues, the likelihood is that you have no initial state for this transition to work.
Add something like this to your non-transitioned state:
.my-non-transitioned-state {
transform: rotateY(0deg);
transition: transform 2s linear;
}
.my-transitioned-state {
transform: rotateY(270deg);
}
And it should work. transition is a mathematically computed tag, and needs two numeric values to work. Thus, if you only give it one state, it can't transition. Or, if you give it a non-numerical state (like background-size: cover, for example), it won't work.
Ensure that your transition has both an initial and a destination state, and this should work.
Edit: A working fiddle
So, there's one additional thing to consider when you're adding these styles via JavaScript.
Order-of-operations for page rendering:
The super-simplified order of operations for page rendering:
Scripts in <head> run
DOM loaded
Scripts appended at end of <body> run
CSS applied
Late-bound script operations
Adding setTimeout (even with a time for 0) pops your JS call from step 1 to step 5, which is why the fiddle works.
I am trying to make some text fade to a new colour and then back to it's original colour.
#sidebar2:target .phonenumber {
-o-transition:0.7s;
-ms-transition:0.7s;
-moz-transition:0.7s;
-webkit-transition:0.7s;
transition:0.7s;
color: yellow;
}
Currently it just goes to the new colour and stays like that. How can I adapt this code so that is does what I want? Any help is appreciated!
EDIT:
I am using :target so that when a user clicks on a same page link, the part of the text that I'm linking to is highlighted. I would like the text to fade to a different colour and then back again
I'm fairly certain it is not possible to loop a transition, you are able to transition from one state to another but not back again in a single transition.
To achieve the result you are looking for you would use an animation instead.
First set up the animation keyframes:
#keyframes glowyellow {
0% { color: auto; }
50% { color: yellow; }
100% { color: auto; }
}
Then to use this on your element:
#sidebar2:target .phonenumber {
animation: glowyellow 1.4s linear;
}
Use vendor prefixes to support browsers as you are doing in your example.
Here is a fiddle as an example.
Do you mean something like this?
Demo
span {
color: #000;
transition: color 1s;
/* Not using proprietary codes here, you can add it if you need */
}
span:hover {
color: #aaa;
}
8 years late, but there is a "psudo-selector" for visited links: :visited
(It's actually a pseudo class)
Just modify the attributes you want from there. No need for animation and transitions.