Element-UI 技术揭秘(5)- 色彩、字体、边框与图标

18,805 阅读7分钟

前言

element-ui 组件库之所以受欢迎,除了组件丰富,文档友好之外,还得益于它的精美的设计。之前在组件库的整体设计文章中提到,element-ui 背后有一只强大的设计团队,他们为组件库了制定了一套设计规范。

需求分析

当我们去设计一套组件库的时候,首先要考虑颜色、字体、边框、图标这些基础元素的设计,它们是构建各个组件的基石,如果没有做好这些基础设计,那么做出来的组件库看上去一定很山寨。

这些基础设计都需要遵循一定的设计规范,经验丰富的设计师在设计的时候会制定一套规范,那作为程序员的我们在实现这套设计规范的时候,在代码层面也可以遵循一定的规范。

设计与实现

那么接下来,我们从代码的角度依次来介绍这四个基础元素在的设计与实现。

色彩

Element 为了避免视觉传达差异,使用一套特定的调色板来规定颜色,为你所搭建的产品提供一致的外观视觉感受。

主色

Element 主要品牌颜色是鲜艳、友好的蓝色。

如图所示,element-ui 提供了一套蓝色系的颜色,可以看到除了主色 #409EFF 之外,还有一系列渐变的蓝色,那么在代码中是如何实现的呢?

element-ui 关于颜色的定义在 packages/theme-chalk/src/common/var.scss 中:

$--color-primary: #409EFF !default;

这里定义了 $--color-primary 变量,值为 #409EFF,注意这里用了 !default 关键字,它在这里的含义是如果外面已经定义了 $--color-primary,那么就用已经定义的值,否则赋值为 #409EFF。这么做的原因应该是和自定义主题色相关,如果用户定义了新的主题色,该变量就可以指向新的主题颜色。

对于主题蓝色的渐变色,element-ui 的实现如下:

$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */
$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */
$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */
$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */
$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */
$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */
$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */
$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */
$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */

这里定义了 9 个变量,都使用了 mix 函数,mix 函数是 sass 中内置的函数,它表示 2 种颜色的混合,第三个参数表示 2 种颜色混合各自占的比例,以 mix($--color-white, $--color-primary, 10%) 为例,表示 $--color-white(白色)占比 10%,而 $--color-primary(主色)占比 90%。

通过这种方式,element-ui 轻松实现了不同颜色深度的主色。

辅助色

除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。

这些辅助色的实现也是大同小异,我们以成功色为例,其余不再赘述。

$--color-success: #67C23A !default;

$--color-success-light: mix($--color-white, $--color-success, 80%) !default;
$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default;

也是通过 mix 混入白色的方式,生成不同颜色深度的成功色。

中性色

中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。

关于文本颜色,由深到浅定义了四个变量:

/// color|1|Font Color|2
$--color-text-primary: #303133 !default;
/// color|1|Font Color|2
$--color-text-regular: #606266 !default;
/// color|1|Font Color|2
$--color-text-secondary: #909399 !default;
/// color|1|Font Color|2
$--color-text-placeholder: #C0C4CC !default;

关于边框颜色,由深到浅定义了四个变量:

/// color|1|Border Color|3
$--border-color-base: #DCDFE6 !default;
/// color|1|Border Color|3
$--border-color-light: #E4E7ED !default;
/// color|1|Border Color|3
$--border-color-lighter: #EBEEF5 !default;
/// color|1|Border Color|3
$--border-color-extra-light: #F2F6FC !default;

关于背景色,定义了三个变量:

/// color|1|Background Color|4
$--color-black: #000000 !default;
/// color|1|Background Color|4
$--color-white: #FFFFFF !default;
/// color|1|Background Color|4
$--background-color-base: #F5F7FA !default;

注意这里的第三个变量和图中透明色表示不同,因为透明背景理论上是不需要配置 background 的,默认就是透明的。这里第三个变量也表示一种基础白色,在多个组件中使用。

字体

element-ui 对字体进行统一规范,力求在各个操作系统下都有最佳展示效果。

字体

图中展示了多种字体的样式,其中有我们 mac 用户比较熟悉的 PingFang SC,还有一些 win 用户熟悉的 MicroSoft YaHei

packages/theme-chalk/src/reset.scss 中定义了全局的字体样式:

body {
  font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
  font-weight: 400;
  font-size: $--font-size-base;
  color: $--color-black;
  -webkit-font-smoothing: antialiased;
}

我们知道 font-family 可以指定一个字体列表,属性值用逗号隔开,浏览器会选择列表中第一个该计算机上有安装的字体。

字号

element-ui 定义了 6 种大小的字体,它们的定义在 packages/theme-chalk/src/common/var.scss 中:

/// fontSize|1|Font Size|0
$--font-size-extra-large: 20px !default;
/// fontSize|1|Font Size|0
$--font-size-large: 18px !default;
/// fontSize|1|Font Size|0
$--font-size-medium: 16px !default;
/// fontSize|1|Font Size|0
$--font-size-base: 14px !default;
/// fontSize|1|Font Size|0
$--font-size-small: 13px !default;
/// fontSize|1|Font Size|0
$--font-size-extra-small: 12px !default;

其中最小是 12px,最大是 20px。通常在设计是不建议出现小于 12px 大小的字体的,太小的字体会对视力不好的人群是不友好的。

行高

如图所示,通常我们在遇到多行文字的时候,设置不同的 line-height 会有不同的渲染效果,一般设置至少为 1.5。这将有助于改善低可视条件下的体验,也对认知阻碍者(如阅读困难者)有帮助。

element-uipackages/theme-chalk/src/common/var.scss 中只定义了 2 种行高:

/// fontLineHeight|1|Line Height|2
$--font-line-height-primary: 24px !default;
/// fontLineHeight|1|Line Height|2
$--font-line-height-secondary: 16px !default;

element-ui 在大部分组件的实现中直接写死了行高的大小,不过通常更好的方式是使用无单位的值而不是具体的大小,因为一旦你更改了字体大小,如果用无单位值就不需要再手动改行高了。另外一特定场景是如果文字的大小要随页面的缩放而变化,使用无单位的值可以确保行高也会等比例缩放。

边框

element-ui 对边框进行统一规范,可用于按钮、卡片、弹窗等组件里。

边框和圆角

element-ui 提供了一系列关于边框的圆角样式的定义,在 packages/theme-chalk/src/common/var.scss 中:

/// color|1|Border Color|3
$--border-color-base: #DCDFE6 !default;
/// color|1|Border Color|3
$--border-color-light: #E4E7ED !default;
/// color|1|Border Color|3
$--border-color-lighter: #EBEEF5 !default;
/// color|1|Border Color|3
$--border-color-extra-light: #F2F6FC !default;

$--border-width-base: 1px !default;
$--border-style-base: solid !default;
$--border-color-hover: $--color-text-placeholder !default;
$--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
/// borderRadius|1|Radius|0
$--border-radius-base: 4px !default;
/// borderRadius|1|Radius|0
$--border-radius-small: 2px !default;
/// borderRadius|1|Radius|0
$--border-radius-circle: 100% !default;
/// borderRadius|1|Radius|0
$--border-radius-zero: 0 !default;s

其中包括了边框的粗细、颜色、样式,圆角大小等变量,还包括了 hover 的颜色,用在组件中。

投影

element-ui 提供了几种常用的投影方式,定义在 packages/theme-chalk/src/common/var.scss 中:

/// boxShadow|1|Shadow|1
$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default;
// boxShadow|1|Shadow|1
$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default;
/// boxShadow|1|Shadow|1
$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;

如果对 box-shadow 相关属性值不太理解的同学,可以去 mdn 上自行查阅相关资料学习;也可以在线调试它的属性值,看看不同的渲染效果。

图标

element-ui 提供了一套常用的图标集合。

使用方法

直接通过设置类名为 el-icon-iconName 来使用即可。例如:

对应代码:

<i class="el-icon-edit"></i>
<i class="el-icon-share"></i>
<i class="el-icon-delete"></i>
<el-button type="primary" icon="el-icon-search">搜索</el-button>

我们只需要简单设置类名即可引入这些字体图标了(关于 button 的实现下一篇文章会提到),这是如何做到的呢?

实现方式

其实 element-ui 提供的图标是利用 IconFont 技术实现的,在 packages/theme-chalk/src/icon.scss 中定义:

@font-face {
  font-family: 'element-icons';
  src: url('#{$--font-path}/element-icons.woff') format('woff'), /* chrome, firefox */
       url('#{$--font-path}/element-icons.ttf') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  font-weight: normal;
  font-display: $--font-display;
  font-style: normal;
}

[class^="el-icon-"], [class*=" el-icon-"] {
  /* use !important to prevent issues with browser extensions that change fonts */
  font-family: 'element-icons' !important;
  speak: none;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;
  vertical-align: baseline;
  display: inline-block;

  /* Better Font Rendering =========== */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.el-icon-edit:before {
  content: "\e78c";
}

// ...

首先,利用 @font-face 定义了自定义字体,它的来源是 packages/theme-chalk/src/fonts/ 目录中定义的字体图标文件。

其次,利用属性选择器筛选了以 el-icon- 开头或者是带有 el-icon- 的类名的元素,它们对应的 font-family 就是自定义字体 element-icons

然后对应不同的图标,定义不同的 el-icon-xxx 类名,并通过 before 伪类指定对应的 content 值,这样用户只需要使用 el-icon-xxx 的类名就可以引用相应的图标。

最后推荐 2 个制作字体图标库的网站,Iconfonticomoon

总结

这篇文章总体来说还是很简单的,对于设计师提供的设计规范,element-ui 主要的实现方式是在公共的 sass 文件中定义了很多变量,未来组件中的样式就会引入这些变量,相当于编程的方式去书写 CSS,而不会在每个组件内部去写死字体、颜色、边框的值。这样的好处不仅语义化强,而且维护性好,一旦这些基础元素的设计改变,我可以只去修改这些变量值就可以,而不用去修改组件,另外对于组件整体的自定义主题设计也是提供了非常大的便利。

学习完这篇文章,你也可以在自己的项目中尝试去定义公共的样式文件和变量,然后在组件中去引入它们。当然如果你的组件库支持了后编译,你甚至可以直接去引入组件库中定义的变量。

把不会的东西学会了,那么你就进步了,如果你觉得这类文章有帮助,也欢迎把它推荐给你身边的小伙伴。

下一篇预告 :Element-UI 技术揭秘(6)- Button 按钮组件。

欢迎关注我的公众号「老黄的前端私房菜」,《Element-UI 技术揭秘》系列文章会第一时间在公众号更新和发布,除此之外,我还会经常分享一些前端进阶知识,干货,也会偶尔分享一些软素质技能。