Vue 3 transition flickers on start - javascript

I've built myself a carousel of divs that slide in and out of the screen. My problem is that on the start of every transition, when the new div first renders (ie. the carousel_2 key changes), it seems to render without the transition-enter class applied to it. This means that the new div flickers overtop of the old one before getting translated off the screen and out of view. It's almost as though the transition takes a tick to register that the new div has appeared. If I could figure out how to delay the new div from rendering for a tick, I believe that my problem might be solved, though I don't know how to do this with keys.
<transition name="slide-img">
<div :key="carousel_2" class="workDiv-container">
<div class="workDiv">
<div class="imgDiv">
<img :src="carousel_2.img" style="width: 100%;"/>
</div>
<div class="infoDiv">
<h1>{{ carousel_2.title }}</h1>
<h3>{{ carousel_2.creator }}</h3>
<h3>{{ carousel_2.date }}</h3>
<h3>{{ carousel_2.medium }}</h3>
<h3>{{ carousel_2.idno }}</h3>
<h3>{{ carousel_2.dimensions }}</h3>
</div>
</div>
</div>
</transition>
.slide-img-enter {
left: -100%;
transform: translate(0, 0);
}
.slide-img-enter-to {
left: -100%;
transform: translate(100%, 0);
}
.slide-img-enter-active {
transition: transform 2s;
}
.slide-img-leave {
transform: translate(0, 0);
}
.slide-img-leave-to {
transform: translate(100%, 0);
}
.slide-img-leave-active {
transition: transform 2s;
}
.workDiv-container {
position: absolute;
width: 100%;
height: 100%;
}
NOTE: carousel_2 is just a computed value that is updated with the object containing the values to display.

on the start of every transition, when the new div first renders (ie. the carousel_2 key changes), it seems to render without the transition-enter class applied to it
That's right. Because In Vue 3 the v-enter and v-leave classes are renamed to v-enter-from and v-leave-from
If you change your transition classes to:
.slide-img-enter-from {
left: -100%;
transform: translate(0, 0);
}
/* this one is actually not needed at all */
.slide-img-leave-from {
transform: translate(0, 0);
}
...the problem is fixed. Demo

Related

Negative vw value is not recognized in translateX(-100vw)

I am using css transitions and a little javascript to make elements slide into the page from the left or right.
It works perfectly fine from the right side (starting from transform: translateX(100vw);).
But from the left side (negative translate value: transform: translateX(-100vw);) it does not work at all. There is no error, but the element pops up at the end of the transition without any "animated" movement.
Using a px value instead of vw for the negative/ left side also works fine. I found several examples where people used negative vw values and did not seem to have problems with it...
I also tried transform: translateX(calc(0px - 100vw));. No luck...
(I am not using any libraries etc.)
<!-- HTML -->
<div class="container">
<div class="slide-in l"></div>
<div class="slide-in r"></div>
</div>
/* CSS */
.slide-in {
transition: transform 0.8s ease;
}
.slide-in.l {
transform: translateX(-100vw); /* this is the line does not work */
}
.slide-in.r {
transform: translateX(100vw);
}
.slide-in.show {
transform: translateX(0);
}
/* JavaScript */
const slider = document.querySelectorAll('.slide-in');
window.addEventListener("load", () => {
slider.forEach(s => {
s.classList.add('show');
})
});
Any ideas what could be the problem?
The translateX(-100vw); should work fine.
When you run this snippet you should see both rectangles sliding into view,
the green one from the left and the right one from the right.
const slider = document.querySelectorAll('.slide-in');
window.addEventListener("load", () => {
slider.forEach(s => {
s.classList.add('show');
})
});
/* CSS */
.slide-in {
transition: transform 0.8s ease;
width: 100px;
height: 100px;
}
.slide-in.l {
transform: translateX(-100vw);
/* this is the line does not work */
background-color: green;
}
.slide-in.r {
transform: translateX(100vw);
background-color: blue;
}
.slide-in.show {
transform: translateX(0);
}
<!-- HTML -->
<div class="container">
<div class="slide-in l">a</div>
<div class="slide-in r">b</div>
</div>

ToggleClass overlap

I'm trying to use the same button to open and close a menu, I'm sure this is super simple but I'm new to the world of jQuery. I'm using the Wordpress builder 'Oxygen' if that helps. Here's my code:
The modal is an in-built feature in the website builder so I can't provide much code on that. It's basically set to trigger when element with class "open" is clicked, and close with element class "oxy-modal-close".
jQuery
jQuery("#toggle").click(function () {
jQuery('#plus').toggleClass('rotate');
jQuery('#toggle').toggleClass('open oxy-modal-close');
});
HTML
<div id="toggle" class="open">
<img id="plus" src="http://hausse.co.uk/wp-content/uploads/2021/01/plus.svg"/>
</div>
CSS
#plus {
-moz-transition: transform 1s;
-webkit-transition: transform 1s;
transition: transform 0.3s;
width: 35px;
position: fixed;
top: 20px;
right: 20px;
}
.rotate {
transform: rotate(45deg);
}
Basically on the 2nd click, the class is re-adding the class "open", which is causing the menu to flicker as the two actions are conflicting with each other. Video here - https://gph.is/g/ZnNQddo
I have tried adding a delay to the class "open", but for some reason the delay is only working on the first click - on the second it's changing class instantly. This is the code I'm trying for that.
jQuery("#toggle").click(function () {
jQuery('#plus').toggleClass('rotate');
jQuery('#toggle').toggleClass('oxy-modal-close');
var el = jQuery("#toggle");
window.setTimeout(function() {
el.toggleClass('open');
}, 500);
});
You are referencing the id again within the click - you need to reference $(this)... to toggle the class on the click
Also - you need to start with one of the states - that way it can toggle the class to the other state on each click as per the snippet (the cross icon is on the right of the snippet widow as per styling ) - now when you click it rotates as intended.
$("#toggle").click(function() {
$('#plus').toggleClass('rotate');
$(this).toggleClass('open oxy-modal-close');
});
#plus {
-moz-transition: transform 1s;
-webkit-transition: transform 1s;
transition: transform 0.3s;
width: 35px;
position: fixed;
top: 20px;
right: 20px;
}
.rotate {
transform: rotate(45deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="toggle" class="open">
<img id="plus" src="http://hausse.co.uk/wp-content/uploads/2021/01/plus.svg"/>
</div>

Vue - apply transition to menu element

I have this scss code in my vue app. I'm trying to make a smooth transition from left for a menu when the isVisible property is set to true but I'm not able to apply the transition I've defined and the menu will instantly appear.
I've done a reserach here on SO and I've found some interesting questions but all of them are using jQuery and css animation so they are not really useful.
I'm not a CSS master, any suggestion about?
HTML
<div class="col-12 settings p-3 position-fixed" :class="{ 'show': isVisible }" ref="settings" v-if="isVisible">
<h4>Settings</h4>
</div>
CSS
.settings {
top: 0;
width: 50%;
height: 100vh;
background-color: white;
transform: translateX(-100%);
transition: transform 0.5s ease;
&.show {
transform: translateX(0);
transition: transform 0.5s ease;
}
}
This is done with <transition>
Here an example:
<transition name="slide">
<div class="col-12 settings p-3 position-fixed" class="settings" v-if="isVisible">
<h4>Settings</h4>
</div>
</transition>
CSS class
.slide-enter-active, .slide-leave-active {
transition: transform .5s;
}
.slide-enter, .slide-leave-to {
transform: translateX(-200px);
}
.settings {
top: 0;
width: 50%;
height: 100vh;
background-color: white;
}
Its really not that hard
Take a look: https://v2.vuejs.org/v2/guide/transitions.html
I believe the issue is that, because you are using v-if, the element is only being rendered when the condition isVisible === True. This means that it is being rendered with the conditional 'show' class already applied, therefore no transition.
You could use the v-show directive instead of v-if, this makes the element hidden but rendered until the condition is true. (more info here).
<div
class="col-12 settings p-3 position-fixed"
:class="{ 'show': isVisible }"
ref="settings"
v-show="isVisible">
<h4>Settings</h4>
</div>
If you want to do more with transitions, I suggest looking up vue-transitions - documentation here - this allows you to assign css to the element during its rendering states, i.e. what styles apply as it enters and when it leaves.
See the other answer here for an example of how to do this with vue transition.

Animate one at a time with ng-repeat

I am trying to use ngRepeat to load an image and play it's associated tone, then move the image from the center of the circle to a specific position on a circle, and proceed with the doing the same thing with the next image. I got the images to display and move one by one using ng-enter-stagger, however the images have different positions so when I change it to to use a different class for each repetition, ng-enter-stagger does not work.
How can I go about loading one image, moving it to the proper position, hiding the image, then proceeding with the next image?
I have created a plunkr but the animation does not work in it https://plnkr.co/edit/DddST6JsemsCKKf3mQ6N?p=preview.
An example of what I want to do is the Learn the sounds part of this (http://www.absolutepitchstudy.com/animalgame/) click either Start Control or Start Animal Game
The data looks like this:
"ImageTones":[{"CPosition":"deg60","Image":{"ImageFileName":"Alligator.png","ImageId":1},"Tone":{"ToneFileName":"C3.mp4","ToneId":1}},
{"CPosition":"deg0","Image":{"ImageFileName":"Cow.png","ImageId":4},"Tone":{"ToneFileName":"B5.mp4","ToneId":2}},
{"CPosition":"deg270","Image":{"ImageFileName":"Bird.png","ImageId":3},"Tone":{"ToneFileName":"E3.mp4","ToneId":3}}]
Html page:
<div class="circle-container">
<div ng-repeat="it in model.imageTones" class="it.CPosition">
<img ng-src="../Content/Game/Animals/{{it.Image.ImageFileName}}"/>
<!--Audio tag goes here-->
</div>
</div>
My CSS (I may be able to fix this to not have as many classes, just am unsure how)
.circle-container {
position: relative;
width: 38em;
height: 38em;
padding: 2.8em;
/*2.8em = 2em*1.4 (2em = half the width of a link with img, 1.4 = sqrt(2))*/
border: dashed 1px;
border-radius: 80%;
margin: -5.25em auto 0;
}
.circle-container div {
display: block;
position: absolute;
top: 50%;
left: 50%;
width: 4em;
height: 4em;
margin: -2em;
}
.circle-container div.ng-enter {
transition: 5s linear all;
opacity: 0;
}
.circle-container div.ng-enter-stagger {
/* this will have a 100ms delay between each successive leave animation */
transition-delay: 5.0s;
/* As of 1.4.4, this must always be set: it signals ngAnimate
to not accidentally inherit a delay property from another CSS class */
transition-duration: 0s;
}
.circle-container div.ng-enter.ng-enter-active {
/* standard transition styles */
opacity:1;
}
.deg0.ng-enter-active {
transform: translate(19em);
}
.deg30.ng-enter-active {
transform: rotate(30deg) translate(19em) rotate(-30deg);
}
.deg60.ng-enter-active {
transform: rotate(60deg) translate(19em) rotate(-60deg);
}
.deg90.ng-enter-active {
transform: rotate(90deg) translate(19em) rotate(-90deg);
transition: transform 5s;
}
.deg120.ng-enter-active {
transform: rotate(120deg) translate(19em) rotate(-120deg);
}
.deg150.ng-enter-active {
transform: rotate(150deg) translate(19em) rotate(-150deg);
}
.deg180.ng-enter-active {
transform: rotate(180deg) translate(19em) rotate(-180deg);
}
.deg210.ng-enter-active {
transform: rotate(210deg) translate(19em) rotate(-210deg);
}
.deg240.ng-enter-active {
transform: rotate(240deg) translate(19em) rotate(-240deg);
}
.deg270.ng-enter-active {
transform: rotate(270deg) translate(19em) rotate(-270deg);
}
.deg300.ng-enter-active {
transform: rotate(300deg) translate(19em) rotate(-300deg);
}
.deg330.ng-enter-active {
transform: rotate(330deg) translate(19em) rotate(-330deg);
}
There's a couple of errors to look at 1st, To get a value of a class from an angular item, it's ng-class you should be looking for:
<div ng-repeat="it in model.imageTones" ng-class="it.CPosition" ng-if="!it.hidden" >
<img ng-src="http://www.absolutepitchstudy.com/animalgame/content/images/{{it.Image.ImageFileName}}" />
</div>
Then in you style sheet there seems to be something wrong with the CSS, so I removed a class that wasn't being used:
.deg60{
transform: rotate(60deg) translate(19em) rotate(-60deg);
}
Although to hide stuff you may want that back.
The updated plunk with the work so far is at:
plunky
Now it's being rendered in the right place, you can use $timeout, ng-click or someother method to alter the class definition in your model. The position of the graphic should automatically update.
What method were you going to use?

Animating a div on hover css - possible loop

Wordpress site using Bootstrap framework
.test {
position: absolute;
z-index: 9;
left: 50%;
height: 10em;
width: 10em;
margin-left: -5em;
background-size: cover;
opacity: 0;
transition: opacity 0.5s ease;
transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
}
.linkage:hover + .test {
opacity: 1;
}
<div class="row">
<div class="col-md-12 indx-img" style="background-image:url('...');">
Link
<div class="test"> Test </div>
</div>
</div>
Right now my site has the div 'test' show up (opacity 1) vertically/horiz centred when the the link 'linkage' is hovered on (linkage is 100% height and width of the container).
I want to animate the 'test' div as it fades in on hover. I was thinking using scale (on hover the div scales down to its original size then scales up on fade out) or something. Unless anyone has a cooler idea
It seems like you are looking for something like the below snippet (a transition and not animation). On hover of the link, the .test is being scaled up two times its original size both along X and Y axes and on mouse out it is brought back to its normal size.
.test {
position: absolute;
z-index: 9;
left: 50%;
top: 50%; /* added as I think this was missed in your code */
height: 10em;
width: 10em;
margin-left: -5em;
background-size: cover;
background: url(http://lorempixel.com/500/500); /* added for image */
opacity: 0;
transition: all 0.5s ease; /* modified to transition all property changes */
/* added to scale up the div with the center as the origin */
transform-origin: 50% 50%;
transform: translateY(-50%) scaleX(2) scaleY(2);
}
.linkage:hover + .test {
opacity: 1;
transform: translateY(-50%) scaleX(1) scaleY(1); /* bring back to normal state */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="row">
<div class="col-md-12 indx-img" style="background-image:url('...');">
Link
<div class="test">Test</div>
</div>
</div>
Alternately, you could use matrix transforms also. Equivalent of translateY(-50%) scaleX(2) scaleY(2) would be matrix(2, 0, 0, 2, 0, -101) and that of translateY(-50%) scaleX(1) scaleY(1) would be matrix(1, 0, 0, 1, 0, -101).
Well this will never be true:
.linkage:hover + .test {
opacity: 1;
}
as linkage (hovered or not) is not a sibling of test.
.test is absolutely positioned, but has no parent element that is not static. Did you want to to be absolute to the body? You use left/margin to horizontally center, and it looks like you are trying to use translateY to vertically center, but you never specify top. Perhaps consolidating to one method?
top:50%; left:50%; transform: translateX(-50%) translateY(-50%);

Categories