初探原子css
简介: windicss、tailwindcss、unocss
前言
在讨论原子css的时候,首先我们先看看以前的css方案,看完之后再对比原子css的好处~
看之前可以看看css优先级:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity,对下文其实也挺重要的
sass
@import
Sass 扩展了 CSS 的@import
规则,能够导入 Sass 和 CSS 样式表,提供对mixins、函数和变量的访问,并将多个样式表的 CSS 组合在一起。与普通的 CSS 导入不同,后者要求浏览器在呈现页面时发出多个 HTTP 请求,Sass 导入完全在编译期间处理。
common.scss:
// flex的水平垂直居中
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
// 解决图片缩小模糊问题
.imgBlur {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
// 单行省略号
.singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// ltr
.ltr {
direction: ltr;
}
// rtl
.rtl {
direction: rtl;
}
// 置灰
.grayscale {
filter: grayscale(100%);
}
// float清除浮动
.clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
index.scss:
@import './common.scss';
.header {
width: 100px;
@extend .singleEllipsis;
}
编译index.scss结果:
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
.imgBlur {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
.singleEllipsis, .header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ltr {
direction: ltr;
}
.rtl {
direction: rtl;
}
.grayscale {
filter: grayscale(100%);
}
.clearfix:after {
display: block;
clear: both;
content: "";
}
.header {
width: 100px;
}
extend
sass源码1(先定义要extend类,再使用):
.singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
.clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
.header {
width: 100px;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
.logo {
width: 50px;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
.footer {
width: 100vw;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
sass源码1编译结果:
.singleEllipsis, .footer, .logo, .header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flexCenter, .footer, .logo, .header {
display: flex;
align-items: center;
justify-content: center;
}
.clearfix:after, .footer:after, .logo:after, .header:after {
display: block;
clear: both;
content: '';
}
.header {
width: 100px;
}
.logo {
width: 50px;
}
.footer {
width: 100vw;
}
编译结果跟顺序有关,有css优先级问题
先定义要extend的类,再使用header,logo,footer的话,其实后面header,logo,footer的规则优先级比extend的高(不考虑!important)
sass源码2(先使用,再定义extend类):
.header {
width: 100px;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
.logo {
width: 50px;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
.footer {
width: 100vw;
@extend .singleEllipsis;
@extend .flexCenter;
@extend .clearfix;
}
.singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
.clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
sass源码2编译结果:
.header {
width: 100px;
}
.logo {
width: 50px;
}
.footer {
width: 100vw;
}
.singleEllipsis, .header, .logo, .footer {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flexCenter, .header, .logo, .footer {
display: flex;
align-items: center;
justify-content: center;
}
.clearfix:after, .header:after, .logo:after, .footer:after {
display: block;
clear: both;
content: '';
}
编译结果跟顺序有关,有css优先级问题
header,logo,footer先试用了extend类,再定义extend类的话,其实后面的extend的类的优先级比header,logo,footer的高(不考虑!important)
mixin
mixin不允许先使用再定义,必须得先定义mixin,再使用。
sass源码:
@mixin singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@mixin flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
@mixin clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
.header {
width: 100px;
@include singleEllipsis;
@include flexCenter;
@include clearfix;
}
.logo {
width: 50px;
@include singleEllipsis;
@include flexCenter;
@include clearfix;
}
.footer {
width: 100vw;
@include singleEllipsis;
@include flexCenter;
@include clearfix;
}
编译结果:
.header {
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
}
.header:after {
display: block;
clear: both;
content: '';
}
.logo {
width: 50px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
}
.logo:after {
display: block;
clear: both;
content: '';
}
.footer {
width: 100vw;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
}
.footer:after {
display: block;
clear: both;
content: '';
}
header,logo,footer的优先级比mixin的优先级高(不考虑!important)
extend和mixin区别
从上面的结果来看很容易得出结论,mixin不会单独输出,它只是将一份样式复制到所有用到的地方里,而extend会单独输出,它是将单独输出的那一份样式共享给所有用到的地方。
- extend不能接收参数,mixin可以接收参数
- mixin的造成的心智负担比extend的低很多(因为extend会根据书写的顺序不同会导致编译结果顺序也不同,有css优先级优先级问题)
- 合理使用extend可以有效的复用样式,减少最终生成的css资源的大小。
sass做不到很好的复用
在使用sass的过程中,我们有沉淀了一些常用的css类,如:
common.scss:
// flex的水平垂直居中
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
// 解决图片缩小模糊问题
.imgBlur {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
// 单行省略号
.singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// ltr
.ltr {
direction: ltr;
}
// rtl
.rtl {
direction: rtl;
}
// 置灰
.grayscale {
filter: grayscale(100%);
}
// float清除浮动
.clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
我们可以通过extend来继承我们之前封装的类样式(至于为什么要用extend,而不是mixin,看上面的extend和mixin区别):
.header {
width: 100px;
@extend .singleEllipsis;
}
这样咋眼一看,好像很正常,但是上面只是很泛的例子,实际的应用场景可能是这样的:
login.scss:
@import 'common.scss';
.header {
width: 100px;
@extend .singleEllipsis;
}
.fullname {
width: 50px;
@extend .singleEllipsis;
}
home.scss
@import 'common.scss';
.logo {
width: 100px;
@extend .imgBlur;
}
.avatar {
width: 50px;
@extend .imgBlur;
}
编译login.scss结果:
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
.imgBlur {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
.singleEllipsis, .fullname, .header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ltr {
direction: ltr;
}
.rtl {
direction: rtl;
}
.grayscale {
filter: grayscale(100%);
}
.clearfix:after {
display: block;
clear: both;
content: "";
}
.header {
width: 100px;
}
.fullname {
width: 50px;
}
编译home.scss结果:
.flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
.imgBlur, .avatar, .logo {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
.singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ltr {
direction: ltr;
}
.rtl {
direction: rtl;
}
.grayscale {
filter: grayscale(100%);
}
.clearfix:after {
display: block;
clear: both;
content: "";
}
.logo {
width: 100px;
}
.avatar {
width: 50px;
}
因为我们需要使用extend,所以我们就得引入common.scss,上面有两个文件引用到了common.scss,但是如果在一个项目里面,有五个十个甚至所有文件都引用了common.scss,那么我们编译这十几个文件的时候,每份文件都会引入所有的common.scss里面的样式,可能这个文件只用到了common.scss里面的一个样式,但是最终编译却会把common.scss的所有样式都会编译进每个样式文件里,很明显这造成了不必要的资源浪费(但是对这个文件或者sass来说,其实是正常的,因为你import了这个文件,他就会把这个文件的所有能引用的样式都引入进来)。那么有没有办法只编译用到的类呢,其实是有的,使用占位符选择器能实现。
占位符选择器
具体解释:https://sass-lang.com/documentation/style-rules/placeholder-selectors,总的来说就是没被extend使用的占位选择器不会被输出。
使用占位符选择器修改common.scss:
// flex的水平垂直居中
%flexCenter {
display: flex;
align-items: center;
justify-content: center;
}
// 解决图片缩小模糊问题
%imgBlur {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
// 单行省略号
%singleEllipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// ltr
%ltr {
direction: ltr;
}
// rtl
%rtl {
direction: rtl;
}
// 置灰
%grayscale {
filter: grayscale(100%);
}
// float清除浮动
%clearfix {
&:after {
display: block;
clear: both;
content: '';
}
}
使用extend时也得用占位符选择器,login.scss:
@import 'common.scss';
.header {
width: 100px;
@extend %singleEllipsis;
}
.fullname {
width: 50px;
@extend %singleEllipsis;
}
编译login.scss结果:
.fullname, .header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.header {
width: 100px;
}
.fullname {
width: 50px;
}
可以看到,在使用占位选择器的时候,我们可以编译出只被extend使用过的类,这样就很好
@keyframes
案例1
占位符选择器不会对@keyframes处理,@keyframes都会编译
animate.scss:
%animate-img {
width: 100px;
height: 100px;
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
animation: img-flash-move 1s infinite ease-out;
}
编译animate.scss结果:
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
其他的属性没有被编译,@keyframes还是会被编译
案例2
animate.scss:
%animate-img {
width: 100px;
height: 100px;
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
animation: img-flash-move 1s infinite ease-out;
}
// 图片闪光
.img-flash {
@extend %animate-img;
@extend %animate-img;
}
编译的animate.scss结果:
.img-flash {
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
}
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
在使用extend的时候,@keyframes定义在占位符选择器里的话,继承两次不会生成两个@keyframes。
案例3
animate.scss:
@mixin animate-img {
width: 100px;
height: 100px;
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
animation: img-flash-move 1s infinite ease-out;
}
// 图片闪光
.img-flash {
@include animate-img;
@include animate-img;
}
编译的animate.scss结果:
.img-flash {
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
}
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
在使用include的时候,@keyframes定义在占位符选择器里的话,include两次会生成两个@keyframes。因此在用mixin的时候,最好不要在里面定义@keyframes,而是在最外层定义@keyframes
案例4
animate.scss:
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
@mixin animate-img {
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
}
// 图片闪光
.img-flash {
@include animate-img;
@include animate-img;
}
编译的animate.scss结果:
@keyframes img-flash-move {
0% {
transform: translate(-50%, -50%) rotate(45deg);
}
100% {
transform: translate(50%, 80%) rotate(45deg);
}
}
.img-flash {
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
width: 100px;
height: 100px;
animation: img-flash-move 1s infinite ease-out;
}
在最外层定义@keyframes就没事
总结
貌似没有一个较好的办法来实现以下的效果
animate.scss
// 文字闪光
%text-flash {
position: relative;
overflow: hidden;
@keyframes text-flash-move {
0% {
left: 0;
}
100% {
left: 100%;
}
}
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 10%;
height: 150%;
background: white;
content: '';
opacity: 0.6;
filter: blur(6px);
transform: translateY(-20%) rotate(45deg);
animation: text-flash-move 3s infinite ease;
}
}
我希望在@extend %text-flash;
的时候,才将@keyframes text-flash-move
编译进去,而实际上并不能,只要引入了animate.scss,没有@extend %text-flash;
也会将@keyframes text-flash-move
编译进去。
而我们将占位符选择器换成mixin后,虽然能实现include的时候才编译@keyframes text-flash-move
,但是mixin的其实是复制操作,有多个地方用到了就会复制多份,@keyframes text-flash-move
也会复制多份,即使我们把@keyframes text-flash-move
提到最外层,那也会将其他的属性复制多份(而且如果将@keyframes text-flash-move
提到最外面的话,那还不如用占位运算符呢)。
综合考虑的话,其实上述的animate.scss其实算是比较优的写法了,缺点就是如果没使用过@keyframes text-flash-move
也会生成一次@keyframes text-flash-move
。
最后更新于:2022-11-02 19:02:57