仅使用CSS的条纹状平滑过渡菜单

我最喜欢的网站之一是 stripe.com。有很多WebGL,但顶部的菜单具有非常酷的幻灯片效果,因此当您浏览它时,它似乎会变成下一个选项。我查看了它是如何制作的,其中有很多 Javascript 代码,但它让我思考是否可以仅使用 CSS 来完成类似的效果。

在本教程中,我们将介绍我是如何做到这一点的,以及我如何最终获得具有流畅动画的干净解决方案的一些细微差别。这是一个相当大的菜单,所以我建议过渡到小屏幕的汉堡菜单。

链接到演示

布局#

让我们谈谈布局。顶层菜单是一个弹性盒,均匀分布。在每个菜单项中都有一个子菜单,我们以 flex box 为中心justify-contents,然后绝对定位。

然后将每个子菜单定位为网格,每个子菜单中的布局都是使用grid-template. 所有宽度和尺寸都em使其易于使用,并且可以调整大小。基本结构如下图所示:

元素#

这里与典型菜单结构的唯一显着区别是在最后包含一个名为#sub-menu-container.

我们这样做的原因是我们必须将背景与内容分开以创建流畅的过渡效果。~我们在 CSS中使用波浪号或运算符,因为#sub-menu-container它是每个菜单项的兄弟,我们可以在用户将鼠标悬停在菜单项上时调整其位置。

这意味着我们可以平滑地过渡和动画背景的移动,如下面的视频所示:

由于它们是分开的,对于某些部分我们必须调整背景的位置,但这并不会太耗时em。因此,调整此效果的手动工作量保持在最低限度,如果我决定使用 SASS 或一点点 Javascript,可能会更少。不过,出于本教程的目的,我想保留纯 CSS。

剪辑路径圆角

所以它不是很出名,但clip-path: inset() 允许圆角边框。我们可以做类似的事情clip-path: inset(0 10% 0 0 round 10px),生成的矩形将具有border-radius: 10px. 就我们的目的而言,这真的很有用。我们可以剪辑背景层以动画其运动。

剪辑路径图标动画

我在这里使用的另一个微妙效果是clip-path箭头图标。当您将鼠标悬停在子菜单项上时,有时会出现一个箭头。使用剪辑路径,我们可以将其淡入。微妙,但效果很好。

带 CSS 的三角形

这是一个非常古老的技巧,但是用于指示活动子菜单的箭头是使用 CSS 使用边框属性生成的。其 CSS 如下所示:

    .menu-text:after {
        opacity: 0;
        content: '';
        position: absolute;
        pointer-events: none;
        bottom: -5em;
        left: calc(50% - 10px);
        border-color: transparent transparent white transparent;
        border-width: 10px;
        border-style: solid;
    }

向前……向后……#

由于我们在这里没有使用任何花哨的遮罩效果,并且背景与内容分离,如果我们不小心,我们可能会出现非常明显的没有意义的过渡,例如内容框外的文本过渡。为了避免这种情况,我们可以做两件事:

  • 为不透明度之类的东西设置过渡时间以限制这一点。
  • 在内容上使用clip-path它可以比背景的移动更快地为其消失设置动画。

这听起来很复杂,但本质上这意味着我们将clip-path内容与背景同步,以便内容消失并且不会流过背景的“边缘”,并且我们将使用更小的动画时间来实现不透明度,以便项目消失的速度比它们在奇怪的位置明显更快。

例如,当您没有将鼠标悬停在菜单项上时,clip-path菜单内容的 设置为实质上使内容不可见:

    .sub-menu {
        clip-path: inset(0 10em 10em 15em);
    }

然后在悬停时,我们可以撤消它,并使内容成为焦点。如果我们做得恰到好处,并且有足够好的过渡,我们会得到一个非常无缝的菜单弹出效果:

    .sub-menu {
        clip-path: inset(0 10em 10em 15em);
        opacity: 0;
        transition: all 0.25s ease-out, clip-path 0.15s ease-out;
        margin-left: -5em;
    }

    .sub-menu:hover {
        clip-path: inset(0 0 0 0);
        opacity: 1;
        margin-left: 0;
    }

为了说明我们在这里对内容所做的动画,请看一下应用于以下块的减速版本:

我们在背景上执行类似的动画,最终得到您可以在演示中找到的菜单效果。当与其他移动元素结合时,它会产生一种新的内容从边缘冲进来的效果。

仅使用 CSS 的动画顺序

当用户第一次将鼠标悬停在链接上时,我们会执行一个动画,其中背景似乎向内弯曲。然后当我们移动到下一个链接时,动画不再执行,而是背景合并到下一个选择中。那么,我们如何让两个动画在悬停时运行?

秘密依赖于动画和过渡。当您第一次将鼠标悬停在链接上时,我们会运行一个动画,但该动画只执行一次:

    nav .menu-item:hover ~ #sub-menu-container #sub-menu-holder {
        opacity: 1;
        right: auto;
        animation: clipPath 0.25s ease-out 1 forwards;
        transition: clip-path 0.25s ease-out 0s, left 0.15s ease-out 0s, height 0.15s ease-out 0s;
    }
    @keyframes clipPath {
        0% {
            opacity: 0;
        }
        100% {
            transform: rotateX(0deg) scale(1);
            top: 4.5em;
            opacity: 1;        
        }
    }    

    /* Example of specific clip path hover effect for 3rd item */
    nav .menu-item:nth-of-type(3):hover ~ #sub-menu-container #sub-menu-holder {
        clip-path: inset(0 15em 0 0 round 10px);
    }

运行初始动画后,我们将恢复为过渡。因此,当用户停留在菜单上时,动画已经运行,因此 CSS 将背景转换到下一个剪辑路径。对于每个菜单项,我们定义了剪辑路径,以确保获得我们想要的外观。

资源#

谢谢阅读。我已将本教程的内容放在 CodePen 和 GitHub 上,您可以在下面找到它们的链接: