【问题标题】:CSS transition on an initially hidden elemement最初隐藏元素上的 CSS 过渡
【发布时间】:2014-07-24 07:43:09
【问题描述】:

我想对设置了display: none 的元素进行css 转换。考虑以下代码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>CSS Transition From Hidden</title>

        <style type="text/css">
            div {
                -webkit-transition-property: all;
                -webkit-transition-duration: 2s;
            }       

            div.hidden {
                display: none;
                opacity: 0;
            }    

            div.from {
                opacity: 0;
            }
        </style>     

        <script type="text/javascript">
            function loaded() {
                var e = document.getElementById("foo");
                e.className = "from";
                window.webkitRequestAnimationFrame(function(t) {
                    e.className = null;
                });
            }
        </script>
    </head>
    <body onload="loaded()">
        <div id="foo" class="hidden">
            My test div
        </div>
    </body>
</html>

我想从class="div.hidden"class="",即从display: none; opacity: 0;display: block; opacity: 1; 但是,在 chrome 中(至少)一个具有display: none 的对象没有动画。元素立即进入结束状态。

我的解决方法是首先将元素设置为display: block; opacity: 0;,然后在下一帧中进行转换(使用requestAnimationFrame()。这有点尴尬,我找不到任何解释这种行为在spec 中。我知道我可以使用visibility-属性,但我不想使用它,因为我不想布置隐藏元素。

所以,问题是:这是正确的行为还是错误?如果这是正确的行为,是否有更好的方法来编写代码?请注意,我不是在问是否有任何库可以做到这一点,我想知道是否有更好的方法可以直接在 DOM 上做到这一点。

【问题讨论】:

    标签: css css-transitions


    【解决方案1】:

    关于这是否在规范中的问题,www-style@w3.org 列表here 上有一个有趣的线程。我还没有全部读完,但似乎他们没有从 none 开始动画,并且过渡规范也需要澄清这一点。

    更新:我询问了邮件列表,我得到了一个工作组会议的minutes 的链接,会议决定如果开始状态为@987654324 则不应进行转换@。

    要确保执行过渡,您必须确保在将动画属性设置为新目标之前计算动画属性的值。当显示设置为无时,通常不计算值。这是一个工作示例:

    <!DOCTYPE HTML>
    <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
        <title>Fade</title>
    
        <style>
          .hidden { display: none }
          .start { opacity: 0 }
          .transition { opacity: 1; -webkit-transition: opacity 1s }
        </style>
      </head>
      <body>
        <div id='div' class="hidden">Test</div>
    
        <script>
          var elem = document.getElementById('div');
    
          function ontransitionend(event) {
            elem.className = null;
            elem.removeEventListener('transitionend', ontransitionend);
          }
          elem.addEventListener('transitionend', ontransitionend);
    
          elem.className = 'start';
          window.getComputedStyle(elem).opacity;
          elem.className = 'transition';
        </script>
      </body>
    </html>
    

    请注意,您必须访问 opacity 属性。打getComputedStyle()是不够的!

    【讨论】:

      【解决方案2】:

      您不一定要中继 transitionend 回调。
      要在 opacity 属性(或其他属性)上显示一个最初具有 display:none 的隐藏元素,只需使用内联样式设置 display:block 然后删除您的 CSS 类 .hidden 以根据需要为元素设置动画:

      CSS:

      #foo {
          display: none;
          opacity: 1;
          /*optional, other ending properties...*/
          transition: opacity 1s;
      }
      .hidden {
          opacity: 0;
          /*optional, other starting properties...*/
      }
      

      HTML:

      <div id="foo" class="hidden">
          My test div
      </div>
      

      最后,用过渡显示元素的 javascript 部分:

      var elem = document.getElementById('foo');
      elem.style.display = 'block';
      elem.classList.remove('hidden');
      

      【讨论】:

        【解决方案3】:

        有几个 css 属性不能小步递增(display 的值是noneblock 之间的 25%?),尤其是那些具有非数值的属性。您描述的解决方法几乎是处理此问题的标准方法。例如,jQuery 在其 fadeInfadeOut 方法中使用了类似的东西。

        如果您想要动画从不占用空间到标准布局的转换,您可以转换heightwidth 属性。

        【讨论】:

        • 我并不是说display 属性上应该有动画。我将display 设置为阻止并且(在这种情况下)opacity 已更改。这就是转换的工作方式。您在transition-property 中列出的属性是动画的,其余的会立即设置。为什么display 不一样?
        • 不,不是我不想让它不占空间。它应该花费很少的时间。隐藏的元素可能非常多且复杂(幻灯片)。
        • @TobiasRitzau 你的意思是立即设置不透明度吗?
        • 是的,不是2s淡入,而是直接将不透明度设置为1。
        • @TobiasRitzau 如果您删除 display:none 并使用完全相同的代码仅用于不透明度,它是否正常工作?
        【解决方案4】:

        显示:无意味着您可以到达该元素,但首先您应该确保 元素已被渲染。 您可以在 jquery 中使用 ready 函数或在 javascript 中实现它以确保元素存在。 您可以使用以下方法执行上述操作:javascript(使用计时器增加不透明度)或 jquery,如下所示

        <html>
            <head>
                <meta charset="utf-8">
                <title>CSS Transition From Hidden</title>
        
            <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
            <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
                <style type="text/css">
        
                    div.hidden {
                        display: none;
                        opacity: 0;
                    }    
        
                            </style>     
        
                <script type="text/javascript">
        $.ready = function () {
        
                        $("#foo").fadeIn(2000);
        
                    }
                </script>
            </head>
            <body>
                <div id="foo" class="hidden">
                    My test div
                </div>
            </body>
        </html>
        

        【讨论】:

        • 元素在那里。这不是问题。当然我可以使用库,但我想知道是否有更好的方法可以直接在 DOM 上实现它。我会在问题中澄清这一点。
        • 是的,你可以在javascript中创建计时器来增加不透明度
        • 但是,这样更好吗? (在这种情况下兼容性不是问题)
        • 是的,它是兼容的,因为我们将在计时器内更改 div 的类
        • 这不是你使用 jQuery 的方式(它是一个函数,而不是一个属性)。这不是使用 CSS 过渡。
        【解决方案5】:

        我有同样的问题,我认为浏览器不应该将其视为可接受的行为。问题不在于有人试图为实际的显示属性设置动画。它是你不能有一个带有 display: none 的元素,将属性更新为 inline 或其他任何东西,然后为不透明度设置动画,例如,即使你在显示更新后设置了 10 秒的超时时间也是如此。

        我现在的解决方法是将宽度和高度设置为 0,溢出到隐藏,更新这些值,然后更新动画属性。至少它的行为更像是不显示而不是隐藏可见性。

        【讨论】:

          【解决方案6】:

          display:none 提升动画效果。很遗憾,我认为应该由浏览器解决。我之前通过将 z-index 设置为 -1 来解决这个问题,这会隐藏元素,如果绝对定位也会将其从静态布局中删除。您实际上可以转换 z-index(尽管它看起来不像动画),因此不会弄乱不透明动画。

          这对我的应用程序很有效,尽管我最终不得不使用 JavaScript 将 display 属性从 none 设置为 block,因为我最终需要在 overflow:auto 元素中使用淡入淡出元素,当它是'不隐藏,在不希望的时间创建滚动条。

          【讨论】:

          • 感谢您的回复。当然,有一些解决方法(就像我发布的那样),我想知道这是否符合规范(指出我在哪里),我正在寻找更好的方法来实现它。我猜想负 z-index 有效,因为该项目放在身体后面,或者?无论如何,我看不出这有什么帮助。我发布的代码有效,但如果这是应该实现的方式,那就太奇怪了:S 我根本不明白为什么你不能从“display:none”中制作动画
          猜你喜欢
          • 2013-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-14
          • 2019-06-18
          • 2021-04-23
          • 2015-05-23
          相关资源
          最近更新 更多