i'm working on a project where i have to render some components with an enter and leave animation, when a component enters the screen it has to enter form the bottom, and when it leaves, it has to do it going upwards, the desired behavior is that when i change the :is property of the component tag, the current component goes upwards and the next one comes from the bottom, the code looks like this:
<template>
<div class="home">
<transition name="section">
<component :is="activeSection"></component>
</transition>
</div>
</template>
<script>
import comp1 from './comp1';
import comp2 from './comp2';
export default {
components: {
comp1,
comp2
},
data() {
activeSection: 'comp1'
}
</script>
<style scoped>
.section-enter {
top: 100vh;
}
.section-enter-to {
top: 0vh;
}
.section-enter-active {
animation-name: 'slideIn';
animation-duration: 1s;
}
.section-leave {
top: 0vh;
}
.section-leave-active {
animation-name: 'slideOut';
animation-duration: 1s;
}
.section-leave-to {
top: -100vh;
}
#keyframes slideIn {
from {
top: 100vh;
}
to {
top: 0
}
}
#keyframes slideOut {
from {
top: 0vh;
}
to {
top: -100vh;
}
}
</style>
but the actual behavior is that the first component goes upwards but the second appears inmediatly after without animation.
if i render one at a time (not destructing one and rendering another with the same action) everything works perfectly. I dont know what is happening.
There are a few problems in your CSS.
CSS Transitions and CSS Animations
A transition can be implemented using either CSS Transitions or CSS Animations. Your CSS incorrectly mixes the two concepts in this case.
In particular, the slideIn keyframes and .section-enter/.section-enter-to rules are effectively performing the same task of moving .section into view. However, this is missing a transition rule with a non-zero time, required to animate the change, so the change occurs immediately. The same issue exists for the slideOut keyframes and leave rules.
.section-enter {
top: 100vh;
}
.section-enter-to {
top: 0;
}
.section-enter-active {
transition: .5s; /* MISSING RULE */
}
.section-leave {
top: 0;
}
.section-leave-to {
top: -100vh;
}
.section-leave-active {
transition: .5s; /* MISSING RULE */
}
Removing the keyframes, and adding the missing rules (as shown above) would result in a working CSS Transition.
demo 1
Using CSS Animations
Alternatively, you could use keyframes with CSS Animations, where the animation is applied only by the *-active rules, and no *-enter/*-leave rules are used. Note your question contained unnecessary quotes in animation-name: 'slideIn';, which is invalid syntax and would be silently ignored (no animation occurs). I use a simpler shorthand in the following snippet (animation: slideIn 1s;).
.section-enter-active {
animation: slideIn 1s;
}
.section-leave-active {
animation: slideOut 1s;
}
#keyframes slideIn {
from {
top: 100vh;
}
to {
top: 0;
}
}
#keyframes slideOut {
from {
top: 0;
}
to {
top: -100vh;
}
}
demo 2
Optimizing CSS Transitions
You could also tweak your animation performance by using translateY instead of transitioning top.
/* top initially 0 in .wrapper */
.section-leave-active,
.section-enter-active {
transition: .5s;
}
.section-enter {
transform: translateY(100%);
}
.section-leave-to {
transform: translateY(-100%);
}
demo 3
Use a Mixin
Thanks for the explanation #tony19
please use a mixin for this so the logic can be repeated easily.
Also, your slideIn and slideOut can be combined by using reverse:
#mixin animationmixin($type:'animation', $style:'', $duration:1s) {
#keyframes #{$type}-#{$style} { // register animation
0% { opacity: 1; transform: none; } // reset style
100% { #content; } // custom style
}
.#{$style} { // add '.section'
&-enter-active, &-leave-active { // add '.section-enter-active', ...
transition: #{$duration};
}
&-enter, &-leave-to {
animation: #{$type}-#{$style} #{$duration}; // use animation
}
&-leave, &-enter-to {
animation: #{$type}-#{$style} #{$duration} reverse; // use animation in reverse
}
}
}
Use it like this:
#include animationmixin($style:'section') { // set custom styling
transform: translateY(100%);
};
And like this:
#include animationmixin($style:'fade') {
opacity: 0;
transform: scale(0.9);
};
Related
Hi in my react project i need to create dynamic keyframes. I need to pass percent variable's value from jsx code. How can i do it? My SCSS Code :
:root {
--percent: 95%;
--dim: 0.75;
--period: 1s;
--delay: 1s;
}
$percent: 95%;
$dim: var(--dim);
$period: var(--period);
$delay: var(--delay);
#mixin animation($percent,$dim, $period, $delay) {
#keyframes blink {
#{$percent} {
opacity: 0
}
100% {
opacity: $dim
}
}
animation: blink $period infinite $delay ;
}
.MarkerWithId{
#include animation($percent, $dim, $period, $delay)
}
I tried to change the percent with JavaScript after page render but it didnt make any change.And I cant use var(--percent) for $percent
I tried adding the animation on a separate line without any condition, but than the transition is not applied. I also tried backticks instead of double quotes for the animation property without success.
How to have the both the animation applied when clicked is false and play the transition for the radius when clicked is true?
import { useState } from "react";
export default function Home() {
const [clicked, setClicked] = useState(false);
return (
<>
<main>
<svg onClick={() => setClicked((c) => !c)}>
<circle cx="50%" cy="40%" stroke="black" strokeWidth={2} fill="gray" />
</svg>
</main>
<style jsx>{`
svg {
width: 100%;
height: 100%;
}
circle {
r: ${clicked ? "10%" : "5%"};
animation: ${clicked ? "none" : "bounce 2s infinite"};
transition: r 0.8s ease-in-out;
}
#keyframes bounce {
0% {
r: 5%;
}
50% {
r: 6%;
}
100% {
r: 5%;
}
}
`}</style>
</>
);
}
This has to do with how styled-jsx applies their css rules.
each <style jsx> tag will be transpiled by babel into a piece of js code that will generate and keep track of an actual <style type="txt/css"/> tag in the html.
That tag will contain a unique ID, if you inspect that tag it will look something like this:
<style type="text/css" data-styled-jsx="">
svg.jsx-1097321267 {
width: 100%;
height: 100%;
}
circle.jsx-1097321267 {
r: 5%;
-webkit-animation: bounce 2s infinite;
animation: bounce 2s infinite;
-webkit-transition: r 0.8s ease-in-out;
transition: r 0.8s ease-in-out;
}
#-webkit-keyframes bounce-jsx-1097321267 {
0% {
r: 5%;
}
50% {
r: 6%;
}
100% {
r: 5%;
}
}
#keyframes bounce-jsx-1097321267 {
0% {
r: 5%;
}
50% {
r: 6%;
}
100% {
r: 5%;
}
}
</style>
Notice how the animation is also generated with the same ID.
bounce-jsx-1097321267.
Any static references/classes in the styles-jsx tag also get this id.
This is all done through babel at compile time.
The resulting js code will do all that referencing for you.
A problem arises when a assigning the css code dynamically.
It seems, that the ${clicked ? "none" : "bounce 2s infinite"}; rule fails to add the generated id to bounce animation name.
This might be by design or might be a bug, or simply a limitation in styled-jsx. IDK.
You have a couple of options to work around this,
probably the easiest way is the make the css style static, and add a class when new styling should be applied.
IE
circle {
r: 5%;
animation: bounce 2s infinite;
transition: r 0.8s ease-in-out;
}
.is-clicked {
animation: none;
r: 10%;
}
and applying a class to circle like
className={clicked && "is-clicked"}
, that way the animation name will be contain an id, and any rule using that animation will also receive the same id.
code sandbox for reference
I'm working on a carousel application and I have to use the React Transition Group to animate it. For some reason I can't seem to get the classes to apply correctly.
It's a mix of proprietary and open-source code, so if this example isn't enough I'm glad to expand my examples.
React render() calls this:
{this.props.slides.map((slide, index) => (
<CSSTransition
key={this.index}
in={this.appearHome}
appear={true}
timeout={600}
classNames="carouselTransition"
>
<CarouselSlide
key={index}
index={index}
activeIndex={this.state.activeIndex}
slide={slide}
/>
</CSSTransition>
))}
And then the css looks like this:
/* appear on page load */
.carouselTransition-appear {
opacity: 0;
z-index: 1;
}
.carouselTransition-appear.carouselTransition-appear-active {
opacity: 1;
transition: opacity 600ms linear;
}
.carouselTransition-enter {
opacity: 0;
z-index: 1;
}
.carouselTransition-enter.CarouselTransition-enter-active {
opacity: 1;
transition: opacity 300ms linear;
}
.carouselTransition-exit {
opacity: 1;
}
.carouselTransition-exit.carouselTransition-exit-active {
opacity: 0;
transition: opacity 300ms linear;
}
.carouselTransition-exit-done {
opacity: 0;
}
The appear css applies but as I cycle the carousel I can see the enter and exit classes falling off of the divs, never to return. My suspicion is that I'm doing something wrong with the key={index} which I've read is an antipattern, but I'm not sure how to fix it.
Again, if more code is needed, say the word!
It's a tricky thing to work with, as I've heard from pretty much everywhere I turned to for help. They need to work on the documentation and build out some better examples! In any case, the CSS simply had the right things in the wrong places. Specifically, what I was trying to do in the done state needed to be done in the active state, and the stuff I was trying to do in the active state needs to be done in the enter state.
.carouselTransition-appear {
opacity: 1;
}
.carouselTransition-appear.carouselTransition-appear-active {
}
.carouselTransition-enter {
transform: translateX(110%);
}
.carouselTransition-enter.carouselTransition-enter-active {
transition: transform 600ms ease-in-out;
transform: translateX(0);
}
.carouselTransition-enter.carouselTransition-enter-done {
}
.carouselTransition-exit {
transform: translateX(0);
}
.carouselTransition-exit.carouselTransition-exit-active {
transition: transform 600ms ease-in-out;
transform: translateX(-100%);
}
.carouselTransition-exit-done {
left: -10000px;
opacity: 0;
height: 0px;
}
I have a class which is just a simple green square. I have made a simple shaking animation but I have not managed to find a way to apply the animation on click. I have tried both jQuery and pure CSS solutions and nothing has worked so far.
The animation:
#keyframes hit {
40% {transform: scale(1,1);transform: rotateX(-20deg);transform: rotateY(20deg);transform:rotate(-5deg);}
60% {transform: scale(1.1,1.1);transform: rotateX(20deg);transform: rotateY(-20deg); }
And the class:
target-container {
animation-name: none;
animation-duration:0.3s;}
The closest I got to making it work was using this function:
function hitTarget() {
target.style.animationName="hit";
setTimeout(stopAnimation,300);
function stopAnimation() {
target.style.animationName="none";
}
}
target.addEventListener("click",function() {
hitTarget();},false);
A few issues with your code - not sure if they're a result of working them into the question, or part of your actual code. So let's go through them.
I think I had to fix some syntax errors in the CSS - missing closing } (bracket).
Also, to define multiple transforms just list all transforms in a single transform style. Like transform: rotate(2deg) scale(1.2).
Instead of passing an anonymous function which calls the hitTarget function, we'll pass the hitTarget function as the callback to the event listener.
Finally, instead of adding/removing the animation-name I'd recommend adding/removing a CSS class, which applies the animation.
Here it is all cleaned up and working:
function hitTarget(event) {
const animationClass = "withAnimation";
event.target.classList.add(animationClass);
setTimeout(stopAnimation, 300);
function stopAnimation() {
event.target.classList.remove(animationClass);
}
}
document.querySelector(".target-container").addEventListener("click", hitTarget, false);
#keyframes hit {
40% {
transform: scale(1, 1) rotateX(-20deg) rotateY(20deg) rotate(-5deg);
}
60% {
transform: scale(1.1, 1.1) rotateX(20deg) rotateY(-20deg);
}
}
.target-container {
width: 100px;
height: 100px;
background-color: green;
}
.withAnimation {
animation-name: hit;
animation-duration: 0.3s;
}
<div class="target-container"></div>
I'm trying to create a simple pulse effect by changing the background color using JQuery. However, I can't get the backgroundColor to animate.
function show_user(dnid) {
/* dnid is HTML ID of a div. */
if (! $(dnid).is(':visible')) {
$(dnid).show()
}
$('html, body').animate({scrollTop: $(dnid).offset().top});
$(dnid).animate({backgroundColor: "#db1a35"}, 1200);
}
What's strange is that this alternate animation works:
$(dnid).animate({opacity: "toggle"}, 1200);
But it's not what I want at all.
Additionally the show() and scroll functionality in the function work fine. It's just the background color animation that doesn't.
The function above is called by this link
Locate Me
Could someone help me animate the background color?
=========
Thanks everyone for the help. Lots of similar answers. Here's what I ended up with
In my header
<script src="http://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
Then in my show_user function right after the scroll animation.
var bgcol = $(dnid).css('backgroundColor');
$(dnid).animate({backgroundColor: "#db1a35"}, 2000);
$(dnid).animate({backgroundColor: bgcol}, 2000);
That gives a relatively quick red "pulse" that will draw the user's eyes.
Again, thanks for the help.
jQuery cannot animate colours by default. In order to animate colours, use the official jQuery.Color plugin.
All animated properties should be animated to a single numeric value, except as noted below; most properties that are non-numeric cannot be animated using basic jQuery functionality (For example, width, height, or left can be animated but background-color cannot be, unless the jQuery.Color() plugin is used).
Source
jQuery supports animation between any numeric CSS properties, which does not include colors. However, there are other libraries that make animating colors possible. One such library is the aptly-named jQuery Color. Its readme page shows several examples of how to use it to animate between colors using the jQuery .animate() function
Use the CSS animation property and keyframes
See it in action
HTML
<div></div>
CSS
div {
background-color: red;
height: 200px; width: 200px;
-webkit-animation: pulse 1s ease-in 0 infinite normal both;
-moz-animation: pulse 1s ease-in 0 infinite normal both;
-o-animation: pulse 1s ease-in 0 infinite normal both;
animation: pulse 1s ease-in 0 infinite normal both;
}
#-webkit-keyframes pulse {
0% { background-color: red; }
65% { background-color: #7F0093; }
100% { background-color: blue; }
}
#-moz-keyframes pulse {
0% { background-color: red; }
65% { background-color: #7F0093; }
100% { background-color: blue; }
}
#-ms-keyframes pulse {
0% { background-color: red; }
65% { background-color: #7F0093; }
100% { background-color: blue; }
}
#-o-keyframes pulse {
0% { background-color: red; }
65% { background-color: #7F0093; }
100% { background-color: blue; }
}
#keyframes pulse {
0% { background-color: red; }
65% { background-color: #7F0093; }
100% { background-color: blue; }
}
you must first set the background to the from color or it wont do anything 2nd time around.
You also typoed the css property 'background-color' and put it in quotes like i didn't :)
$(dnid).css({'background-color': "#ffffff"});
$(dnid).animate({'background-color': "#db1a35"}, 1200);
Just add this below your jQuery script and you are done:
<script src="https://cdn.jsdelivr.net/jquery.color-animation/1/mainfile"></script>