我目前正在设计一个CSS“巨型下拉菜单”——基本上是一个常规的仅限CSS的下拉菜单,但包含不同类型的内容。

目前,CSS 3转换似乎不适用于“display”属性,也就是说,您不能进行从display:none到display:block(或任何组合)的任何转换。

当有人悬停在一个顶级菜单项上时,上面示例中的第二层菜单是否有办法“淡入”?

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

我也尝试过使用高度,但那只是失败得很惨。

我也意识到,使用JavaScript实现这一点很简单,但我想挑战一下自己,只使用CSS,我觉得我做得有点短。


当前回答

现在可以向块特性添加自定义动画。

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

Demo

在这个演示中,子菜单从display:none变为display:block,并且仍然能够淡入淡出。

其他回答

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

我通过绝对定位<div>s并将隐藏的<div>设置为不透明度:0来实现这一效果。

如果您甚至将显示属性从“无”切换为“块”,则不会在其他元素上进行转换。

要解决此问题,请始终允许元素显示为:块,但通过调整以下任何方式隐藏元素:

将高度设置为0。将不透明度设置为0。将元素放置在另一个溢出的元素的框架之外:隐藏。

可能有更多的解决方案,但如果将元素切换为显示:无,则无法执行转换。例如,您可以尝试以下操作:

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

你可以让它以你所期望的自然方式工作-使用显示-但你必须限制浏览器才能让它工作,要么使用Javascript,要么像其他人建议的那样,使用一个标签放在另一个标签内的花式技巧。我不关心内部标记,因为它会使CSS和维度更加复杂,所以这里是Javascript解决方案:

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

以如下框开头:

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

一个隐藏的盒子。

div.hidden {
    display: none;
}
#box {
    transition: opacity 1s;
}
    

我们将使用相关问答中的技巧,检查offsetHeight以立即限制浏览器:

https://stackoverflow.com/a/16575811/176877

首先,库将上述技巧正规化:

$.fn.noTrnsn = function () {
    return this.each(function (i, tag) {
        tag.style.transition = 'none';
    });
};
$.fn.resumeTrnsn = function () {
    return this.each(function (i, tag) {
        tag.offsetHeight;    
        tag.style.transition = null;
    });
};

接下来,我们将使用它来显示一个框,并将其淡入:

$('#button').on('click', function() {
    var tag = $('#box');
    if (tag.hasClass('hidden'))
        tag.noTrnsn().removeClass('hidden')
        .css({ opacity: 0 })
        .resumeTrnsn().css({ opacity: 1 });
    else
        tag.css({ opacity: 0 });
});

这会使盒子变暗。因此,.noTrnsn()关闭了转换,然后我们删除了隐藏类,该类将显示从“无”转换为默认的“块”。然后,我们将不透明度设置为0,为淡入做好准备。现在,我们已经设置了阶段,我们使用.resumeTrnsn()重新打开过渡。最后,通过将不透明度设为1开始过渡。

如果没有该库,对显示的更改和对不透明度的更改都会导致不理想的结果。如果我们简单地删除了库调用,我们根本不会得到转换。

请注意,上述操作不会在渐变动画结束时再次将显示设置为无。不过我们可以变得更漂亮。让我们用一个从0开始逐渐变高的渐变。

想要

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

#box {
    transition: height 1s, opacity 1s;
}

我们现在正在转换高度和不透明度。注意,我们没有设置高度,这意味着它是默认值,自动。传统上,这是无法转换的——从自动转换为像素值(如0)不会导致转换。我们将使用库和另一个库方法来解决这个问题:

$.fn.wait = function (time, fn) {
    if (time)
        this.delay(time);
    if (!fn)
        return this;

    var _this = this;
    return this.queue(function (n) {
        fn.call(_this);
        n();
    });
};

这是一种方便的方法,可以让我们参与jQuery现有的fx/animation队列,而不需要jQuery3.x中现在排除的任何动画框架。

让我们设置向下滑动效果的动画。

$('#button').on('click', function() {
    var tag = $('#box');
    if (tag.hasClass('hidden')) {
        // Open it
        // Measure it
        tag.stop().noTrnsn().removeClass('hidden').css({
            opacity: 0, height: 'auto'
        });
        var h = tag.height();
        tag.css({ height: 0 }).resumeTrnsn()
        // Animate it
        .css({ opacity: 1, height: h })
        .wait(1000, function() {
            tag.css({ height: 'auto' });
        });
    } else {
        // Close it
        // Measure it
        var h = tag.noTrnsn().height();
        tag.stop().css({ height: h })
        .resumeTrnsn()
        // Animate it
        .css({ opacity: 0, height: 0 })
        .wait(1000, function() {
            tag.addClass('hidden');
        });
    }
});

这段代码首先检查#box以及它当前是否隐藏,然后检查它的类。但是,它使用wait()库调用实现了更多的功能,在滑动/淡出动画的末尾添加隐藏类,如果它实际上是隐藏的,您可以找到隐藏类-这是上面的简单示例无法做到的。这也会启用反复显示/隐藏元素,这在前面的示例中是一个错误,因为隐藏类从未恢复。

您还可以看到在.noTrnsn()之后调用CSS和类更改,以通常设置动画的阶段,包括进行测量,例如在调用.resumeTrnsn()之前测量#box的最终高度,而不向用户显示,并将其从完全设置的阶段动画化为其目标CSS值。

旧答案

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

您可以通过以下方式在单击时进行转换:

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

关键是限制显示属性。通过删除隐藏的类,然后等待50毫秒,然后通过添加的类开始转换,我们可以让它出现,然后像我们想要的那样展开,而不是只在屏幕上闪烁而没有任何动画。类似的情况会以相反的方式发生,只是我们要等到动画结束后再应用隐藏。

注意:我在这里滥用.animate(maxWidth)来避免setTimeout竞争条件。setTimeout很快就会在你或其他人不知道的情况下拾取代码时引入隐藏的错误。animate()可以很容易地用.stop()杀死。我只是用它在标准fx队列上设置50毫秒或2000毫秒的延迟,在这里,其他基于此构建的程序员很容易发现/解决。

您也可以使用此选项:

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

我感谢所有的回答。以下是我用于类似目的的内容:过渡与动画。

例子:https://jsfiddle.net/grinevri/tcod87Le/22/

<div class="animation"></div>
<div class="transition"></div>
@keyframes animationTo {
  0% { background-color: rgba(0, 0, 0, 0.1); }
  100% { background-color: rgba(0, 0, 0, 0.5); }
}

@keyframes animationFrom {
  0% { background-color: rgba(0, 0, 0, 0.5); }
  100% { background-color: rgba(0, 0, 0, 0.1); }
}

.animation,
.transition{
  margin: 5px;
  height: 100px;
  width: 100px;
  background-color: rgba(0, 0, 0, 0.1);
}

.animation{
  animation: animationFrom 250ms;
}

.animation:hover{
  background-color: rgba(0, 0, 0, 0.5);
  animation: animationTo 250ms;
}

.transition{
  transition: background-color 250ms;
}

.transition:hover{
  background-color: rgba(0, 0, 0, 0.5);
}

将溢出:隐藏更改为溢出:可见。它工作得更好。我这样使用:

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

可见更好,因为溢出:隐藏的行为与显示:无完全相同。