[译] 如何为 <select> 添加一致性样式

1,984 阅读6分钟

原文链接:Styling a Select Like It’s 2019,by Scott Jehl

select 元素添加库跨浏览器一致性样式一直就是一件很难的事情。过去为了避免这个问题,我们用过诸如给父元素添加样式、添加伪元素、甚至是借助 JavaScript 的帮助实现类 Select 的功能控件,只是为了能够更加容易的自定义样式。但缺点是较难维护和使用,更不用说是用自定义组件带来的可访问性挑战了。

最近,我们看到一些文章,认为 select 的样式限制并没有太大的改变,但是我决定回到这个问题上来,并亲自进行实验确认是否真的是这样。事实证明,合理的样式集可以让 select 在新的浏览器中创建一致且有吸引力的样式,同时在旧版本中也能得到很好的展示。

快速示例

首先,先展示下浏览器原生的 select 元素。根据浏览器的不同,最终展出来的外观也会有所差异。

这是一个本地选择元素 苹果 香蕉 葡萄 橘子

下面是添加了样式后的 select。没有使用其他包装元素或者伪元素(IE10+ 除外):

image.png

你可以在 这个地址里 看到它在不同布局上下文中的展示效果。

代码

select 框的 HTML 代码如下。注意,这里是通过 .select-css 这个类控制它的样式的。

<select>
    <option>这是一个本地选择元素</option>
    <option>苹果</option>
    <option>香蕉</option>
    <option>葡萄</option>
    <option>橘子</option>
</select>

下面是控制 select 外观的 CSS,你也可以在 我们的 select-css 仓库 中找到。这里还添加了部分的注释说明:

/* class applies to select element itself, not a wrapper element */
.select-css {
    display: block;
    font-size: 16px;
    font-family: sans-serif;
    font-weight: 700;
    color: #444;
    line-height: 1.3;
    padding: .6em 1.4em .5em .8em;
    width: 100%;
    max-width: 100%; /* useful when width is set to anything other than 100% */
    box-sizing: border-box;
    margin: 0;
    border: 1px solid #aaa;
    box-shadow: 0 1px 0 1px rgba(0,0,0,.04);
    border-radius: .5em;
    -moz-appearance: none;
    -webkit-appearance: none;
    appearance: none;
    background-color: #fff;
    /* note: bg image below uses 2 urls. The first is an svg data uri for the arrow icon, and the second is the gradient. 
    	for the icon, if you want to change the color, be sure to use `%23` instead of `#`, since it's a url. You can also swap in a different svg icon or an external image reference
    	
    */
    background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'),
      linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
    background-repeat: no-repeat, repeat;
    /* arrow icon position (1em from the right, 50% vertical) , then gradient position*/
    background-position: right .7em top 50%, 0 0;
    /* icon size, then gradient */
    background-size: .65em auto, 100%;
}

此外,我们还建议添加一些规则来支持从右到左的语言,包含一个明确的禁用状态(disabled state):


/* Support for rtl text, explicit support for Arabic and Hebrew */
*[dir="rtl"] .select-css, :root:lang(ar) .select-css, :root:lang(iw) .select-css {
    background-position: left .7em top 50%, 0 0;
    padding: .6em .8em .5em 1.4em;
}

/* Disabled styles */
.select-css:disabled, .select-css[aria-disabled=true] {
    color: graytext;
    background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22graytext%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'),
      linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
}
.select-css:disabled:hover, .select-css[aria-disabled=true] {
    border-color: #aaa;
}

你可以在 GithubNPM 上看见完整 CSS 代码。

CSS 注释

上面的 CSS 代码你可以粘贴直接使用,但如果需要做自定义修改的话,就需要认识一些数字和值的意思。

  • select 默认设置成 display: block 了。如果你需要将它与 label 排列在一行的话,可以修改为 display: inline-block; width: auto;
  • select 的背景使用了两张背景图片:一个是 svg 箭头图标(用 data URI 表示的),另一个是重复的线性渐变(repeating linear gradient)。这里的每张图片你都可以使用另外部的图片 URL 地址替换,不过还要注意预设的 background-size: .65em auto, 100%; 和 background-position: right .7em top 50%, 0 0; 属性(箭头图标距离左边缘 .7em),可能要根据情况调整的。同时,如果 select 尺寸变大了,那么它的 padding-left 也需要相应的调大点,否则箭头可能会挡住下方的文字。不过还需要注意的是,在 IE9- 的浏览器中,是看不见自定义箭头图标的,而浏览器的默认箭头将显示在填充(译注:此处指 padding-left)的左侧,所以不要添加太多,否则 IE9 中的箭头的显示会距离左边太远。
  • 这里线性渐变背景需要保留,这是为了阻止 IE9- 浏览器器识别预设的 background 属性,因为在 IE9- 浏览器中不支持清除原生箭头图标,为了避免自定义图标覆盖它,才使用了渐变背景的。如果你只需要纯色背景的话,将 linear-gradient 两端的颜色改成一样的就行了,比如 linear-gradient(to bottom, #fff 0%, #fff 100%)
  • appearance 属性(包括其前缀版本)是用来重置 select 的默认样式的。
  • font-size: 16px; 这个规则也很重要,因为在 iOS Safari 中,如果 select 的文字是小于 16px 的,那么浏览器会放大网站布局的。一般来说,这种行为是很恼人的,所以我们用 16px 的字体大小避免这个问题。
  • .select-css option 使 option 元素不能继承 select 按钮本身的字重。
  • 根据  Scott O’Hara 的文章 所指出的问题,我为 select 设置了背景色(option 元素默认可能会继承 select 的背景色,因此这里显式设置了下,避免出现意想不到的问题)。
  • .select-css::-ms-expand 规则指示 IE11 和 IE10 隐藏菜单图标伪元素,这样它后面的自定义图标就能出现了。

在不同浏览器中的展示

以下是应用了上面的样式后,在各种浏览器中 <select> 元素的快照。在对像 IE9- 这样的旧版浏览器中,不支持显示自定义图标,显示了原生的,但控件依旧是可用的,看起来也足够好。

Firefox

image.png

Chrome

image.png

Safari

image.png

Edge

image.png

Internet Explorer 11

image.png

Internet Explorer 10

image.png

Internet Explorer 9

image.png

Internet Explorer 8

image.png

Internet Explorer 8

image.png

iOS Safari

image.png

Android Chrome

image.png

感谢阅读!

(完)


广告时间(长期有效)

我有一位好朋友开了一间猫舍,在此帮她宣传一下。现在猫舍里养的都是布偶猫。如果你也是个爱猫人士并且有需要的话,不妨扫一扫她的【闲鱼】二维码。不买也不要紧,看看也行。

瞄~