Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transition child when parent goes from display: none to block

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 versa). This is necessary because otherwise the transition does not happen when the element has just had it's display property changed. I did not think that this would propagate to children. But inside of my flyout I have 4 columns of links that have an opacity transition, each with it's own delay so they come in one at a time. However, this does not work as the flyout appears. They are instantly at opacity: 1 and even with a long delay time it still does not work.

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. I'd rather not have to write javascript when the CSS is so simple. But if javascript is the only answer, then that will be an easy solve.

Here's a very simplified example of the code:

$flyout.addClass('in').animate({opacity: 1}, 200, "linear");

"in" is the class that causes the transition on the columns:

.flyout { display: none; }

.flyout.in { display: block; }

.columns li {
    opacity: 0;
    -webkit-transition: opacity 0.2s;
}

.flyout.in .columns li { opacity: 1; }

// delay increases with each column
.columns > li:first-child {
    -webkit-transition-delay: 0.2s;
}
like image 991
Unilat Avatar asked Nov 24 '14 21:11

Unilat


People also ask

Can you add transition to display none?

When we want to use transition for display:none to display:block, transition properties do not work. The reason for this is, display:none property is used for removing block and display:block property is used for displaying block. A block cannot be partly displayed.

Does transition work with display?

display is not one of the properties that transition works upon. See Animatable CSS properties for the list of CSS properties that can have transitions applied to them.

How do you add transitions to display blocks?

To work around this always allow the element to be display block but hide the element by adjusting any of these means: Set the height to 0. Set the opacity to 0. Position the element outside of the frame of another element that has overflow: hidden.


2 Answers

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.

  • you can set 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).
  • you can use a different method of visually hiding your wrapper, eg 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:

  • the .animate() of the wrapper can be done in CSS as well
  • do not only use the vendor-prefixed CSS property -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
like image 85
rodneyrehm Avatar answered Oct 09 '22 05:10

rodneyrehm


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>
like image 34
paolobasso Avatar answered Oct 09 '22 03:10

paolobasso