xinglie / xinglie.github.io

blog
https://xinglie.github.io
153 stars 22 forks source link

原子化样式 #67

Open xinglie opened 3 years ago

xinglie commented 3 years ago

前端的工具层出不穷,对于javascript,目前typescript+esm基本上一统天下了,我们在平常开发中也都是使用typescript写标准的module模块,如果目标环境不支持,则可以使用babeltypescript进行编译转换一下即可。

对于样式,从早期的resetnormalize,再到bootstrap框架,bem规范,再到tailwind原子化的写法,可谓无一定论。

以往我们通常会对选择器起一个名称,把用到的样式写进入,如

.keys-group{
    margin: 1px 4px;
    padding: 2px;
    background-color: @color-border;
    border-radius: @border-radius;
}

但这样很容易出现交叉重复,比如padding: 2px很可能再别的选择器里再出现。对于这样的情况,cssnano在压缩的时候,可以自动提取同一个样式中重复的规则进行复用,这一定程度上缓解了重复规则的问题。

这种方式不利于复用,比如另一个样式和这个很像,只有某一个不一样,那我们就需要写成

.keys-group,
.member-group{
    margin: 1px 4px;
    padding: 2px;
    background-color: @color-border;
    border-radius: @border-radius;
}

.member-group{
    padding: 4px
}

后期我们进行样式重构或移除不需要的样式时,人工就很费劲。

tailwind为代表的原子化样式可解决重复及样式重构的问题,而在我们项目中,我们的一些基础样式也无意中使用了原子方式

.ml5{
    margin-left:5px;
}

这种在使用上稍显麻烦,而遇到样式伪类时,则不太好办。

如果我们要在当前项目中就使用原子化方案,需要先定义声明规则。

规则

keyvalue包含单位一起为选择器的名称

.padding-2px{
    padding:2px
}
.margin-1px-4px{
    margin:1px 4px;
}

如果遇上变量时,value直接使用变量值表示

.padding-app-box{
    padding:var(--app-box)
}

.color-app-brand{
    color: var(--app-brand)
}

遇到伪类时,伪类名称拼在最前面

.before-color-red::before{
    color:red;
}

实施方案

人工

直接由开发人员书写原子化样式

  1. 兼容目前的样式,项目中无须做任何改变
  2. 可自由调整样式规则
  3. 如果原子样式规则多,会导致在htmlclass也堆砌很多选择器名称
工具编译

由工具进行编译转换

  1. 开发人员自由书写
  2. 样式规则多,且要完整实现浏览器样式权重,有成本 

走编译路线,需要考虑如下场景

.selector1{
    padding:2px;
    color:red;
}

.selector2{
    margin:4px;
    color:green;
}

html

<div class="selector1 selector2"></div>

需要识别样式声明时的先后顺序,即在cssselector1 selector2谁在前谁在后有关,编译器需要根据权重选择最终显示的样式规则

magix项目中,通常一个项目会有一个全局样式,我们会把原子化样式写在全局样式里,而对于需要使用伪类的样式,则写在各自的组件样式里(如果是全局通用的,则也需要写在全局样式里)。

短期看采用人工的方式比较经济,后期配合我们的magix-composer打包检测工具,可对htmlcss进行任意的添加和删除,magix-composer可自动检测哪些样式声明了未用,html中使用了哪些未声明的样式等问题,帮助我们重构和删除样式。

facebook也出了样式的编译工具,编译目标也是原子化样式,可有效减少冗余的样式规则。

长期看走编译路线会是更好的方式,这样可以最大化的解放开发人员:无须记忆任务规则,按自己的喜好书写样式,最终由编译器兜底处理。