Tailwind: 撸一个带图标和动画效果的下拉框

19553
2022/11/18 21:53:25

本章将使用 tailwind 实现一个没有任何 Javscript 代码的纯 CSS 的下拉框,把应用到导航栏、菜单栏时,也被称为下拉菜单。同时我们将讨论如何在 tailwind 中使用图标,包括图标的进化史:从字体文件到SVG。

从本章开始,将不再每一步都进行分解说明并提供代码了,毕竟你已经不是一个宝宝了——而是给出阶段性的代码进行统一分析讲解。

知识点

  • 元素的定位
  • 元素的分组
    • 分组的伪类
  • 元素的隐藏

实现

你可以点击这里查看效果及代码。

<div class="max-w-sm my-60 mx-auto bg-gray-50 p-6 rounded-lg" id="cta">
  <div class="relative group" id="dropdown-cta">
    <a href="#" class="block" id="dropdown-link">鼠标移上来看看</a>
    <ul class="hidden absolute bg-white z-10 w-full border rounded shadow-md divide-y group-hover:block" id="dropdown-items">
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
    </ul>
  </div>
</div>
  • #cta:为了更好地显示我们真正的内容,这里包裹了一个容器。它不是必需的。“容器”应该对应 container这个单词,但由于 tailwind 提供了 .container 类,为了避免某些喜欢想当然的读者误会,这里使用了 #cta 作为简写。虽然它只是为了更好地显示,但使命感爆棚的站长还是决定对其中使用到的类进行说明
    • max-w-sm:设置最大宽度为 sm
    • my-60:设置垂直方向上的外边距为60个单位
    • mx-auto:设置水平方向上的外边距为 auto,以实现水平居中
    • bg-gray-50:设置背景为50号灰色
    • p-6:设置内边距为6个单位
    • rounded-lg:设置圆角为 lg 大小
  • #dropdown-cta:整个下拉框的容器
    • relative:启用相对定位。【有关定位的文档
    • group:通过分组,可以根据父元素的状态改变样式
      • group 使用在父元素上,启用分组
      • 启用分组后,它的子元素可以感知父元素的状态
      • 有关分组的文档
    • 扩展:peer
      • 感知兄弟元素的状态
      • 有关peer文档
  • #dropdown-link
    • block:显示为块级元素【有关显示的文档
  • #dropdown-items
    • hidden:隐藏该元素
    • absolute:绝对定位
    • bg-white:设置背景颜色为白色
    • z-10:设置 z-index10 【有关z-index文档
    • w-full:设置宽度占满整个父容器
    • border:设置显示边框【有关边框的文档
    • rounded:设置显示圆角
    • shadow-md:设置使用md大小的阴影
    • divide-y:给相邻的元素加上垂直方向上,加上分割线【有关分割线的文档
    • group-hover:block:感知分组(父元素)的 hover(光标悬停事件),并将元素显示为块级元素

很好,仅仅使用 tailwind 就能这么简单地实现下拉框,又是一件值吹三天的事件。

图标

通常我们使用 tailwind 官方的 HeroIcons图标库,它不但提供可直接复制的 HTML/JSX 之外,还针对 react 和 vue 生态提供了组件。在 HeroIcons 无法满足的情况下,可以使用诸如Bootstrap Icons 作为补充。

在几年前,图标还是通过字体文件来实现的。发展到现在,大部分图标库都已经从字体文件转换到 SVG。

SVG 有很大的优势,包括它是矢量图片,放大缩小都不会产生锯齿;同时它既可以用标签的形式(HTML 有专门的<svg>标签)直接放到 HTML 里,也可以作为图片文件,通过 HTML 的 <img>标签来引入。

由于我们目前并没有将 tailwind 集成到 React/NextJS 里,所以直接将 <svg> 标签放到页面中不失为好方法。需要提醒的是,<svg>标签往往占用较多的编辑器区域,你可以使用编辑器的代码折叠功能把它折叠起来。

给下拉框加上箭头图标

我们知道,下拉框的箭头至少有两种:初始状态的向下箭头,以及下拉菜单展开后的向上箭头。

需要多个图标吗

你可以准备两个图标,分别是向上和向上箭头的图标。

但还有一种更巧妙的方法,让你只需要一个图标就可以了。

下面我们用以上两种思路分别进行实现。

使用多个图标实现

<div class="my-60 mx-auto max-w-sm rounded-lg bg-gray-50 p-6" id="cta">
  <div class="group relative" id="dropdown-cta">
    <div class="flex items-center space-x-1" id="dropdown-header">
      <a href="#" class="block" id="dropdown-link">鼠标移上来看看</a>
      <!-- 箭头向下 -->
      <svg xmlns="http://www.w3.org/2000/svg" class="block h-6 w-6 group-hover:hidden" id="icon-arrow-down" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
      </svg>
      <!-- 箭头向上 -->
      <svg xmlns="http://www.w3.org/2000/svg" class="hidden h-6 w-6 group-hover:block" id="icon-arrow-up" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" />
      </svg>
    </div>
    <ul class="absolute z-10 hidden w-full divide-y rounded border bg-white shadow-md group-hover:block" id="dropdown-items">
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
    </ul>
  </div>
</div>

点击这里查看代码和预览效果。

为了便于布局,我们把 #dropdown-link 和新加的两个 <svg>放到了 #dropdown-header容器里。

  • #dropdown-header:为了布局 #dropdown-link 和图标引入的容器
    • flex :启用 flex 布局
    • items-center:让子元素垂直居中对齐
    • space-x-1:让子元素之间存在1个单位的间隙
  • #icon-arrow-down:箭头向下的图标
    • block:显示为块线元素
    • h-6:高度设置为6
    • w-6:宽度设置为6
    • group-hover:hidden:感知分组的 hover(光标悬停事件),并将元素隐藏
  • #icon-arrow-up:箭头向上的图标
    • hidden:将元素隐藏
    • group-hover:block:感知分组的 hover(光标悬停事件),并将元素设置为块级元素

特别强调:

  • 我们在之前章节说过,图片是不具有响应式

使用单个图标实现

你可以任意使用向上或向下箭头实现本案例,考虑到初始状态,箭头是向下的,所以我们的示例将使用向下箭头。

<div class="my-60 mx-auto max-w-sm rounded-lg bg-gray-50 p-6" id="cta">
  <div class="group relative" id="dropdown-cta">
    <div class="flex items-center space-x-1" id="dropdown-header">
      <a href="#" class="block" id="dropdown-link">鼠标移上来看看</a>
      <!-- 箭头向下 -->
      <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 group-hover:rotate-180" id="icon-arrow-down" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
      </svg>
    </div>
    <ul class="absolute z-10 hidden w-full divide-y rounded border bg-white shadow-md group-hover:block" id="dropdown-items">
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
      <li class="p-3"><a href="https://axum.rs" class="hover:text-red-600">AXUM中文网</a></li>
    </ul>
  </div>
</div>

点击这里查看。

  • #icon-arrow-down
    • group-hover:rotate-180
      • 感知分组的 hover,并将元素翻转180度
      • 查看翻转的文档

动画效果

在使用 tailwind 撸一个按钮的章节中,我们曾提到,开启过渡能让元素具有动画效果,本案例中的 rotate也可以通过开启过渡来实现动画。

点击这里查看

  • #icon-arrow-down
    • transition-all:开启所有过渡效果
    • duration-500:动画持续500毫秒

挑战

如果要让下拉菜单项也有动画效果,你在 #dropdown-items 元素上添加 transition-all duration-500之后,发现并没有效果。那是因为,我们是通过改变 #dropdown-itemsdisplay 来显示或隐藏菜单项的,而 display 并不属于过渡效果,所以无法达到预期效果。

可见性透明度是属于过渡效果,试着动手使用这两个属性来改写本案例,并最终实现菜单项的动画效果吧。加油,奥利给!

参考答案在这里