继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

CSS的未来:轻松为下拉菜单设置样式,告别那些笨拙的 hacks

手掌心
关注TA
已关注
手记 275
粉丝 18
获赞 76

多年来,<select>元素一直很难被美化。开发者们要么接受浏览器的默认样式,要么不得不使用大量的JavaScript来解决。为什么这种情况已经持续这么久了?

为什么 <select> 不能设置样式?

<select>组件是一个表单元素,这意味着浏览器原生处理了许多行为,如下拉菜单逻辑(你有没有注意到选项列表可能会超出窗口范围?)、键盘导航和辅助功能。然而,由于这些控件与操作系统紧密结合,样式设计受到了很大的限制。

替代方案:从jQuery UI到shadcn/ui

因为没有现成的原生样式可用,开发人员只好转向使用库。

jQuery UI (jQuery用户界面插件)

  • jQuery UI(早期2010年代):将 <select> 包裹在一个 div 中,并用 <ul> 替换它。
  • 自定义下拉选择(2015–2022):React/Vue 解决方案通常完全替换 <select>
  • shadcn/ui(现代的做法):利用 Radix UI 创建可访问的下拉选择。

虽然这些解决方案可行,但它们也带来了取舍:多余的JavaScript,可能的无障碍问题以及性能损耗。

进入 base-select:一个新的方法,但有一个注意事项

随着引入了新的 CSS 属性 base-select,浏览器将允许对 <select> 元素进行完整的 CSS 样式设置,而不覆盖大多数内置功能。这意味着,用户可以进行完整的 CSS 样式设置,而不会影响大多数默认功能。

  • 无需使用 JavaScript 来实现下拉菜单。
  • 完全掌控外观,同时保持内置的易用性。
  • 可能更快渲染,性能更佳。

重要提示: base-select 属性目前还在试验中,仅在 Chrome 134+ 中可用。请注意在实际应用中谨慎使用。

base-select 风格美化 <select>

当对下拉列表框进行样式设置时,你必须这样为selectselect::picker(select)添加appearance: base-select;

    选择器将应用基础选择器的外观,当选择器作为拾取器时,也将应用基础选择器的外观。

全屏模式,退出全屏

这告诉浏览器允许 <select> 元素的样式用 CSS 来样式化,而不是使用系统默认的外观。

理解 ::picker(select): 此伪类表示 <select> 元素的下拉框(即“picker”)。它允许你单独对下拉框进行样式设置。

有一些可用的伪类和伪元素可以用于修改select元素。下面列了一些有用的伪类和伪元素,select元素

    select {
     appearance: base-select;
     /* 定义 'button' 样式 */

     &::picker(select) {
      appearance: base-select;
      /* 定义 'listbox' 样式 */
     }

     &::picker-icon {
      /* 设置图标样式 */
     }

     &:not(:open) {
      /* 关闭时的样式设置 */

      &::picker(select) {
       /* 关闭时的 'listbox' 样式设置 */
      }
     }

     &:open {
      /* 打开时的样式设置 */

      &::picker(select) {
       /* 打开时的 'listbox' 样式设置 */
      }
     }

     & option {
      /* 选项样式设置 */

      &::checkmark {
       /* 选中时对勾样式设置 */
      } 

      &:checked {
       /* 选中时选项样式设置 */
      }
     }
    }

进入全屏,退出全屏

Demo: 仅使用 CSS 的 shadcn/ui Select:

让我们只用 CSS 重新实现 shadcn/ui 的 select 组件。下面是如何实现的:

  • 使 <select> 的样式与 shadcn/ui 的外观一致。
  • 自定义下拉列表的外观。
  • 确保无障碍功能完好无损。

注意: 这个演示仅适用于 Chrome 134+ 及以上版本。如果你无法进行测试,我已经在下面附上了一个 GIF 动图,你可以通过 GIF 动图了解它的运行情况。

Fallback animation

标记语言

HTML结构仍然保持简单。<selectedcontent>元素允许我们单独显示和样式化选定的选项,并通过添加一个 Chevron 图标来模仿 shadcn/ui 的样式。

    <select>
      <button>
        <selectedcontent></selectedcontent>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
          <path d="m6 9 6 6 6-6"></path>
        </svg>
      </button>
      <optgroup>
        <label>水果</label>
        <option value="" hidden disabled selected>请选择一个水果选项</option>
        <option>苹果</option>
        <option>香蕉</option>
        <option>蓝莓(莓果)</option>
        <option>葡萄</option>
        <option>菠萝</option>
      </optgroup>
    </select>

切换到全屏模式, 点击退出全屏

设置选择按钮的外观

首先,我们得用这个属性 appearance: base-select 并设置基本样式。

    select {
     appearance: 基础选择器;
     color: #71717a;
     background-color: 透明;
     width: 180px;
     box-sizing: border-box;
     padding: 0.5rem 0.75rem;
     border: 1px solid #e4e4e7;
     border-radius: calc(0.5rem - 2px);
     box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
     cursor: pointer;
    }

进入全屏 退出全屏

调整内容和图标的摆放位置:

    select > button {
     display: flex;
     width: 100%;
     font-family: inherit;
     color: currentColor;
    }

    select > button > svg {
     margin: 0 0 0 auto;
     width: 1.2rem;
     height: 1.2rem;
    }

全屏,退出全屏

下拉列表框的样式

listbox需要单独进行样式设置,以确保其在打开时能够平滑显示。我们采用较新的starting-style,以便从display: none开始进行动画效果。

    select::picker(select) {
     appearance: base-select;
     border: 1px solid #e4e4e7;
     padding: 0.25rem;
     margin-top: 0.25rem;
     border-radius: calc(0.5rem - 2px);
     box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
      0 2px 4px -2px rgba(0, 0, 0, 0.1);
     cursor: default;
     transition: opacity 225ms ease-in-out, transform 225ms ease-in-out;
     transform-origin: top;
     transform: translateY(0);
     opacity: 1;

     @starting-style {
      transform: translateY(-0.25rem) scale(0.95);
      opacity: 0;
     }
    }

点击全屏进入,点击退出全屏

增强可访问性和互动性

提高焦点的可见度,并确保占位文本更加显眼。

    select:focus-visible {
     outline: 2px solid #a1a1aa;
     outline-offset: -1px;
    }

    select:has(option:not([hidden]):checked) {
     color: #18181b;
    }

全屏模式 退出全屏

自定义复选标记

我们可以把默认的对勾替换成自定义的 SVG 图标。

    select option::after {
     content: "";
    width: 1rem;
     height: 1.5rem;
     margin-left: auto;
     opacity: 0;
     background: center / contain no-repeat
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2318181b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'%3E%3C/path%3E%3C/svg%3E");
    }

    select option:checked::after {
     opacity: 1;
    }

切换到全屏 退出全屏

结论部分

<select> 组件终于变得更加灵活。我们可以用 base-select 创建漂亮的下拉菜单,无需使用 JavaScript。想了解更多详情,请参阅 open ui 介绍

你对 base-select 有什么看法?是不是有点等不及要告别那些重依赖 JavaScript 的下拉菜单了?base-select(这里可以加入注释说明 base-select 的具体含义或功能)。

感谢阅读!如果你想进一步了解我,这里是我的TwitterBlueSky领英资料。来跟我打个招呼吧 😊

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP