前言
本文旨在介绍如何使用Less语言手写CSS的原子化工厂。如果你有意向在项目中引入原子CSS,可以阅读下antfu大神的新轮子 重新构想原子化 CSS,或者使用 Tailwind CSS 。
什么是原子化CSS?
定义
首先,让我们为 原子化 CSS (Atomic CSS) 给出适当的定义:
John Polacek 在 文章 Let’s Define Exactly What Atomic CSS is 中写道:
原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名。
白话一点就是
在项目中定义一些语义化的类名,来表示单一的CSS属性,让你在编写页面时可以直接使用类似
class="w-100"
的原子属性来设置{ width: 100px; }
的样式,从而提升开发效率。
示例:
// margin 单位px
.m-1 { margin: 1px; }
...
.m-100 { margin: 100px; }
// margin 单位rem
.m-1rem { margin: 1rem; }
...
.m-100rem { margin: 100rem; }
// width 单位px
.w-1 { width: 1px; }
...
.w-100 { width: 100px; }
// width 单位%
.w-1pe { width: 1%; }
...
.w-100pe { width: 100%; }
// font-weight 无单位
.fw-100 { font-weight: 100; }
...
.fw-1000 { font-weight: 1000; }
...
开始整活,用less手写一个属于你的原子化工厂吧!
1. 我们先来简单实现margin的原子类,生成 m-1 ~ m-100
,实现1到100,肯定不可能一个个手写,借助less语法的循环特性,我们可以这样实现
.generate-atomic-margins(@start, @end) when (@start <= @end) {
.m-@{start} {
margin: unit(@start, px);
}
.generate-atomic-margins((@start + 1), @end);
}
.generate-atomic-margins(1, 100);
编译结果
现在你可以直接使用
m-1
~ m-100
来设置边距了,以此类推,你可以生成p-1 ~ p-100
、w-1 ~ w-100
、h-1 ~ h-100
来使用,但是这样很麻烦,你得把写过的逻辑cv一遍又一遍。
2. 进阶版:加入自定义类名前缀、自定义原子属性、以及自定义步长的功能
.generate-atomic-classes(@prefix, @property, @start, @end, @step: 1) {
.loop-properties(@index) when (@index <= @end) {
.@{prefix}-@{index} {
@{property}: unit(@index, px);
}
.loop-properties(@index + @step);
}
.loop-properties(@start);
}
// 步长为2,生成 .m-0, .m-2, .m-4 ... .m-10
.generate-atomic-classes(m, margin, 0, 10, 2);
// 生成 .mt-1, .mt-2, .mt-3, .mt-4
.generate-atomic-classes(mt, margin-top, 1, 4);
// 生成 .p-1, .p-2, .p-3, .p-4
.generate-atomic-classes(p, padding, 1, 4);
编译生成
.m-0 {
margin: 0px;
}
.m-2 {
margin: 2px;
}
.m-4 {
margin: 4px;
}
.m-6 {
margin: 6px;
}
.m-8 {
margin: 8px;
}
.m-10 {
margin: 10px;
}
.mt-1 {
margin-top: 1px;
}
.mt-2 {
margin-top: 2px;
}
.mt-3 {
margin-top: 3px;
}
.mt-4 {
margin-top: 4px;
}
.p-1 {
padding: 1px;
}
.p-2 {
padding: 2px;
}
.p-3 {
padding: 3px;
}
.p-4 {
padding: 4px;
}
写到这里,原子工厂的雏形就基本完成了,但目前为止产出的单位都是px,还得考虑项目中使用的单位非px的情况。
3. 最终版:加入自定义单位
/**
* @description less自定义原子类工厂
* @param {string} prefix 前缀
* @param {string} property 属性
* @param {string} unit 单位
* @param {number} start 起始值
* @param {number} end 结束值
* @param {number} step 步长
* @return 自命名的原子类
*/
.generate-atomic-classes(@prefix, @property, @unit: none, @start, @end, @step: 1) {
// 无单位
.unit-check() when (@unit = none) {
.loop-properties(@index) when (@index <= @end) {
.@{prefix}-@{index} {
@{property}: @index;
}
.loop-properties(@index + @step);
}
.loop-properties(@start);
}
// px
.unit-check() when (@unit = px) {
.loop-properties(@index) when (@index <= @end) {
.@{prefix}-@{index} {
@{property}: unit(@index, @unit);
}
.loop-properties(@index + @step);
}
.loop-properties(@start);
}
// 百分比
.unit-check() when (@unit = pe) {
.loop-properties(@index) when (@index <= @end) {
.@{prefix}-@{index}@{unit} {
@{property}: @index * 1%;
}
.loop-properties(@index + @step);
}
.loop-properties(@start);
}
// 其他单位
.unit-check() when (not (@unit = none) and not (@unit = px) and not (@unit = pe)) {
.loop-properties(@index) when (@index <= @end) {
.@{prefix}-@{index}@{unit} {
@{property}: unit(@index, @unit);
}
.loop-properties(@index + @step);
}
.loop-properties(@start);
}
.unit-check();
}
原子化工厂启动!
按需生成常用的原子CSS
// 生成 .w-1 { width: 1px; } ~ .w-100 { width: 100px; }
.generate-atomic-classes(w, width, px, 1, 100);
// 生成.w-1pe { width: 1%; } ~ .w-100pe { width: 100%; }
.generate-atomic-classes(w, width, pe, 1, 100);
// 生成.h-1 { height: 1px; } ~ .h-100 { height: 10px; }
.generate-atomic-classes(h, height, px, 1, 100);
// 生成.h-1pe { height: 1%; } ~ .h-100pe { height: 100%; }
.generate-atomic-classes(h, height, pe, 1, 100);
// 生成.fs-1 { font-size: 1px; } ~ .fs-100 { font-size: 100px; }
.generate-atomic-classes(fs, font-size, px, 1, 100);
// 生成.fw-400 { font-weight: 400; } ~ .fw-1000 { font-weight: 1000; }
.generate-atomic-classes(fw, font-weight, none,400, 1000, 100);
// 生成.lh-1 { line-height: 1px; } ~ .lh-100 { line-height: 100px; }
.generate-atomic-classes(lh, line-height, px, 1, 100);
// 生成.m-1 { margin: 1px; } ~ .m-100 { margin: 100px; }
.generate-atomic-classes(m, margin, px, 1, 100);
// 生成.mt-1 { margin-top: 1px; } ~ .mt-100 { margin-top: 100px; }
.generate-atomic-classes(mt, margin-top, px, 1, 100);
// ...
颜色原子化
/**
* less原子颜色生成
* @param {string} prefix 前缀
* @param {string} property 属性
* @param {string} color 颜色 可以用 #xxx、rgb...
* @param {number} step 步长
**/
.generate-atomic-colors(@prefix, @property, @color, @step: 5%) {
@red: red(@color);
@green: green(@color);
@blue: blue(@color);
.@{prefix} {
@{property}: rgb(@red, @green, @blue);
}
.loop-properties(@index) when (@index * @step <= 100%) {
.@{prefix}-@{index} {
@{property}: rgba(@red, @green, @blue, @index * @step);
}
.loop-properties(@index + 1);
}
.loop-properties(1);
}
同上,根据属性、颜色值、透明度,生成对应颜色原子类
.generate-atomic-colors(c-white, color, white, 10%);
.generate-atomic-colors(bg-c-red, background-color, #ff0000, 50%);
.generate-atomic-colors(b-c-black, border-color, rgb(0, 0, 0), 50%);
编译结果
.c-white {
color: #ffffff;
}
.c-white-1 {
color: rgba(255, 255, 255, 0.1);
}
.c-white-2 {
color: rgba(255, 255, 255, 0.2);
}
.c-white-3 {
color: rgba(255, 255, 255, 0.3);
}
.c-white-4 {
color: rgba(255, 255, 255, 0.4);
}
.c-white-5 {
color: rgba(255, 255, 255, 0.5);
}
.c-white-6 {
color: rgba(255, 255, 255, 0.6);
}
.c-white-7 {
color: rgba(255, 255, 255, 0.7);
}
.c-white-8 {
color: rgba(255, 255, 255, 0.8);
}
.c-white-9 {
color: rgba(255, 255, 255, 0.9);
}
.c-white-10 {
color: #ffffff;
}
.bg-c-red {
background-color: #ff0000;
}
.bg-c-red-1 {
background-color: rgba(255, 0, 0, 0.5);
}
.bg-c-red-2 {
background-color: #ff0000;
}
.b-c-black {
border-color: #000000;
}
.b-c-black-1 {
border-color: rgba(0, 0, 0, 0.5);
}
.b-c-black-2 {
border-color: #000000;
}
现在你可以直接使用你生成的 原子CSS
来设置你所需的样式了。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Less原子工厂</title>
<link rel="stylesheet" href="./atimic.css">
</head>
<body>
<div class="w-100 h-100 fs-16 fw-500 c-red-10 bg-c-black-10 b-c-white">Less原子工厂</div>
</body>
</html>
在项目中使用
- 创建一个less文件
- 将本文中的less原子类生成函数复制进去,并生成你需要的原子css属性
- 使用 less在线生成工具 验证你生成的原子css
- 在项目入口引入lessFactory.less即可使用
总结
原子化CSS是一种CSS架构方式,它使用小而具有单一用途的类,并以视觉效果进行命名。本文通过Less的嵌套和循环特性来实现CSS原子化工厂,使开发者能够快速生成各种原子类,例如设置边距、宽度、高度、字体大小、行高等。
本文旨在介绍如何使用less的打造你的原子CSS,再次向大家推荐antfu大神的新轮子 重新构想原子化 CSS。
参考资料
[1] 重新构想原子化CSS
[2] unocss
[3] tailwindcss
[4] less