【问题标题】:How to transition child when parent goes from display: none to block当父母离开显示时如何转换孩子:无到阻止
【发布时间】:2015-01-22 17:42:27
【问题描述】:

我在创建具有特定效果的弹出菜单时遇到问题。弹出窗口从 display:none 变为 block,然后我使用 jquery 将不透明度从 0 设置为 1(反之亦然)。这是必要的,否则当元素刚刚更改其显示属性时,不会发生过渡。我不认为这会传染给孩子。但是在我的弹出窗口中,我有 4 列具有不透明度过渡的链接,每列都有自己的延迟,因此它们一次进入一个。但是,这在浮出控件出现时不起作用。它们立即处于不透明状态:1,即使延迟时间很长,它仍然不起作用。

有没有办法解决这个问题?我知道 CSS 动画与同一元素上的显示更改一起不起作用,但发现任何子动画也不起作用有点令人沮丧。当 CSS 如此简单时,我宁愿不必编写 javascript。但如果 javascript 是唯一的答案,那么这将是一个简单的解决方案。

这是一个非常简化的代码示例:

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

“in”是导致列转换的类:

.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;
}

【问题讨论】:

  • 请发布您当前菜单代码的简化版本

标签: jquery css jquery-animate css-transitions css-animations


【解决方案1】:

有没有办法解决这个问题?我知道 CSS 动画与同一元素上的显示更改一起不起作用,但发现任何子动画也不起作用有点令人沮丧。

它不仅适用于同一个元素,还适用于整个子树——因为整个子树没有被渲染。

  • 您可以在包装器上设置display: block,然后强制回流(通过使用wrapperElement.offsetHeight; 刷新样式缓冲区),然后添加一个设置opacity:1 的类给您的孩子(或做任何您正在做的事情)开始动画)。
  • 您可以使用不同的方法在视觉上隐藏您的包装,例如width: 0; height: 0; overflow: hidden; visibility: hidden;(或者,为了更好的过渡transform: scale(0); visibility: hidden; pointer-events: none;

一旦涉及到display:none,当涉及到转换时,你就会被搞砸。最好的方法是避免它。很长一段时间以来,我一直在使用第二个选项,没有出现任何重大问题。


在 OP 添加一些演示代码后编辑:

  • 包装器的 .animate() 也可以在 CSS 中完成
  • 不仅要使用供应商前缀的 CSS 属性 -webkit-transition,还要使用正确的 transition
  • // delay increases with each column 看起来像是一个误解。选择器.columns > li:first-child 适用的所有元素都将具有完全相同的延迟——它们不会等待前一个元素完成其转换。如果你想在 CSS 中定义它,你必须使用 :nth-child() 或其表亲之一

【讨论】:

  • 如果我遵循您的第二个建议,可以完成 .animate,但这在某些版本的 IE 中不起作用,我必须支持。我使用 -webkit 是因为我只在 chrome 中进行原型设计,所以在更最终的代码之前这只是习惯。使以后更容易返回并确定我需要在哪里添加其他供应商前缀。而且,我有 nth-child 选择器,我只是为了简洁没有包括它们。
【解决方案2】:

如果您只想更改opacity,您可以使用JQuery 的FadeInFadeOut 函数,但如果您想要更复杂的转换,您可以使用CSS3(this 是一个非常好的库)。 看到这个DEMO,你可以看到这两种不同的方式。

你也可以像这样向类添加一个控件:

    $("OBJECT").click(function(){
    if ($("OBJECT").hasClass("CLASS")){
        $("OBJECT").removeClass("CLASS");
    } else {
        $("OBJECT").addClass("CLASS");
    }
});

实现双向功能。

$(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>

【讨论】:

    【解决方案3】:

    前段时间我遇到了同样的问题,我的解决方法很老套,但大部分都有效

    当你改变一个,比如说,不可转换的属性,比如“显示”,事情很快就出错了,我想如果你用一个定时器来改变不可转换的属性,几毫秒后你改变另一个可转换的属性,它有点工作,你还需要使用另一个计时器来扭转局面

    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>
    

    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

    $('.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);
    })
    

    这是一个工作示例 https://codepen.io/Teobis/pen/QxmqGQ

    希望对你有帮助

    【讨论】:

      【解决方案4】:

      @rodneyrehm 的 answer 几乎总结了您在使用 css display 属性处理动画时所需的一切。

      您需要在切换显示属性后触发重排并在其后应用动画类。

      // 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>

      【讨论】:

      • text.outerWidth() 在这里做什么?
      • @sol text.outerWidth() 主要用于在我们更改元素的显示属性并让浏览器确认DOM已更改后触发重排
      【解决方案5】:

      如果可能的话,用 div 包裹父级。 然后那个 div 将是您的不透明度过渡,而您的原始父级将显示 none

      <div class="wrapper">
          <div class="parent">
              <div class="child">Content</div>
      
          </div>
      </div>
      
      .wrapper{ opacity: 0; transition: all 0.5s; }
      .parent{ display: none; }
      .wrapper:hover{ opacity: 1;}
      .parent{ display: block; }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-23
        • 1970-01-01
        • 2023-02-18
        • 2020-11-10
        相关资源
        最近更新 更多