I\'m having trouble creating a flyout menu with a specific effect. The flyout goes from display:none to block and then I use jquery to animate opacity from 0 to 1 (and vice vers
if you want only to change the opacity
you can use FadeIn and FadeOut functions of JQuery but if you want more complex transition you can use CSS3 (this is a realy good library).
See this DEMO where you can see this two different way.
You can also add a controll to the class like this:
$("OBJECT").click(function(){
if ($("OBJECT").hasClass("CLASS")){
$("OBJECT").removeClass("CLASS");
} else {
$("OBJECT").addClass("CLASS");
}
});
to make two way functions.
$(document).ready(function(){
$("#fadeOut").click(function(){
var duration = 500;
$("#div").fadeOut(duration);
});
$("#css").click(function(){
$("#div").addClass("out");
setTimeout(
function() {
$("#div").css("display", "none");
},
2001);
});
});
#div {
width:200px;
height:200px;
background-color:red;
text-align:center;
vertical-align:middle;
/* Animation CSS */
-webkit-animation-duration: 2s;
animation-duration: 2s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
/* Setup CSS3 animations */
@-webkit-keyframes out {
0% {
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
20%, 60% {
-webkit-transform: rotate3d(0, 0, 1, 80deg);
transform: rotate3d(0, 0, 1, 80deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
40%, 80% {
-webkit-transform: rotate3d(0, 0, 1, 60deg);
transform: rotate3d(0, 0, 1, 60deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
opacity: 1;
}
to {
-webkit-transform: translate3d(0, 700px, 0);
transform: translate3d(0, 700px, 0);
opacity: 0;
}
}
@keyframes out {
0% {
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
20%, 60% {
-webkit-transform: rotate3d(0, 0, 1, 80deg);
transform: rotate3d(0, 0, 1, 80deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
40%, 80% {
-webkit-transform: rotate3d(0, 0, 1, 60deg);
transform: rotate3d(0, 0, 1, 60deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
opacity: 1;
}
to {
-webkit-transform: translate3d(0, 700px, 0);
transform: translate3d(0, 700px, 0);
opacity: 0;
}
}
.out {
-webkit-animation-name: out;
animation-name: out;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<div id="div"></div>
<button id="fadeOut">fadeOut</button>
<button id="css">CSS3</button>
</body>
</html>
Is there a way around this? I knew that CSS animation alongside a display change on the same element did not work, but finding out that any child animations also do not work is a little frustrating.
It does not only apply to the same element, but the entire sub-tree - as the entire sub-tree is not rendered.
display: block
on the wrapper, then force a reflow (by flushing the style buffer with wrapperElement.offsetHeight;
), then add a class that sets opacity:1
to your children (or do whatever you're doing to kick off the animations).width: 0; height: 0; overflow: hidden; visibility: hidden;
(or, for nicer transitions transform: scale(0); visibility: hidden; pointer-events: none;
)As soon as display:none
is involved, you're screwed when it comes to transitions. The best way is to avoid it. I've been using the second option without any significant problems for quite a while now.
edit after OP added some demo code:
.animate()
of the wrapper can be done in CSS as well-webkit-transition
, but the proper transition
as well// delay increases with each column
looks like a misconception. all elements the selector .columns > li:first-child
applies to will have the exact same delay - they won't wait for the previous element to finish its transition. If you want to define that in CSS, you'll have to play with :nth-child() or one of its cousins@rodneyrehm's answer pretty much sums up everything you need when handling animations with css display property.
You need to trigger a reflow after toggling the display property and apply an animation class after it.
// find elements
const banner = $("#banner")
const button = $(".banner__button")
const text = $(".banner__text")
let isVisible = false
// toggle display
button.on("click", () => {
if (!isVisible) {
text.addClass("display--block")
text.outerWidth()
text.addClass("text--show")
isVisible = true
} else {
text.addClass("text--hide")
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', () => {
text.removeClass("display--block")
text.removeClass("text--show")
text.removeClass("text--hide")
isVisible = false
})
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
margin: 0 auto;
width: 300px;
height: 150px;
display: flex;
flex-flow: column nowrap;
}
.banner__button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
cursor: pointer;
transition: box-shadow 0.3s, transform 0.6s;
}
.banner__button:hover {
box-shadow: 0 3px 8px 2px #9d9d91;
transform: translateY(-2px)
}
.banner__button:focus {
outline: 0;
}
.flex--1 {
flex: 1;
}
.banner__text {
display: none;
opacity: 0;
transition: all 0.6s;
}
.display--block {
display: block;
}
.text--show {
animation: slide-in 1s forwards;
}
.text--hide {
animation: slide-out 1s forwards;
}
@keyframes slide-in {
0% {
opacity: 0;
transform: translateX(-30px)
}
100% {
opacity: 1;
transform: translateX(0px)
}
}
@keyframes slide-out {
0% {
opacity: 1;
transform: translateX(0px)
}
100% {
opacity: 0;
transform: translateX(30px)
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="banner">
<div class="flex--1">
<p class="banner__text">Hello World</p>
</div>
<button class="banner__button">Toggle Text</button>
</div>
I went into this same problem a while ago, my workaround was very hacky but mostly works
When you change a, lets say, non transitionable property, like 'display' thing go wrong really fast, i figured that if you use a timmer to change the not transitionable property and a few miliseconds later you change another transitionable property, it kind of works, an you also need to use another timer for turning things back
The HTML
<div class="content_menu_item">
<a href="#">Im a menu item</a>
<ul>
<li>
<a href="#">Sub Item 1</a>
</li>
<li>
<a href="#">Sub Item 2</a>
</li>
<li>
<a href="#">Sub Item 3</a>
</li>
</ul>
</div><div class="content_menu_item">
<a href="#">Im a menu item</a>
<ul>
<li>
<a href="#">Sub Item 1</a>
</li>
<li>
<a href="#">Sub Item 2</a>
</li>
<li>
<a href="#">Sub Item 3</a>
</li>
</ul>
</div>
The CSS
.content_menu_item{
vertical-align: top;
display:inline-block;
width: 140px;
height: 32px;
position:relative;
border:1px solid #b388ff;
text-align: center;
background-color: #6200ea;
}
.content_menu_item a{
line-height: 32px;
display: inline-block;
text-decoration: none;
color:white;
width: 140px;
}
ul{
padding: 0;
list-style:none;
display:none;
margin: 0;
opacity:0.5;
}
.content_menu_item ul li{
color:white;
background: #1e88e5;
line-height: 26px;
vertical-align: top;
transition:all 385ms cubic-bezier(0.895, 0.03, 0.685, 0.22);
opacity:0;
}
.content_menu_item ul li.on{
opacity:1;
}
.content_menu_item ul li.on:nth-child(1){
transition-delay:0ms;
}
.content_menu_item ul li.on:nth-child(2){
transition-delay:50ms;
}
.content_menu_item ul li.on:nth-child(3){
transition-delay:100ms;
}
.content_menu_item ul li.off{
opacity:0;
}
.content_menu_item ul li.off:nth-child(3){
transition-delay:0ms;
}
.content_menu_item ul li.off:nth-child(2){
transition-delay:50ms;
}
.content_menu_item ul li.off:nth-child(1){
transition-delay:100ms;
}
jQuery for handlig the states of the mouse
$('.content_menu_item').hover(
function(){
// mouse over
$(this).find('ul').show(); // show the sub list of the menu, basicaly display block
timmeron = setTimeout(()=>{ // 10 miliseconds later add the class to change the opacity, the on class has a transition-delay for every element usin nth-child
$(this).find('li').addClass('on');
},10);
},function(){
//mouse out
$(this).find('li').removeClass('on'); // remove the on class
$(this).find('li').addClass('off'); // add the off class to invert the transition-delay
timmeroff = setTimeout(()=>{
$(this).find('ul').hide(); // hide the element with time after the transition completes
$(this).find('li').removeClass('off'); // remove both classes
$(this).find('li').removeClass('on');
},500);
})
And here is a working example https://codepen.io/Teobis/pen/QxmqGQ
Hope this helps