显示器上的转换:属性

我目前正在devise一种CSS“mega dropdown”菜单 – 基本上是一个普通的CSS下拉菜单,但是包含不同types的内容。

目前看来,CSS3过渡不适用于'显示'属性,即你不能做任何forms的从display: nonedisplay: block (或任何组合)的过渡。

任何人都可以想到一个方法来从上面的例子中的第二层菜单“淡入”,当有人hover在顶级菜单项之一?

我知道你可以使用visibility:属性的转换,但我想不出有效利用它的方法。

我也尝试过使用高度,但只是失败了。

我也意识到使用JavaScript实现这一点是微不足道的,但是我想挑战自己只使用CSS,而且我认为我有点短了。

所有和任何build议最受欢迎。

你可以连接两个或更多的转换,而这次的visibility是非常方便的。

 div { border: 1px solid #eee; } div > ul { visibility: hidden; opacity: 0; transition: visibility 0s, opacity 0.5s linear; } div:hover > ul { visibility: visible; opacity: 1; } 
 <div> <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> </div> 

您需要通过其他方式隐藏该元素才能使其工作。

我通过绝对定位<div>并将隐藏的设置为opacity: 0来实现效果opacity: 0

如果你甚至将display属性从none切换到block ,你的其他元素的转换将不会发生。

要解决这个问题,请始终允许该元素为display: block ,但通过调整以下任何方法来隐藏该元素:

  1. height设置为0
  2. opacity设置为0
  3. 将元素放置在另一个overflow: hidden元素的框架之外overflow: hidden

有可能有更多的解决scheme,但是如果您切换元素以display: none ,则不能执行转换。 例如,你可能试图尝试这样的事情:

 div { display: none; transition: opacity 1s ease-out; opacity: 0; } div.active { opacity: 1; display: block; } 

但是那不行 。 根据我的经验,我发现这无所作为。

正因为如此,你总是需要保持元素display: block – 但你可以通过做这样的事情绕过它:

 div { transition: opacity 1s ease-out; opacity: 0; height: 0; overflow: hidden; } div.active { opacity: 1; height: auto; } 

在这篇文章的时候,如果您尝试更改display属性,所有主stream浏览器将禁用CSS转换,但CSSanimation仍然可以正常工作,因此我们可以将它们用作解决方法。

示例代码: – (您可以将其应用到您的菜单相应) 演示

将以下CSS添加到您的样式表中: –

 @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } 

然后将fadeInanimation应用到父级hover上的子级上: – (当然,设置display: block

 .parent:hover .child { display: block; -webkit-animation: fadeIn 1s; animation: fadeIn 1s; } 

我怀疑,如果“显示”被改变,转换被禁用的原因是因为显示实际上做了什么。 它不会改变任何可以想象的顺利animation。

“display:none;”和“visibility:hidden;”是两个完全不同的东西。 两者都具有使元素不可见的效果,但“可见性:隐藏”的效果仍然呈现在布局中,但不是明显如此。 隐藏的元素仍然占用空间,仍然呈现为内联或块,内联或表格或“显示”元素告诉它呈现为,并相应地占用空间。 其他元素不会自动移动占据该空间。 隐藏的元素只是不会将其实际像素渲染到输出中。

另一方面,“display:none”实际上阻止了元素完全呈现。 它不占用任何布局空间。 其他会占据这个元素占据的部分或全部空间的元素现在将调整占据这个空间,就像这个元素完全不存在一样

“显示”不只是另一个视觉属性。 它build立了元素的整个渲染模式,比如是块,内联,内嵌块,表格,表格,单元格,列表项还是其他的东西! 其中每一个都有非常不同的布局分支,并且没有合理的方式来进行animation或平滑过渡(试图想象从“块”到“内联”的平滑过渡,反之亦然)。

这就是为什么如果显示更改(如果更改是从“none” – “none”不仅仅是不可见性,它是它自己的元素渲染模式,意味着根本不渲染!

我知道这是一个非常古老的问题,但是对于正在查看此线程的人员,现在可以将自定义animation添加到块属性。

 @keyframes showNav { from {opacity: 0;} to {opacity: 1;} } .subnav-is-opened .main-nav__secondary-nav { display: block; animation: showNav 250ms ease-in-out both; } 

演示

在这个演示中,子菜单从display:none更改为display:block并且仍然设法淡入淡出。

根据W3C工作草案2013年11月19日 display不是一个animation的属性 。 幸运的是, visibility是可以animation的。 你可以通过不透明的转换( JSFiddle )来链接它的转换:

  • HTML:

     <a href="http://example.com" id="foo">Foo</a> <button id="hide-button">Hide</button> <button id="show-button">Show</button> 
  • CSS:

     #foo { transition-property: visibility, opacity; transition-duration: 0s, 1s; } #foo.hidden { opacity: 0; visibility: hidden; transition-property: opacity, visibility; transition-duration: 1s, 0s; transition-delay: 0s, 1s; } 
  • 用于testing的JavaScript:

     var foo = document.getElementById('foo'); document.getElementById('hide-button').onclick = function () { foo.className = 'hidden'; }; document.getElementById('show-button').onclick = function () { foo.className = ''; }; 

请注意,如果您只是使链接透明,而不设置visibility: hidden ,那么它将保持可点击。

我整洁的JavaScript技巧是将整个场景分成两个不同的function

准备事情,一个全局variables被声明,一个事件处理程序被定义:

  var tTimeout; element.addEventListener("transitionend", afterTransition, true);//firefox element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome 

然后,当隐藏元素时,我使用这样的东西:

 function hide(){ element.style.opacity = 0; } function afterTransition(){ element.style.display = 'none'; } 

为了重现元素,我正在做这样的事情:

 function show(){ element.style.display = 'block'; tTimeout = setTimeout(timeoutShow, 100); } function timeoutShow(){ element.style.opacity = 1; } 

它到目前为止工作!

编辑:在这个例子中,display none没有被应用。

 @keyframes hide { 0% { display: block; opacity: 1; } 99% { display: block; } 100% { display: none; opacity: 0; } } 

上面发生的事情是,通过99%的animation显示设置为阻止,而不透明度淡出。 在最后一刻显示属性设置为无。

最重要的是使用animation-fill-mode:forwards保留animation结束后的最后一帧

 .hide { animation: hide 1s linear; animation-fill-mode: forwards; } 

这里有两个例子: https : //jsfiddle.net/qwnz9tqg/3/

今天我遇到了一个问题position: fixed模式,我正在重复使用。 我无法保持它display: none ,然后animation,因为它刚刚跳到外观,和z-index (负值等)做了奇怪的事情。

我也在使用height: 0height: 100% ,但只有在模态出现时才起作用。 这和你使用left: -100%

然后它让我感到有一个简单的答案。 Et瞧:

首先,你的隐藏模式。 注意height0 ,并检查过渡中的height声明…它有一个500ms这比我的opacity过渡更长 。 请记住,这会影响正在进行的淡出转换:将模式返回到默认状态。

 #modal-overlay { background: #999; background: rgba(33,33,33,.2); display: block; overflow: hidden; height: 0; width: 100%; position: fixed; top: 0; left: 0; opacity: 0; z-index: 1; -webkit-transition: height 0s 500ms, opacity 300ms ease-in-out; -moz-transition: height 0s 500ms, opacity 300ms ease-in-out; -ms-transition: height 0s 500ms, opacity 300ms ease-in-out; -o-transition: height 0s 500ms, opacity 300ms ease-in-out; transition: height 0s 500ms, opacity 300ms ease-in-out; } 

其次,你的可见模态。 假设你正在为body设置一个.modal-active 。 现在height100% ,我的转变也改变了。 我希望立刻改变heightopacity需要300ms

 .modal-active #modal-overlay { height: 100%; opacity: 1; z-index: 90000; -webkit-transition: height 0s, opacity 300ms ease-in-out; -moz-transition: height 0s, opacity 300ms ease-in-out; -ms-transition: height 0s, opacity 300ms ease-in-out; -o-transition: height 0s, opacity 300ms ease-in-out; transition: height 0s, opacity 300ms ease-in-out; } 

就这样,它就像一个魅力。

从其中一些答案和其他一些build议,下面的工作伟大的hover菜单(我使用bootstrap 3,具体):

 nav .dropdown-menu { display: block; overflow: hidden; max-height: 0; opacity: 0; transition: max-height 500ms, opacity 300ms; -webkit-transition: max-height 500ms, opacity 300ms; } nav .dropdown:hover .dropdown-menu { max-height: 500px; opacity: 1; transition: max-height 0, opacity 300ms; -webkit-transition: max-height 0, opacity 300ms; } 

如果您自height:auto指定了两个值,则也可以使用height代替max-height height:auto不允许使用transitionmax-height的hover值需要大于菜单的height

更改overflow:hidden overflow:visible 。 它效果更好。 我使用这样的:

 #menu ul li ul { background-color:#fe1c1c; width:85px; height:0px; opacity:0; box-shadow:1px 3px 10px #000000; border-radius:3px; z-index:1; -webkit-transition:all 0.5s ease; -moz-transition:all 0.6s ease; } #menu ul li:hover ul { overflow:visible; opacity:1; height:140px; } 

visible是更好,因为overflow:hidden行为完全像一个display:none

没有JavaScript要求,并没有蛮大的巨大的最大高度需要。 相反,请在文本元素上设置最大高度,然后使用像rem或em这样的字体相关单位。 这样,您可以设置最大高度大于您的容器,同时避免延迟或菜单closures时的“popup”:

HTML

 <nav> <input type="checkbox" /> <ul> <li>Link 1</li> <li>Link 1</li> <li>Link 1</li> <li>Link 1</li> </ul> </nav> 

CSS

 nav input + ul li { // notice I set max-height on li, not ul max-height: 0; } nav input:checked + ul li { max-height: 3rem; // a little bigger to allow for text-wrapping - but not outrageous } 

在这里看一个例子: http : //codepen.io/mindfullsilence/pen/DtzjE

我怀疑任何人只要开始CSS转换很快发现,如果你同时修改显示属性(块/无)他们不工作。 一种尚未提到的解决方法是,您可以继续使用display:block / none来隐藏/显示元素,但将其不透明度设置为0,以便即使在display:block时仍然不可见。 然后将其淡入,添加另一个CSS类,如“on”,将不透明度设置为1,并为不透明度定义转换。 正如你可能已经想象的那样,你必须使用JavaScript来将“on”类添加到元素,但至less你仍然在使用CSS来进行实际的转换。

PS如果您发现自己处于需要同时显示:block和添加class on的情况,则同时使用setTimeout延迟后者。 否则,浏览器只能看到两个事情一次发生,并禁用转换。

在吉列尔莫接受的答案写成后,2012年4月3日的CSS转换规范改变了可视化转换的行为, 现在可以在不使用转换延迟的情况下以更短的方式解决这个问题

 .myclass > div { transition:visibility 1s, opacity 1s; visibility:hidden; opacity:0 } .myclass:hover > div { visibility:visible; opacity:1 } 

为两个转换指定的运行时间通常应该是相同的(尽pipe稍长的可见时间不是问题)。 对于正在运行的版本,请参阅我的博客http://www.taccgl.org/blog/css-transition-visibility.html#visibility-opacity

关于“显示器上的转换:属性”以及对于来自Rui Marques和Josh的评论的回答,可以接受的答案是:这种解决scheme在与使用显示或可见性属性无关的情况下工作在这个问题是这样的)。 它不会完全删除元素,如display:none,只是使其不可见,但仍然保留在文档stream中,影响后续元素的位置。 完全删除类似于显示的元素的转换:无可以使用height(如其他答案和注释所示),max-height或margin-top / bottom来完成,还请参阅如何转换height:0; 到高度:auto; 使用CSS? 和我的博客http://www.taccgl.org/blog/css_transition_display.html

作为对GeorgeMillo的评论的回应:需要两个属性和两个转换:不透明属性用于创build淡入淡出animation和可见性属性,以避免元素仍然对鼠标事件作出反应。 不透明度需要转换视觉效果和延迟隐藏的可视性,直到淡出完成。

我觉得用这么多答案回答问题差不多,但是这个解决scheme有很好的兼容性,我还没有看到:

 .hidden-element { position: absolute; z-index: -1; pointer-events: none; visibility: hidden; opacity: 0; transition: visibility 0s, opacity .5s ease-out; } .hidden-element.visible { position: static; z-index: auto; pointer-events: auto; visibility: visible; opacity: 1; } 

说明 :它使用visibility: hidden技巧(与“显示 – animation”兼容),但使用组合position: absolute; z-index: -1; pointer-events: none; position: absolute; z-index: -1; pointer-events: none; 确保隐藏的容器不占用空间并且不回答用户交互

我认为SalmanPK有最接近的答案,它使用以下CSSanimation淡入或淡出项目。 然而,显示属性并不平滑,只有不透明度。

 @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @-webkit-keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } 

如果你想animation元素从显示块移动到显示无,我不能看到它是目前可能只是用CSS,你必须得到高度,并使用CSSanimation降低高度。 如下面的例子所示,这可以通过CSS来实现,但是要知道需要为元素设置animation效果的确切高度值将非常困难。

jsFiddle的 例子

CSS

 @-webkit-keyframes pushDown { 0% { height: 10em; } 25% { height: 7.5em; } 50% { height: 5em; } 75% { height: 2.5em; } 100% { height: 0em; } } .push-down { -webkit-animation: pushDown 2s forwards linear; } 

JavaScript的

 var element = document.getElementById("element"); // push item down element.className = element.className + " push-down"; 

您可以将元素“屏幕外”存储到您需要的位置,而不是使用显示器,然后将其位置设置到您想要的位置并同时进行转换。 这引起了一大堆其他devise问题,所以ymmv。 您可能不想使用显示器,因为您希望屏幕阅读器可以访问内容,而屏幕阅读器大部分都试图遵守可见性规则 – 即,如果它不应该是可见的,它不会显示为代理的内容。

这个问题的最简单的通用解决scheme是:随意在CSS中指定display:none ,但是您将使用JavaScript更改它以block (或其他),然后您还必须为您的元素添加一个类这个问题实际上是用setTimeout()进行的 。 就这样。

即:

 <style> #el { display: none; opacity: 0; } #el.auto-fade-in { opacity: 1; transition: all 1s ease-out; /* future, future, please come sooner! */ -webkit-transition: all 1s ease-out; -moz-transition: all 1s ease-out; -o-transition: all 1s ease-out; } </style> <div id=el>Well, well, well</div> <script> var el = document.getElementById('el'); el.style.display = 'block'; setTimeout(function () { el.className = 'auto-fade-in' }, 0); </script> 

在最新的理智浏览器中进行testing。 显然不应该在IE9或更早版本中工作。

您可以简单地使用CSS 可见性 :hidden / visible而不是display :none / block

 div { visibility:hidden; -webkit-transition: opacity 1s ease-out; -moz-transition: opacity 1s ease-out; -o-transition: opacity 1s ease-out; transition: opacity 1s ease-out; opacity: 0; } parent:hover > div { opacity: 1; visibility: visible; } 

你也可以使用这个:

 .dropdown { height: 0px; width: 0px; opacity: .0; color: white; } .dropdown:hover { height: 20px; width: 50px; opacity: 1; transition: opacity 200ms; /* Safari */ -webkit-transition: opacity 200ms; } 

你可以用你想要的自然的方式工作 – 使用显示 – 但是你必须调整浏览器才能使用JS,或者使用JS或者其他人使用一个标签来表示一个奇妙的技巧。 我不关心内部标签,因为它进一步复杂的CSS和尺寸,所以这里的JS解决scheme:

https://jsfiddle.net/b9chris/hweyecu4/1/

从一个盒子开始:

 <div class="box hidden">Lorem</div> 

一个隐藏的盒子。 您可以通过点击进行转换:

 function toggleTransition() { var el = $("div.box1"); if (el.length) { el[0].className = "box"; el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() { el[0].className = "box hidden"; }); } else { el = $("div.box"); el[0].className = "box"; el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() { el[0].className = "box box1"; }); } return el; } someTag.click(toggleTransition); 

CSS是你猜到的:

 .hidden { display: none; } .box { width: 100px; height: 100px; background-color: blue; color: yellow; font-size: 18px; left: 20px; top: 20px; position: absolute; -webkit-transform-origin: 0 50%; transform-origin: 0 50%; -webkit-transform: scale(.2); transform: scale(.2); -webkit-transition: transform 2s; transition: transform 2s; } .box1{ -webkit-transform: scale(1); transform: scale(1); } 

关键是限制显示属性。 通过删除隐藏的类然后等待50ms, 然后通过添加的类开始转换,我们得到它,然后展开像我们想要的,而不是它只是没有任何animation的屏幕上。 类似的情况发生在另一个方向,除了我们在应用隐藏之前等到animation结束。

注意:我在这里滥用.animate(maxWidth)来避免setTimeout竞争条件。 setTimeout很快就会引入隐藏的错误,当你或者别人拿起代码不知道的时候。 .animate()很容易被.stop()所杀死。 我只是用它在标准fx队列上放置50ms或2000ms的延迟,在这个队列中很容易find/解决这个问题。

你可以用转换事件来做到这一点,所以你为转换创build了2个css类,一个持有其他animation,保持显示无状态。 并在animation结束后切换它们? 在我的情况下,我可以再次显示div,如果我按btn,并删除这两个类。

尝试下面的剪辑…

 $(document).ready(function() { //assign transition event $("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) { //we check if this is the same animation we want if (event.originalEvent.animationName == "col_hide_anim") { //after the animation we assign this new class that basically hides the elements. $(this).addClass("animation-helper-display-none"); } }); $("button").click(function(event) { $("table tr .hide-col").toggleClass(function() { //we switch the animation class in a toggle fashion... //and we know in that after the animation end, there is will the animation-helper-display-none extra class, that we nee to remove, when we want to show the elements again, depending on the toggle state, so we create a relation between them. if ($(this).is(".animation-helper-display-none")) { //im toggleing and there is already the above classe, then what we want it to show the elements , so we remove both classes... return "visibility_switch_off animation-helper-display-none"; } else { //here we just want to hide the elements, so we just add the animation class, the other will be added later be the animationend event... return "visibility_switch_off"; } }); }); }); 
 table th { background-color: grey; } table td { background-color: white; padding:5px; } .animation-helper-display-none { display: none; } table tr .visibility_switch_off { animation-fill-mode: forwards; animation-name: col_hide_anim; animation-duration: 1s; } @-webkit-keyframes col_hide_anim { 0% {opacity: 1;} 100% {opacity: 0;} } @-moz-keyframes col_hide_anim { 0% {opacity: 1;} 100% {opacity: 0;} } @-o-keyframes col_hide_anim { 0% {opacity: 1;} 100% {opacity: 0;} } @keyframes col_hide_anim { 0% {opacity: 1;} 100% {opacity: 0;} } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <table> <theader> <tr> <th>Name</th> <th class='hide-col'>Age</th> <th>Country</th> </tr> </theader> <tbody> <tr> <td>Name</td> <td class='hide-col'>Age</td> <td>Country</td> </tr> </tbody> </table> <button>Switch - Hide Age column with fadeout animation and display none after</button> 

It can be handle by using transition timing functions step-end and step-start

For example: https://jsfiddle.net/y72h8Lky/

 $(".run").on("click", function() { $(".popup").addClass("show"); }); $(".popup").on("click", function() { $(".popup").removeClass("show"); }) 
 .popup { opacity: 0; display: block; position: absolute; top: 100%; bottom: 0; left: 0; right: 0; z-index: 1450; background-color: rgba(0, 175, 236, 0.6); transition: opacity 0.3s ease-out, top 0.3s step-end; } .popup.show { transition: opacity 0.3s ease-out, top 0.3s step-start; opacity: 1; top: 0; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="popup"></div> <button class="run" style="font-size: 24px;">Click on me</button> 

I started an open source skeleton project called Toggle Display Animate

https://marcnewton.github.io/Toggle-Display-Animate/

This skeleton helper will allow you to easily mimic jQuery show/hide but with in/out CSS3 transition animations.

It uses class toggles so you can use any css methods you want on elements besides display:none|block|table|inline etc as well as other alternate uses that can be thought up.

Its main design purpose is for element toggle states, it supports a revert state where hiding the object allows you to run your keyframe in reverse or play an alternate animation for hiding the element.

Most of the markup for the concept I am working on is CSS, there is very little javascript actually used.

There is a demo here: http://marcnewton.co.uk/projects/toggle-display-animate/

I've came across this issue multiple times and now simply went with:

 .block { opacity: 1; transition: opacity 250ms ease; } .block--invisible { pointer-events: none; opacity: 0; } 

By adding the class block--invisible the whole Elements will not be clickable but all Elements behind it will be because of the pointer-events:none which is supported by all major browsers.

I finally found a solution for me, by combining opacity with position absolute (not to occupy space when hidden).

 .toggle { opacity: 0; position: absolute; transition: opacity 0.8s; } .parent:hover .toggle { opacity: 1; position: static; } 

There is a alternate solution with css animation for drop-down hidden:

 .dropdown{ position: relative; width: 100%; -webkit-animation-name: animatetop; -webkit-animation-duration: 0.4s; animation-name: animatetop; animation-duration: 0.4s } /* Add Animation */ @-webkit-keyframes animatetop { from {top:-300px; opacity:0} to {top:0; opacity:1} } @keyframes animatetop { from {top:-300px; opacity:0} to {top:0; opacity:1} }