小而美的 css 的原子化 http://zoo.zhengcaiyun.cn/blog/article/css
引用 文章 Let’s Define Exactly What Atomic CSS is 中定义:
“Atomic CSS is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.
译文:
“原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。
.bg-blue { background-color: #357edd; }
.f1 { font-size: 3rem; }
.m0 { margin: 0; }
原子化 CSS 是一个 CSS 框架, 在没有对应的 CSS 框架的项目中,是如何写 CSS 的。我们引用 Challenging CSS Best Practices 文中例子来看看。
如图所示:我们要实现一个类似访问记录组件,右边是访问人的头像,左侧是访问的描述。
对应代码.
<div class="media">
<a href="https://www.zcygov.cn/" class="img">
<img width="40" src="logo.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分钟之前</div>
</div>
<style>
.media {
margin: 10px;
}
.media,
.bd {
overflow: hidden;
_overflow: visible;
zoom: 1;
}
.media .img {
float: left;
margin-right: 10px;
}
.media .img img {
display: block;
}
</style>
新增一个设计,需要把头像放在右侧,描述在左侧,如图所示
我们通过新增一个类名 imgExt,右浮动
代码:
<div class="media">
<a href="https://www.zcygov.cn/" class="imgExt">
<img width="40" src="https://sitecdn.zcycdn.com/f2e-assets/b37c37db-ce59-4bfe-a889-5c8615d008c8.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分钟之前</div>
</div>
<style>
...
/* 图片在右侧 */
.media .imgExt {
float: right;
margin-left: 10px;
}
</style>
这时候有来一个新设计,要求组件在页面右侧栏中时候,字体变小
代码:
<div id="rightRail">
<div class="media">
<a href="https://www.zcygov.cn/" class="imgExt">
<img width="40" src="https://sitecdn.zcycdn.com/f2e-assets/b37c37db-ce59-4bfe-a889-5c8615d008c8.png" alt="zcy" />
</a>
<div class="bd">@小明 14 分钟之前</div>
</div>
<style>
</div>
<style>
...
/* 页面右侧容器中时,字体变小 */
#rightRail .bd {
font-size: smaller;
}
</style>
用这种方式写 CSS 存在存在以下的问题
虽然文中的代码样例是 2013 年的,9 年过去了,发现自身的老项目中还是存在着类似问题。
.text-overflow-dot {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
...
.title-number {
width: 55%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
...
.invoice-content {
div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.time-tip {
i {
margin-left: 10px;
cursor: pointer;
}
}
#service-charge-Bill {
.zcy-search-panel .ant-form-item-label {
min-width: 80px;
}
}
.invoice-tpl-container {
max-height: 360px;
overflow-y: scroll;
}
.add-invoice-tpl-item {
border: 1px dashed rgb(209, 215, 232);
text-align: center;
height: 160px;
line-height: 160px;
margin: 10px;
}
.invoice-tpl-item {
border: 1px solid rgb(209, 215, 232);
margin: 10px;
height: 160px;
position: relative;
.invoice-content {
overflow: hidden;
padding: 20px;
height: 119px;
div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.invoice-type-mark {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
color: white;
background-color: #3177fd;
}
}
.operate {
position: absolute;
bottom: 0;
width: 100%;
border-top: 1px solid rgb(209, 215, 232);
height: 40px;
line-height: 40px;
text-align: center;
}
}
.invoice-tpl-item.active {
border-color: #3177fd;
}
.default-mark {
position: absolute;
right: 0;
top: 0;
background-color: #bbb;
color: white;
padding: 0 5px;
}
.catalogue {
&-title {
display: flex;
&-btns {
flex-grow: 1;
align-items: center;
text-align: right;
.ant-btn {
margin: 0 5px;
}
}
}
&-content {
height: calc(100% - 60px);
overflow: auto;
padding: 18px;
.cy-tree {
width: 80%;
}
.ant-tree {
overflow: auto;
}
}
&-tree {
height: calc(100% - 22px);
.ant-input {
width: 100%;
&-search {
width: 80%;
flex-grow: 1;
}
}
}
}
我们大多数项目是后台管理的项目,自身也有一个成熟的组件库。这样的项目 CSS 的工作量是比较少的。所以项目开始之处,没有指定对应 CSS 规范和架构,上诉的问题日积月累,导致现有项目 CSS 代码状况较差,维护起来让人十分头大,急需整理项目 CSS 框架和规范整体项目的 CSS。我们这边调研几个比较流行的 CSS 框架,以下是几个框架简要介绍。
“原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class。
“
“https://css-tricks.com/lets-define-exactly-atomic-css/
“OOCSS (Object-Oriented CSS 面向对象 CSS ) 是组织 CSS 的领先的模块化或基于组件的系统。它是 Nicole Sullivan 在 2008 年在 Web Directions North 大会上首次提出的,核心就是编写可复用和可维护的样式。
“
background
或 border
)。这样您就不必覆盖视觉属性。“http://oocss.org/
“SMACSS(Scalable and Modular Architecture for CSS)编写模块化、结构化和可扩展的 CSS。
“
“http://smacss.com/
“首先 BEM 是一个分层系统,它把我们的网站分为三层,这三层正好对应着 BEM 三个英文单词的简写 block, element, modifier,分为为 块层、元素层、修饰符层
“
__
两个下划线将块名称与元素名称分开--
两个破折号分隔元素名称及其修饰符“https://getbem.com/
“理智、可扩展、可管理CSS架构
“
html
、body
的样式a
p
div
等元素的样式重置 Objects – 类似 OOCSS 中的对象,描述一些常用的基础状态.hidden
“https://getbem.com/
考虑到我们自身项目项目是一个后台管理类的项目,有成熟组件库。日常 CSS 开发工作量和复杂度不高。我们也希望有一个快速可以落地的框架方案,且实现的成本较低。我们对比几个框架后,选择 CSS 原子化作为我们的 CSS 的架构方案。CSS 原子化提供现成的解决方案,几乎就是拿就用( tailwindcss ,windicss )。而且成体接入和改造成本也是最低的,不用自己再制定命名规则和使用规范。
首先我们看看前文中提到组件使用 CSS 原子化是如何实现的,项目中已引入 winidicss。
<div class="overflow-hidden mr-1">
<a href="https://www.zcygov.cn/" class="float-left mr-1">
<img
width="30"
src="logo.png"
alt="zcy"
/>
</a>
<div class="overflow-hidden text-sm">@小明 14 分钟之前</div>
</div>
这边如果需要 头像在右侧的,只需要将 float-left 替换成 float-right 即可。
基本上解决了项目现有的 CSS 问题,而且 CSS 的维护性有了很大的提高,CSS 编码的成本相对于以前有明显的降低。
使用 vscode 的编辑器,建议安装自动补全插件( https://marketplace.visualstudio.com/items?itemName=voorjaar.windicss-intellisense ),对于日常使用有很大的帮助,用起来的体验也很好。
刚开始的时候对应功能的类名不熟悉,需要使用官网( https://windicss.org/guide/ )查询。
CSS 规范是要基于视觉的设计规范的,winidicss 工具提供了 design token 的设计规范实现,再推广 CSS 的原子化之前和设计师统一好此类的规范,形成工具配置
import { defineConfig } from 'windicss/helpers';
import colors from 'windicss/colors';
export default defineConfig({
theme: {
extend: {
transitionProperty: {
width: 'width',
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
},
colors: {
gray: colors.coolGray,
blue: colors.sky,
red: colors.rose,
pink: colors.fuchsia,
},
fontSize: {
xs: '.75rem',
sm: '.875rem',
tiny: '.875rem',
base: '14px',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem',
'4xl': '2.25rem',
'5xl': '3rem',
'6xl': '4rem',
'7xl': '5rem',
},
},
},
});
功能类优先的 原子化 CSS 框架,带来便利的同时,也是存在一些问题的。最突出的问题就是 html 上类过多,如果要实现一个相同功能,需要复制一个很长的字符串。这个情况下的可读性和复用性是比较差的。
比如一个简单按钮的例子:涉及到背景,字体,边距,边框的设置,类就很多
<button
className="bg-blue-400 text-sm text-white font-mono font-light py-2 px-4 border-2 border-rounded border-blue-200"
>
Button
</button>
而且相同样式复用需要整块的复制。虽然这提供属性化(https://windicss.org/features/attributify.html)的模式,Shortcuts(https://windicss.org/features/shortcuts.html)和指令(https://cn.windicss.org/features/directives.html)来解决相同功能类集合过长,过多的问题。但是实际上可以发现,原子化框架自身是无法解决这个问题的。
当然你有可以通过设计变量的方式来解决这个问题,但其实上和命名一个类名没有多大的区别。
const myButtonClass = "bg-blue-400 text-sm text-white font-mono font-light py-2 px-4 border-2 border-rounded border-blue-200"
<button
className={myButtonClass}
>
Button
</button>
在选定一个 CSS 框架作为项目的 CSS 规范的时候,需要考虑自身项目的现状,如果项目本身 CSS 复杂度较高,整体工作量较多,原子化的 CSS 是不太适合的。
原子化的 CSS 可以帮助我们的项目解决 CSS 命名,代码重复,不断膨胀的问题,但它也不是一劳永逸的,实际使用中还是会有问题,关键在与开发者自身的取舍,权衡利弊。不要一个规则用到底,遇到问题也不变通。工具和思想发明其实也是为了解决你实际的问题。你会发现 windicss (https://cn.windicss.org/posts/v30-utilities.html) 这类工具优先的css框架,也是添加蛮多额外的功能来弥补原子化 CSS 框架的缺陷,提升自身使用体验。