Vue transition within a transition ending the transition in the wrong place - javascript

I am trying to add a transition to a child div within another 'parent' div with its own transition, however there seems to be an issue with the child transition.
What appears to be happening is the child transition is getting confused with the parent transition and ending the transition in the wrong place.
The effect I am trying to get is when the button is clicked the Child Container A (in view) slides out left and Child Container B slides into view after Child Container A from the right.
I have replicated the issue here: https://codepen.io/BONDJAMES/pen/mdegmMe
How do I slide Child Container A out left, with Child Container B sliding into view after Child Container A, from the right, after a toggle?
HTML
<div id="app">
<div class="viewBlocks">
<transition name="slide">
<div class="left" v-if="!MaxView">
<div class="subContainer">
<div class="container">
...
</div>
</div>
</div>
</transition>
<transition name="slide">
<div class="right">
<div class="subContainer">
<button #click="toggleBtn">Toggle</button>
Parent DIV
<div class="container">
<transition name="first-slide">
<div v-if="!showMiniB" class="miniContainerA">
<button #click="slideDivs">Slide A out - B In</button>
Child Container A
</div>
</transition>
<transition name="second-slide">
<div v-if="showMiniB" class="miniContainerB">
<button #click="slideDivs">Slide B out - A</button>
Child Container B
</div>
</transition>
</div>
</div>
</div>
</transition>
</div>
</div>
CSS
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.viewBlocks {
display: flex;
}
.viewBlocks > * {
flex: 1 1 0%;
overflow: hidden;
}
.viewBlocks .subContainer {
margin: 10px;
background-color: white;
min-height: 200px;
padding: 1rem;
/* prevent text wrapping during transition? */
min-width: 300px;
}
.viewBlocks .left {
background-color: blue;
}
.viewBlocks .right {
background-color: red;
}
.viewBlocks .container {
background-color: white;
}
.slide-leave-active, .slide-enter-active {
transition: 1s cubic-bezier(0.5, 0, 0.3, 1);
}
.slide-leave-to, .slide-enter {
flex-grow: 0;
}
.miniContainerA{
border: green 3px solid;
text-align: center;
height: 60px
}
.miniContainerB{
border: pink 3px solid;
text-align: center;
height: 60px
}
.first-slide-enter {
opacity: 0;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.first-slide-enter-to {
opacity: 1;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.first-slide-leave-to {
opacity: 0;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.second-slide-enter {
opacity: 0;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.second-slide-enter-to {
opacity: 1;
transform: translatex(-100%);
transition: all 0.7s ease-out;
}
.second-slide-leave-to {
opacity: 0;
transform: translatex(0);
transition: all 0.7s ease-out;
}
.second-slide-leave {
transform: translatex(-100%);
}
VUE
var app = new Vue({
el: '#app',
data: () => ({
MaxView: false,
showMiniB: false
}),
methods: {
toggleBtn(){
this.MaxView = !this.MaxView
},
slideDivs(){
this.showMiniB = !this.showMiniB
}
}
})

It's just a matter of adjusting the css a bit
for miniContainerA and miniContainerB (using just div in example below) you need to anchor to the top. You can do this by positioning the parent as absolute, and the children (miniContainers) relative
.viewBlocks .container {
background-color: white;
position: relative;
top: 0;
}
.viewBlocks .container div{
background-color: yellow;
position: absolute;
top: 0;
left:0;
width:100%;
}
then adjust your transition percentage (added 100% to your translatex values)
.second-slide-enter {
opacity: 0;
transform: translatex(100%);
transition: all 0.7s ease-out;
}
.second-slide-enter-to {
opacity: 1;
transform: translatex(0%);
transition: all 0.7s ease-out;
}
.second-slide-leave-to {
opacity: 0;
transform: translatex(100%);
transition: all 0.7s ease-out;
}
.second-slide-leave {
transform: translatex(0%);
}

Related

Vuejs transition is not working to show a modal

I am at a loss to why my animation is not working using vue transitions. Here is my code:
<template>
<teleport to="body">
<div class="modal-overlay" v-if="loading">
<transition name="loading">
<div v-if="loading" class="dialog">
<h1>LOADING</h1>
</div>
</transition>
</div>
</teleport>
</template>
<script>
export default {
props: ["loading"],
};
</script>
<style scoped>
.dialog {
text-align: center;
border-radius: 10px;
width: 10%;
border: 2px solid #00f6f6;
background-color: #0f0f0f;
color: #efefef;
padding: 10px;
/* animation: enter 0.25s linear; */
overflow: hidden;
}
.modal-overlay {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
}
.loading-enter-active {
animation: enter 0.2s ease-out;
}
.loading-leave-active {
animation: leave 0.2s ease-in;
}
#keyframes enter {
0% {
opacity: 0%;
transform: scale(0);
}
100% {
opacity: 100%;
transform: scale(1);
}
}
#keyframes leave {
0% {
transform: scale(1);
opacity: 100%;
}
100% {
transform: scale(0);
opacity: 0%;
}
}
</style>
I am passing a prop from the parent component called "loading". This serves as a modal and it serves the purpose as the modal is it does appear and disappear based on the value of "loading" but the animation is not working. Can anyone tell me why?
Thank you!
It's because you have v-if="loading" on .modal-overlay. This doesn't give it a chance to evaluate the condition and transition the element.
Remove that and it should work:
Vue.createApp({
data() {
return {
loading: false
}
},
created() {
setInterval(() => {
this.loading = !this.loading
}, 2000)
}
}).mount('#app')
.dialog {
text-align: center;
border-radius: 10px;
width: 10%;
min-width: fit-content;
border: 2px solid #00f6f6;
background-color: #0f0f0f;
color: #efefef;
padding: 10px;
/* animation: enter 0.25s linear; */
overflow: hidden;
}
.modal-overlay {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
}
.loading-enter-active {
animation: enter 0.2s ease-out;
}
.loading-leave-active {
animation: enter 0.2s ease-in reverse;
}
#keyframes enter {
0% {
opacity: 0%;
transform: scale(0);
}
100% {
opacity: 100%;
transform: scale(1);
}
}
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
<teleport to="body">
<div class="modal-overlay">
<transition name="loading">
<div class="dialog" v-if="loading">
<h1>LOADING</h1>
</div>
</transition>
</div>
</teleport>
</div>
Well, I was facing similar problem when i was using Modal. From your question, i understood that you have problem with the transition, that is because of the <style scoped>.
You can go through this link https://cli.vuejs.org/guide/css.html#referencing-assets for better understanding how the CSS works in Vue/cli projects.
I am not sure why you have used <div v-if="loading" class="dialog">, first remove the v-if and then try adding a class to CSS <style lang="scss" scoped>.
If this is working fine for you, then you can add v-if or anything according to your requirements.
Thank you, I hope this will help you.

REACT - Child position with respect of scale of parent

I have a situation, where I have a parent div in which there can be any number of children divs, now I am applying scale on the parent div, so since the scale is applied on parent it looks that the child element is displacing from its position, I want the children divs to follow parent scale how to manage this situation, here are some portion of my code..
<div className="image-viewer">
<div className="image-wrapper">
<div class="zoom-2 image-outer">
<img class="map-image" src="map.png"/>
<div class="booth" style="left: 617px; top: 178px;"> </div>
<div class="booth" style="left: 735px; top: 160px;"> </div>
</div>
</div>
</div>
In the above code the child elements have there left and top defined dynamically by mouse click position on map image. I have four predefined zoom levels from css which I am supplying dynamically on Zoom In/Out buttons.
Below are my css
.image-viewer .image-wrapper {
position: relative;
width: 92vw;
height: 92vh;
margin: 4vh 4vw;
overflow: hidden;
}
.image-viewer .image-outer {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
text-align: center;
transition: all .35s ease;
-webkit-transition: all .35s ease;
}
.image-viewer .image-outer .map-image {
display: inline-block;
vertical-align: middle;
max-width: 100%;
max-height: 100%;
width: auto !important;
height: auto !important;
background-size: contain!important;
background-position: center!important;
background-repeat: no-repeat !important;
transform: scale3d(1, 1, 1);
-webkit-transform: scale3d(1, 1, 1);
transition: all .4s ease;
-webkit-transition: all .4s ease;
animation: image-fade-in 0.4s ease;
-webkit-animation: image-fade-in 0.4s ease;
}
.image-viewer .image-outer.zoom-1 {
cursor: default;
}
.image-viewer .image-outer.zoom-2 .map-image {
transform: scale3d(1.5, 1.5, 1);
-webkit-transform: scale3d(1.5, 1.5, 1);
}
.image-viewer .image-outer.zoom-3 .map-image {
transform: scale3d(2, 2, 1);
-webkit-transform: scale3d(2, 2, 1);
}
.image-viewer .image-outer.zoom-4 .map-image {
transform: scale3d(2.5, 2.5, 1);
-webkit-transform: scale3d(2.5, 2.5, 1);
}
.image-viewer .image-outer.zoom-5 .map-image {
transform: scale3d(3, 3, 1);
-webkit-transform: scale3d(3, 3, 1);
}
.booth{
width:9px;
height:9px;
border-color:white;
border-width:1px;
border-style:solid;
position:absolute;
z-index:999;
background-color: red;
transition: all .2s ease-in-out;
}
.booth:hover{
cursor: pointer;
transform: scale(2.0);
}
Here is my jsFiddle - https://jsfiddle.net/veda_in/o2qLt4q8/33/
Just change this.
.image-viewer .image-outer.zoom-2 .map-image {
transform: scale3d(1.5, 1.5, 1);
-webkit-transform: scale3d(1.5, 1.5, 1);
}
to :
.image-viewer .image-outer.zoom-2 {
transform: scale3d(1.5, 1.5, 1);
-webkit-transform: scale3d(1.5, 1.5, 1);
}
The problem here is when you are scaling map image, image is scaling but class zoom-2 width is not scaling, which is container for both booth element and map image.
.image-viewer .image-outer {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
text-align: center;
transition: all .35s ease;
-webkit-transition: all .35s ease;
}
So either you scale zoom-2 div class or add zoom-2 class to map-image and define map-image relative.

Multiple CSS animations: How to avoid re-triggering one of them?

I am trying to build an animated menu for mobile apps similar to Pinterest's radial menu. I have managed to get the behaviour to where I want it except for one minor detail: when the menu opens, the items shoot out as I want them to, and when you hover on them, they transform as I want them to. problem is, after the cursor leaves the items, they re-trigger their original animation, instead of just returning to their previous state. I realise this is a problem to do with the class being used for the animation and I have tried a number of solutions, including deleting the class and adding a new one .onmouseover() and changing animation running state on hover/mousover. I am probably missing something simple and idiotic, but I just cannot see it. can anybody help?
The following code is just the way I had it before trying to implement solutions.
HTML:
<!--Footer-->
<div class="footer">
<!--RADIAL NAV MENU-->
<div id="navContainer">
<!--Buttons-->
<div id="workouts" class="sml smlOne">Go there</div>
<div id="home" class="sml smlTwo">Go here</div>
<div id="profile" class="sml smlThree">Go somewhere</div>
<!--Burger-->
<div class="burger-menu">
<div id="top" class="bar barTop"></div>
<div id="middle" class="bar barMid"></div>
<div id="bottom" class="bar barBot"></div>
</div>
</div>
</div>
CSS:
.footer
{
position: fixed;
bottom: 0%;
width: 100%;
height: 50px;
background-color: #d36363;
box-shadow: 0px -6px 6px #888888;
z-index: +2;
}
/* Burger menu section */
#navContainer
{
text-align: center;
font-size: 10px;
}
.burger-menu
{
position: relative;
margin: auto;
height: 100%;
width: 50px;
}
.bar
{
height: 6px;
width: 100%;
background-color: white;
}
#top
{
position: relative;
top: 5px;
}
#middle
{
position: relative;
top: 15px;
}
#bottom
{
position: relative;
top: 25px;
}
.barTop, .barMid, .barBot
{
-webkit-transition: all 0.1s ease;
-moz-transition: all 0.1s ease;
-o-transition: all 0.1s ease;
-ms-transition: all 0.1s ease;
transition: all 0.1s ease;
}
.barTopOn
{
transform: rotate(45deg) translateY(12px) translateX(11px);
}
.barMidOn
{
opacity: 0;
}
.barBotOn
{
transform: rotate(-45deg) translateY(-12px) translateX(11px);
}
/* Navigation buttons section */
#navContainer
{
position: relative;
margin: auto;
width: 50px;
}
.sml
{
border: 2px solid #58a7dd;
height: 50px;
width: 50px;
border-radius: 50%;
background-color: white;
box-shadow: 6px 6px 6px #888888;
transform: scale(0);
}
#workouts
{
position: absolute;
bottom: 10px;
left: -60px;
}
#home
{
position: absolute;
bottom: 50px;
}
#profile
{
position: absolute;
bottom: 10px;
left: 60px;
}
.smlOnOne
{
animation: pop, slideOne 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnTwo
{
animation: pop, slideTwo 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnThree
{
animation: pop, slideThree 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnOne:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopL 0.2s;
animation-fill-mode: forwards;
}
.smlOnTwo:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopC 0.2s;
animation-fill-mode: forwards;
}
.smlOnThree:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopR 0.2s;
animation-fill-mode: forwards;
}
#keyframes pop
{
100%
{
transform: scale(1,1);
}
}
#keyframes slideOne
{
0%
{
bottom: -20px;
left: 0px;
}
100%
{
bottom: 10px;
left: -60px;
}
}
#keyframes slideTwo
{
0%
{
bottom: -20px;
}
100%
{
bottom: 50px;
}
}
#keyframes slideThree
{
0%
{
bottom: -20px;
left: 0px;
}
100%
{
bottom: 10px;
left: 60px;
}
}
#keyframes whopL
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px) translateX(-10px);
}
}
#keyframes whopC
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px);
}
}
#keyframes whopR
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px) translateX(10px);
}
}
JS/jQuery:
$(".burger-menu").click(function()
{
$(".barTop").toggleClass("barTopOn");
$(".barMid").toggleClass("barMidOn");
$(".barBot").toggleClass("barBotOn");
$(".smlOne").toggleClass("smlOnOne");
$(".smlTwo").toggleClass("smlOnTwo");
$(".smlThree").toggleClass("smlOnThree");
});
Here is a working demo:
https://codepen.io/BGGrieco/pen/NgjxXq
You have an element that is a set of #-webkit-keyframes to animate in. On hamburger-menu click, these keyframes run, and that works well.
Next, you have a second set of #-webkit-keyframes on hover, so on hover works well too.
However, the instant the mouse is away from the element, the first (intro) set of keyframes gets run again. You don't want it to run after it first runs.
Here is what I was able to accomplish:
https://codepen.io/CapySloth/pen/RgxKEb
<div id="workouts" class="sml smlOne">
<div class="test1">
Go there
</div>
</div>
Instead of stacking classes which contain keyframe animations onto the one ".sml" class, I have split the task between two elements. ".sml" now acts as a wrapper which takes care of the "hamburger-menu open" animation and "test1 a" takes care of the "whop" animation.
If you can find a way to hide/show parents of the "test1 a/test2 a/test3 a" then you will have what you want.
You can use .stop() before your .toggleClass.
$("#example").stop().toggleClass("class");

CSS animation is working only one way

I have a div that when clicked it slides up another div, but when I close the div that had slid up, it doesn't slide down, it just abruptly goes away.
I tried putting the transition on .agent-modal instead, but it achieved the same result.
$('[data-agent]').click(function() {
var element = $(this);
var target = element.data('agent');
$('body').addClass('agentLoaded');
$('[data-agent-target="' + target + '"]').addClass('active');
return false;
});
$('.close').click(function() {
$('[data-agent-target]').removeClass('active');
$('body').removeClass('agentLoaded');
return false;
});
.agent-modal {
position: fixed;
transform: translateY(100%);
-webkit-transform: translateY(100%);
left: 275px;
opacity: 1;
width: calc(100% - 275px);
height: 100%;
background-color: $c-blue;
&.active {
overflow: auto;
top: 0;
padding-top: 40px;
padding-bottom: 40px;
transform: translateY(0);
-webkit-transform: translateY(0);
-webkit-transition-duration: 0.5s;
-moz-transition-duration: 0.5s;
-ms-transition-duration: 0.5s;
-o-transition-duration: 0.5s;
transition-duration: 0.5s;
transition-timing-function: ease-out;
-webkit-transition-timing-function: ease-out;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-xs-12 col-sm-2 col-md-4 agent">
<a href="#" data-agent="alexander-cuturilo">
<div class="agent-meta">
<div class="agent-name">
<h5>Alexander Cuturilo</h5>
</div>
</div>
</a>
</div>

prevent effect hover from occurring until previous effect has completed

Currently if I hover over an element it displays the animation I am looking for, and hides the other elements on the page.
The issue I am facing is that if I hover over many of the divs quickly it queues, and hides the divs one after an other. I want to just allow one div to be hidden when hovered on, and when all animations are complete allow the functionality work again.
See jsfiddle here
If you hover quickly over the divs you will see that they appear/disappear and this keeps repeating. I want more control over this, and to only allow the effect to happen again, once the animation is complete.
Please also see code below for convenience.
I tried adding
if(!$(".wrapper").is(":animated")){....
but unfortunately this didn't work.
html
<div class="box-1">
<div class="wrapper">
<div class="background-out label-1 label"></div>
<div class="background-over label-1 label"></div>
<div class="background-info">
<div class="text">Bla bla bla.</div>
</div>
</div>
</div>
<div class="box-2">
<div class="wrapper">
<div class="background-out label-2 label"></div>
<div class="background-over label-2 label"></div>
<div class="background-info">
<div class="text">Bla bla bla</div>
</div>
</div>
</div>
css
.box-1 {
position: absolute;
top: 40%;
left: 40%;
}
.box-2 {
position: absolute;
top: 10%;
left: 40%;
}
.wrapper {
position: relative;
width: 100px;
height: 100px;
margin: 0 0 20px;
}
.background-out,
.background-over {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.background-out,
.background-over,
.background-info {
transition: opacity 600ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms, -moz-transform 600ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms, -webkit-transform 600ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms;
}
.background-info {
position: absolute;
left: 100px;
top: 0;
width: 100%;
height: 100%;
opacity: 0.2;
transform-origin: 0% 50% 0px;
transform: rotateY(-90deg);
background-color: #f8f8f8;
}
.background-info .text {
font-size: 12px;
letter-spacing: 1px;
text-align: center;
width: 80%;
margin-left: 10%;
margin-top: 5px;
}
.background-out {
transition-timing-function: linear;
}
.wrapper:hover .background-out {
visibility: hidden;
}
.wrapper:hover .background-over,
.wrapper:hover .background-info {
transform: translate3d(0px, 0px, 0px) rotateY(0deg);
transition: opacity 1000ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms, -moz-transform 1000ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms, -webkit-transform 1000ms cubic-bezier(0.55, 0.31, 0.15, 0.93) 0ms;
opacity: 1;
}
.background-over {
background-color: transparent;
opacity: 0;
transform-origin: 100% 50% 0px;
transform: rotateY(-90deg);
}
.label-1 {
background: yellow;
}
.label-2 {
background: pink;
;
}
.label {
animation-duration: 1s;
animation-name: slidein;
}
JS
$('.wrapper').hover(function() {
$('.wrapper').not(this).fadeOut('slow');
$('.wrapper .label').not(this).removeClass('label');
}, function() {
$('.wrapper').not(this).fadeIn('slow');
});
You need to use the jQuery .stop() method to prevent the animations queuing.
https://jsfiddle.net/po34gv6v/11/
$('.wrapper').hover(function() {
$('.wrapper').not(this).stop().fadeOut('slow');
$('.wrapper .label').not(this).removeClass('label');
}, function() {
$('.wrapper').not(this).stop().fadeIn('slow');
});
see: https://api.jquery.com/stop/

Categories

Resources