文章永远首发自个人 Github,你们能够关注点赞,一般会早于发布各大平台一周时间以上。css
如今大部分搞前端的应该仍是这样写 CSS 的:html
.mock {
margin: auto;
font-size: 16px;
// ...
}
<div class='mock'>mock</div>
复制代码
以上代码就是举个例子,大部分状况应该都是写一个类,而后整一堆样式进去。前端
可是这种方式写多了之后,你应该会感觉到一些痛点,好比说:react
当下,社区里有一些 CSS 方案,可以解决以上一些痛点:git
本文就来聊聊以上三种方案的优缺点以及各自方案的表明做。github
首先来聊聊啥叫作 Atom CSS:意思是一个类只干一件事,好比说:设计模式
.m-8 {
margin: 8px;
}
复制代码
想象一下你按照这样的思想搞出一大堆相似的类名,就能整出一个践行 Atom CSS 方案的三方库了,tailwindcss 就是这个方案里的佼佼者。其实 Atom CSS 不少人应该早都用过了,栅格系统上就有它的身影,无非不清楚原来它就是 Atom CSS 罢了。缓存
咱们先来看看若是用 tailwindcss 的话,写好样式的 HTML 大概长啥样:markdown
上图是人家官网上的,在这以前还有一段挺炫的动画。看起来好像挺方便的,写上一堆类名就能出左边好看的样式了,省了不少写样式的时间,可是读者们能够来想一想这种方式它会有啥好处及弊端?app
在说优缺点以前,咱们先来聊聊 Atom CSS 的历史。其实它并非一个新兴产物,这玩意你往前推个十年就能看到它的讨论。正所谓天道好轮回,苍天饶过谁。Atom CSS 之前火过,并且是被喷火的,沉寂了几年以后这几年又被拿出来讲了。
接下来咱们以 tailwindcss 为例来聊聊 Atom CSS 方案的优劣点。
若是你想在团队内部推广这个产品,学习成本会是一个问题,毕竟须要你们都看得懂你这坨东西究竟是啥意思,这算一个很明显的缺陷。可是对于语法问题你还真的不用怎么担忧,tailwindcss 是有语法补全的工具链的,Webstorm 已经内置了,VSCode 须要你们自行装个插件,因此喷写 tailwindcss 语法麻烦的能够歇一歇。
样式复用,就像写组件同样,此次咱们是把样式一个个抽离了出来,这样带来的一大好处是减小了 CSS 代码文件体积。
本来传统的写法是定义一个类,而后写上须要的样式:
.class1 {
font-size: 18px;
margin: 10px;
}
.class2 {
font-size: 16px;
color: red;
margin: 10px;
}
复制代码
这种写法是存在一部分样式重复的,换成 Atom CSS 就能减小一部分代码的冗余。
把 CSS 当成组件来写。你们乍一看 tailwindcss 官网确定会以为我在 HTML 里写个样式要敲那么多类是有病吧?
<figure class="md:flex bg-gray-100 rounded-xl p-8 md:p-0">
<img class="w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
<div class="pt-6 md:p-8 text-center md:text-left space-y-4">
<blockquote>
<p class="text-lg font-semibold">
“Tailwind CSS is the only framework that I've seen scale
on large teams. It’s easy to customize, adapts to any design,
and the build size is tiny.”
</p>
</blockquote>
<figcaption class="font-medium">
<div class="text-cyan-600">
Sarah Dayan
</div>
<div class="text-gray-500">
Staff Engineer, Algolia
</div>
</figcaption>
</div>
</figure>
复制代码
其实咱们是能够利用 Atom CSS 一次只干一件事的特性,将这些类随意组装成咱们想要的类,这样就能够提供出来一个更上层的通用样式来复用。
好比说项目中的按钮都是存在通用的圆角、内边距、字体等,这样咱们就能够封装出这样一个类:
.btn {
@apply p-8 rounded-xl font-semibold
}
复制代码
效率工具。tailwindcss 用的好确定是能提升写布局的效率的,尤为对于须要作响应式的页面而言。固然这东西其实也算是甲之蜜糖乙之砒霜,评价两极分化很严重,有人认为提升了效率,也有人认为反而是增长了成本,或者说是脱裤子放屁。
提供了一整套规范化的设计模式,直接点说就是 tailwindcss 给你内置好一套优秀的设计主题了。可是这玩意对于规范的视觉团队来讲是个不小的福音,不规范的话就多是火葬场了。下面我给你们举个例子:
// tailwind.config.js
const colors = require('tailwindcss/colors')
module.exports = {
theme: {
screens: {
sm: '480px',
md: '768px',
lg: '976px',
xl: '1440px',
},
colors: {
gray: colors.coolGray,
blue: colors.lightBlue,
red: colors.rose,
pink: colors.fuchsia,
},
fontFamily: {
sans: ['Graphik', 'sans-serif'],
serif: ['Merriweather', 'serif'],
},
extend: {
spacing: {
'128': '32rem',
'144': '36rem',
},
borderRadius: {
'4xl': '2rem',
}
}
}
}
复制代码
以上是 tailwindcss 的主题配置文件,你们能够按照视觉的要求来作调整。好比说今天视觉以为屏幕的 lg 尺寸应该是 976px
,过段时间又以为须要改为 1000px
。对于开发者而言咱们只须要修改一行代码就能全局生效了,很舒服。
可是假如说视觉本来定义的边距规则以下:
// tailwind.config.js
module.exports = {
theme: {
spacing: {
px: '1px',
0: '0',
0.5: '0.125rem',
1: '0.25rem',
1.5: '0.375rem',
2: '0.5rem',
2.5: '0.625rem',
3: '0.75rem',
3.5: '0.875rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
// ...
},
}
}
复制代码
如今须要咱们把 6
换成 1.6rem
,可是这个规则只须要做用在某些组件上,此时咱们须要如何修改样式?新增一个 spacing
而后一个个去替换须要的地方么?
上述场景笔者认为仍是很多见的,最起码在咱们公司内部是存在这样的问题。已经定义了视觉规范并体如今内部的组件库上,可是在业务中仍是有很多视觉会去动组件的基本样式,这里改个边距,那里改个颜色等等。本来组件库是为了帮助开发者提效的,可是在这种场景下开发者反而会抱怨改动样式极大提升了他们的成本,而且大部分状况下还不得不这样作。
再说回传统 CSS 的问题,其实 tailwindcss 也解决了一部分,可是仍旧存在没解决的点,好比说:
以上说了那么多,其实对于咱们使用 tailwindcss 而言,有利也有弊。它确定是存在很好用的场景的,好比说写我的的产品页,或者说业务中样式变化不频繁的场景中,可是若是说须要业务中全量切换到 tailwindcss 的话,笔者确定是持保留态度的。
对于 Atom CSS 来讲,你们应该是不可否认它的优势的,可是咱们是否有办法在尽量避免它的缺点的状况下又得到它的优势呢?答案是有的,可是在讲答案以前我想先来聊聊 CSS-in-JS。
CSS-in-JS(下文以 CIJ 缩写表示)核心就是在用 JS 写 CSS,这一样也是一个颇具争议的技术方案。
在这个领域下有两个库比较流行,分别为:styled-components(下文以 sc 缩写表示) 以及 Emotion。笔者目前已经用了一年多的 sc 了,来粗略谈谈它的优缺点。
咱们先来了解下 sc 是怎么使用的。首先说下 sc 和 Emotion 的语法是趋于一致的,应该是为了 API 层面的统一吧,甚至前者还依赖了后者的一些包,如下是 sc 的经常使用写法:
const Button = styled.a` display: inline-block; ${props => props.primary && css` background: white; color: black; `} `
render(
<div> <Button href="https://github.com/styled-components/styled-components" target="_blank" rel="noopener" primary > GitHub </Button> <Button as={Link} href="/docs"> Documentation </Button> </div>
)
复制代码
用法咱们很少展开,有兴趣的能够去官方看看,基本没有学习成本的,主要是一些样式组件上的使用。
另外 sc 并非最终生成了内联样式,而是帮咱们插入了 style
标签。
笔者用了一年多的 sc,感受这种方案对于 React 来讲是很香的。而且解决了我很讨厌的传统写 CSS 的一些点,因此关于优劣点这段的讲述会有点主观。
首先 CSS-in-JS 这种方案不只能让咱们完整使用到 CSS 的功能,并且还扩充了一些用法。好比说选择器这块,在 sc 中咱们能经过选择组件的方式来编写样式,以下代码:
const Button = styled.a` ${Icon} { color: green; } `
复制代码
另外既然咱们经过 JS 来管理 CSS 了,那么咱们就能够充分享受 JS 带来的工具链好处了。一旦项目中出现没有使用到的样式组件,那么 ESLint 就能够帮助咱们找到那些死代码并清除,这个功能对于大型项目来讲仍是能减小一部分代码体积的。
除此以外,样式污染、取名问题、自动添加前缀这些问题也很好的解决了。
除了以上这些,再来聊两点不容易注意到的。
首先是动态切换主题。由于咱们是经过 JS 来写 CSS 了,那么咱们就能够动态地控制样式。若是你的项目有切换主题这种相似的大量动态 CSS 的需求,那么这个方案会是一个不错的选择。
还有个点是按需加载。由于咱们是经过 JS 写的 CSS,现阶段打包基本都走的 code split,那么就能够实现 CSS 文件的按需加载,而不是传统方式的一次性所有加载进来(固然也是能够优化的,只是没那么方便)。
聊完了优势咱们再来讲说缺点。
第一个缺点很明显,有学习成本,固然笔者以为这个学习曲线仍是平缓的。
运行时成本,sc 自己就有文件体积,加上还须要动态生成 CSS,那么这其中一定有性能上的损耗。项目越大影响的也会越大,若是你的项目对于性能有很高的要求,那么须要谨慎考虑使用。另外由于 CSS 动态生成,因此不能像传统 CSS 同样缓存 CSS 文件了。
代码复用性和传统写 CSS 的方式没啥两样。
最后点是代码耦合问题。会有人以为在大型项目中将 CSS 及 JS 写在一块儿会增长维护成本,而且也不符合 CSS 须要分离开来想法。
看了上文,若是你以为两种方案都挺好的话,能够了解下 twin.macro,这个库(还有别的竞品)把这两种方案融合了起来。
import 'twin.macro'
const Input = () => <input tw="border hover:border-black" />
const Input = tw.input`border hover:border-black`
复制代码
这种方案之上其实还有更好玩的方式,能帮助咱们尽可能取其精华而去其糟粕。
假如说我不只想用 CSS-in-JS,还想把 Atom CSS 也给整上,可是又不想记 / 写一大堆类名,我这个想法能实现么?
答案是有的。利用运行时的方式把单个样式抽离出来,最后实现虽然咱们写的是 CSS-in-JS,可是最终呈现的是 Atom CSS 的样子。
以 styletron 举个例子,开发时候的代码长这样:
import { styled } from "styletron-react";
export default () => {
// Create a styled component by passing
// an element name and a style object
const Anchor = styled("a", {
fontSize: "20px",
color: "red"
});
return <Anchor href="/getting-started">Start!</Anchor>;
};
复制代码
实际编译出来的时候长这样:
<html>
<head> <style> .foo { font-size: 20px; } .bar { color: red; } </style> </head>
<body> <a href="/getting-started" class="foo bar">Start!</a> </body>
</html>
复制代码
这样的方式就能很好地享受到两种方案带来的好处了。可是这类方案笔者找了些竞品,以为尚未前二者方案来的流行,你们了解一下便可。另外这种方式带来的运行时成本应该会更大,也许能够配套打包工具在本地先作一次预编译(一个不成熟的想法,说错勿喷)?
说了那么多方案,可能读者会有疑问,那么我到底该用啥?这里笔者说下本身的想法。
首先对于 sc 来讲,笔者以为很香,在项目中大范围用起来何尝不可,固然咱们还能够搭配着 Atom CSS 一块儿来写通用样式。
对于 Atom CSS,笔者我的认为不适合项目中大规模使用,起码在咱们公司内部不会是一个好方案,毕竟视觉真的会来动某些通用样式。
你们也能够来讲说各自的见解。
本文同步更新于公众号「前端真好玩」,欢迎关注。