不枚举,微信WeUI如何巧妙定义白天、暗夜模式各主色的active态色号?

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情

这是我的专栏《前端入门到进阶》,跟HullQin学前端,入门到进阶!带你进大厂!

背景

最近在研究微信官方的weui.css,发现有些实现比较巧妙。比如Button的active状态,它不是通过直接设置:active时的颜色,而是在:active时,叠加了一个透明遮罩层上去,使得按钮颜色颜色不一样。

image.png

而不是像Ant Design一样,分别定义了所有主色的常态active态hover态

image.png

此外,字节跳动的Arco Design也是通过CSS变量表示所有主色的各种状态,但它多嵌套了一层CSS颜色变量,这比Ant Design灵活性高一些:

image.png

image.png

为什么微信要这么做

其实在白天模式、暗夜模式,让用户感觉舒适的active状态其实是不同的:

  • 在白天模式,按钮颜色在active状态应该更暗;
  • 在暗夜模式,按钮颜色在active状态应该更亮。

如果某个颜色的白天、暗夜模式色号相同,那它的active状态在白天、黑夜模式下一定不相同。

如果给所有的主色都指定active状态色号,那么会有非常多的颜色值:白天模式普通状态色号、白天模式active状态色号、暗夜模式普通状态色号、暗夜模式active状态色号。后来微信又出现了新的模式:关怀模式,也会影响色号的值(对比度更大)。最终,这些色号常量将翻倍增加,设计师难以维护!

所以微信设计师就给active状态设计了一套规则:白天模式就给元素叠加一个透明的暗的遮罩层表达active状态,黑夜模式就给元素叠加一个透明的亮的遮罩层表达active状态。这样,每个主色只需要维护一个普通状态色号即可。

备注:这个做法可能不是微信首创的,可能其它优秀的组件库也是这么实现的,这里只是拿微信举个例子。

微信是怎么实现的

假如有个按钮,那么微信是如何通过叠加遮罩层实现active状态的呢?

1. 定义白天、暗夜模式的遮罩层色号

首先,微信定义了1个「遮罩层色号」CSS变量,它会跟随当前白天/暗夜主题变化,这个CSS变量表示遮罩层的色号:

.wx-root,body {
  --weui-BTN-ACTIVE-MASK: rgba(0, 0, 0, 0.1);
}

.wx-root[data-weui-theme='dark'],body[data-weui-theme='dark'] {
  --weui-BTN-ACTIVE-MASK: rgba(255, 255, 255, 0.05);
}

@media (prefers-color-scheme:dark) {
  .wx-root:not([data-weui-theme='light']),body:not([data-weui-theme='light']) {
    --weui-BTN-ACTIVE-MASK: rgba(255, 255, 255, 0.05);
  }
}
复制代码

这里微信写的比较复杂,其实是给前端开发者2种实现暗黑模式的方案:

  1. 网页主题可以跟随操作系统的白天/暗夜主题。这是通过媒体查询@media (prefers-color-scheme:dark)实现的。
  2. 网页主题可以通过Html标签里的data-weui-theme属性控制。这允许开发者在网页中放一个白天/暗夜模式的开关,网页的主题不再跟随操作系统,而是用户主动可控。

不得不承认,这个写法确实简短、精妙。

2. 给Button添加before伪元素

为了给Button元素增加一个透明的遮罩层,方法有很多,微信采用了精巧的纯CSS方案:before伪元素。

.weui-btn:before {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.1);
  background-color: var(--weui-BTN-ACTIVE-MASK);
  border-radius: 8px;
}
复制代码

在设置了content后,会自动在Button元素前添加一个大小一模一样、形状一模一样的伪元素,该伪元素拥有透明的背景色,就实现了叠加遮罩层。

当然,这段样式没有设置contentcontent默认值是normal,不会展示伪元素。

3. 在Button actice状态时展示伪元素

.weui-btn:not(.weui-btn_disabled):not(.weui-btn_loading):active:before,.weui-btn:not([disabled]):not(.weui-btn_loading):active:before {
  content: "";
}
复制代码

只要在Button:active时,设置content""就会展示伪元素,上面的遮罩层就出现了。

这个CSS写的很长,是为了防止disabled的按钮或者loading的按钮变成active状态。

两种方案对比

方案 案例 优点 缺点
维护所有主色的所有状态、所有模式的色号枚举值 Ant Design, Arco Design 设计师可以精心挑选和任意搭配,灵活性高 色号维护成本高
维护主色的色号枚举值,根据遮罩层计算其它状态和模式的色号 WeUI 各种状态的计算方式统一,维护成本低 色号模式比较固定

二者都是优秀的方案,大家可以根据需要决策。只是WeUI的实现方式令我眼前一亮,打破了我以前的认知(以为只能通过枚举所有色号值来表示Hover态、Active态),所以就分享给大家。

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,联系我,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》《极致用户体验》

猜你喜欢

转载自juejin.im/post/7132133082445905956