Vue.js animation: Enter after Leave and not simultaneously - vue.js

I have two components and a fade-in/fade-out animation set up for them.
For a brief moment, both components exist on the page at different opacities, and the scrollbar shows up and disappears.
Is there a way to avoid this? A way to start the fade-in animation only after the fade-out animation is done?
The Animation:
.view-leave-active {
transition: opacity 0.5s ease-in-out, transform 0.5s ease;
}
.view-enter-active {
transition: opacity 0.5s ease-in-out, transform 0.5s ease;
transition-delay: 0.5s; /* Increasing this doesn't seem to work */
}
.view-enter, .view-leave-to {
opacity: 0.5; /* It should be 1, but setting it to 0.5 allows you to see exactly what's happening */
}
.view-enter-to, .view-leave {
opacity: 1;
}
Any help would be very much appriciated!

To further elaborate on my comment: VueJS transition components support the mode property, where you can specify the sequence of transitions when toggling between two elements.
Since you do not want both elements to appear at the same time when one is transitioning in while the other is transitioning out, you should be using:
mode="out-in"
Based on the documentation:
out-in: Current element transitions out first, then when complete, the new element transitions in.

Related

Safari opacity animation sometimes fails

update: I've found a workaround for this, see my own answer.
I have an animation that crossfades back and forth between two images, by changing the opacity of one image that is placed directly on top of the other.
Symptoms:
It works fine it all browsers.
It occasionally stops working after a while in Safari - typically permanently stuck on the opening image, or you see two or three frames midway through the fade with the rest skipped, occasionally you'll get a flash between the two states without any animation.
Occurs significantly more frequent on mobile. Either way always cleared by restarting the browser, but often not by reloading tabs. Sometimes fixed by navigating a new page then using the back button.
I've used will-change: opacity on both images, it doesn't help.
I didn't notice this problem when I was animating the same graphics by changing a single background image URL - but the problem with that was it's not supported in Firefox…
The images are scaled down in the browser - the full size is 1200x1200 in a frame roughly 400x400 - though that doesn't seem excessive, and they've been compressed.
They need to be within a grid because of the layout of the rest of the page (using position: absolute wouldn't give them height.)
Simplified HTML and CSS:
#keyframes crossfade {
0% {
opacity: 0;
}
33.3% {
opacity: 1;
}
66.6% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<img class="start-frame" src="square-start-1200.jpg">
<img class="end-frame" src="square-end-1200.jpg">
/* within a div that has display: grid... */
img {
grid-column: 1;
grid-row: 1;
will-change: opacity;
}
img.start-frame {
z-index: 1;
}
img.end-frame {
/* placed on top of the start image, but needs to be hidden to begin with */
opacity: 0;
z-index: 2;
animation: crossfade linear 20s;
animation-iteration-count: infinite;
}
#### Affected browsers
Safari 14.1.2 on Mojave 10.14.6
iPhone 6S with iOS 14.7.1
iPad Mini 5th Gen with iOS 14.7.1
iPod Touch 7th Gen with iOS 13.7
A workaround - run the animation in reverse:
animation-direction: reverse;
As it's symmetrically in this case, it doesn't matter.
I can't explain it, but touch wood this has proved stable on Safari 14.1.2 on Mojave, and on both iOS 13 (iPod) and iOS 14 on (iPhone and iPad) in normal daily use, with backgrounding the tabs, refreshing them, sleep/wake cycles etc.
I did also try making the animation start at 5% rather than 0 (i.e. having opacity: 0 at both the 0% and 5% marks, but was only changing the direction that seemed to have an immediate effect.)
Adding animation-delay (in the hope dropped/stuttering frames might be somehow related to an image that hadn't finished loading) didn't help either.
You can try with webkit property I think It works Fine check below Ex.
img {
grid-column: 1;
grid-row: 1;
will-change: opacity;
}
img.start-frame {
z-index: 1;
}
img.end-frame {
opacity: 0;
z-index: 2;
-webkit-animation: crossfade linear 20s infinite;
animation: crossfade linear 20s infinite;
}

bootstrap modal scale and translate

My bootstrap modal has animation with translate.
.modal.in .modal-dialog {
-webkit-transform: translate(0, 0);
-ms-transform: translate(0, 0);
-o-transform: translate(0, 0);
transform: translate(0, 0);
}
So bootstrap modal fade from top to middle. Everything works fine, but transition is reset when i want to apply scale for this modal like :
.modal.in .modal-dialog {
transform: scale(1.5)
}
so it's okay that my scale reset my translate so i apply mutliple transform conditions :
.modal.in .modal-dialog {
transform: scale(1.5) translate(0,0)
}
but in that case my modal behave like translate and scale in same time and the effect is like zoomIn.
How can i apply that modal dialog is first scale and then on scaled modal apply transition from top to middle ?
Please help !
What you are looking for are so called "keyframes" (if you want to know more, have a look here).
I created a fiddle and tested it shortly: Modal example with keyframes
The following code handles the transformations (scale and translate)
#keyframes mymove {
0% {transform: scale(1);}
50% {transform: scale(1.2);}
100% {transform: scale(1.2) translate(0, 100px);
}
Then you call "animation" instead of "transition" to make the keyframe work like this:
animation: mymove 2s ease-out;
Once the animation is finished, the state of the modal will go back to normal (no scale, no transition) - that's why we have to add the following line:
transform: scale(1.2) translate(0, 100px);
Hope this helps!

How to get the nth element of #rest in Less? [duplicate]

I currently have -webkit specific attributes in my Less CSS sheet, I am trying to update them with mixins to add -moz attributes, like this:
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
div {
.transition(all .5s);
}
The example above works fine, however I also have things like that:
div {
-webkit-transition: border-color .3s, background .3s;
}
And I can’t call the mixin as .transition(border-color .3s, background .3s) because it has more arguments than defined in the mixin. So what I am doing at the moment is this:
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
.transition-2(#1, #2) {
-webkit-transition: #1, #2;
-moz-transition: #1, #2;
}
div {
.transition-2(border-color .3s, background .3s);
}
This is annoying, I need to add redundant code in my sheet any time I’m using a number of arguments not previously used before; and I have this problem with others CSS3 properties too, for example box-shadow when I need to add inset at the beginning.
Is there any way to declare mixins flexible in their number of arguments with Less, just like CSS3 properties are?
For this case, the redundant mixin code can be avoided using any one of the below mentioned options.
Option 1: (Simplest solution - thanks to seven-phases-max for highlighting the miss)
We can use semi-colon as a separator/delimiter for arguments and when we add a semi-colon at the end after specifying all properties that need to be transitioned (in a comma separated format), the whole part before it would be considered as one single argument.
Extract from the official Less website:
Using comma as mixin separator makes it impossible to create comma separated lists as an argument. On the other hand, if the compiler sees at least one semicolon inside mixin call or declaration, it assumes that arguments are separated by semicolons and all commas belong to css lists
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
div{
.transition(border-color .5s, background .3s, color .3s;);
}
So the above code when compiled would result in
div {
-webkit-transition: border-color 0.5s, background 0.3s, color 0.3s;
-moz-transition: border-color 0.5s, background 0.3s, color 0.3s;
}
Option 2:
Pass the input values to the mixin (how many ever specific properties need to be transitioned) within quotes. Within the mixin, use the ~ or the e() in-built functions to strip the quotes.
.transition(#1) {
-webkit-transition: ~"#{1}";
-moz-transition: ~"#{1}";
}
div {
.transition("border-color .5s, background .3s");
}
div#sample2 {
.transition("border-color .3s, background .3s, color .3s");
}
will produce the below CSS when compiled
div {
-webkit-transition: border-color .5s, background .3s;
-moz-transition: border-color .5s, background .3s;
}
div#sample2 {
-webkit-transition: border-color .3s, background .3s, color .3s;
-moz-transition: border-color .3s, background .3s, color .3s;
}
Option 3:
Less does allow creation of mixins which allow/accept variable number of inputs using the ... option. Hence you can use the same mixin as in your original code by adding the ... to the input variable and calling it as you had originally wanted.
.transition(#args...) {
-webkit-transition: #args;
-moz-transition: #args;
}
div {
.transition(border-color .5s, background .3s);
}
The above will compile successfully but the only problem is that it would produce the below output when compiled. As you can see, the problem is that the parameter values are space separated and not comma separated (as they should be for the CSS to work properly).
div {
-webkit-transition: border-color 0.5s background 0.3s;
-moz-transition: border-color 0.5s background 0.3s;
}
Ofcourse we could write complex replace functions using regular expressions but that would really make the code messy. Instead we could use loops and some built-in functions to achieve the required output (like shown below).
.transition(#args...) {
.loop-args(#argCount) when (#argCount > 0) {
.loop-args(#argCount - 1);
#arg: extract(#args, #argCount);
-webkit-transition+: #arg;
-moz-transition+: #arg;
}
.loop-args(length(#args));
}
div {
.transition(border-color .5s, background .3s, color .3s);
}
Basically what we are doing is use the ... to accept multiple arguments as input to the mixin and then loop over each argument and add it to the CSS property's value. The +: (merge function introduced in Less v1.5.0) is used to produce the comma separated output.
When compiled, it would produce the below output:
div {
-webkit-transition: border-color 0.5s, background 0.3s, color 0.3s;
-moz-transition: border-color 0.5s, background 0.3s, color 0.3s;
}
You could try
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
.transition-2(#1, #2) {
.transition(#1); // this includes all the stuff from transition(#1)
color:red; // additional stuff
}
As for your actual question, I dont believe that LESS itself has any sort of "rest" style arguments passing.

Controlling rotation axis with webkit 3d transform

I'm creating a card-flip effect using webkit transformations. I have it working as I like in one section, where I have a DIV that rotates around its center axis giving the look of a card that is flipping over.
I now want to add this same effect to a page transition. I'm using the same CSS and HTML structure, but in this case I'm not getting an effect that rotates around a center axis.
Instead, it looks like the transformation is rotating along the y axis anchored to the left of the object rather than the center (so it looks like a door opening, rather than a card flipping).
I've been reading through the spec's but can't figure out which property controls the rotation axis' position. What do I need to add or change with this to get the flip working?
html structure:
<div id="frontbackwrapper">
<div id="front"></div>
<div id="back"></div>
</div>
and the css (.flip is being added via jQuery to start the effect)
#frontbackwrapper {
position: absolute;
-webkit-perspective: 1000;
-webkit-transition-duration: 1s;
-webkit-transform-style: preserve-3d;
-webkit-transition: 1s;
}
#frontbackwrapper.flip {
-webkit-transform: rotateY(180deg);
}
#frontbackwrapper.flip #front,
#frontbackwrapper.flip #back {
-webkit-transform: rotateY(180deg);
-webkit-transition: 1s;
}
#front, #back {
position: absolute;
-webkit-backface-visibility: hidden;
}
#back {
-webkit-transform: rotateY(180deg);
}
Try this on your wrapper
-webkit-transform-origin: 50% 0 0;
Though you may or may not have to have its width explicitly set.

webkit translateX animation is rolling back to initial position

I am trying to do a images gallery for mobile webkit,
The only way it is actually fast enough is using the hardware accelerated translateX .
My problem is that the div take back its initial position at the end of the animation. I add the slideGalLeft class cliking on the left button. to the animated div
You can see an example here, in the callback events section:
http://position-absolute.com/jqtouch/demos/main/#home
.slideGalLeft {
-webkit-animation-name: slideColis;
}
#-webkit-keyframes slideColis {
from { -webkit-transform: translateX(0%); }
to { -webkit-transform: translateX(-100%); }
}
Do not use webkit animation for this as it comes back to the default values once played.
Instead define
.slideGalleft{
-webkit-transition: -webkit-transform 1s linear;
-webkit-transform: translateX(0%);
}
and using Javascript, either set -webkit-transform: translateX(100%); or add a CSS class to your element which set the final transform value and webkit will animate it properly
Guillaume's answer is great. However, if you are looking for hardware acceleration, you must let the webkit engine know you want 3D rendering (what makes hardware acceleration active).
According to http://www.html5rocks.com/tutorials/speed/html5/#toc-hardware-accell, this is done by adding translateZ(0) to your rule, like so:
.slideGalleft{
-webkit-transition: -webkit-transform 1s linear;
-webkit-transform: translateX(0%) translateZ(0);
}
Follow Guillaume's advice beyond that.
Use:
-webkit-animation-fill-mode: none/backwards/forwards/both;
This allows you to define at what end of your animation the element remains when the animation is finished.
I was able to make it work by adding a "display:none" style on the finish of the animation. Use the following CSS:
.paused {
-webkit-animation-play-state: paused;
}
.hiddendiv {
display:none;
}
Then in your jQuery code:
$('div.sideimage').click(
function () {
$(this).removeClass("paused").delay(2000).queue(
function(next) {
$(this).addClass("hiddendiv");
next();
}
);
}
);
Should work!