博客改版及 Tailwind CSS 实践

2019-11-12 21:39:40 +08:00
 djyde

原载于我的独立博客: https://lutaonan.com/blog/what-is-tailwindcss-and-how-did-i-apply-it-on-my-blog

如您所见,本博客在前不久进行了微小的改版,改版的目的是做一个可以承载更多元内容的版式,如无意外,在未来的不久,我会增加「摄影」和「乐评」两个新的版块。

但本文想要讨论的是 Tailwind CSS 这个框架,我用 Tailwind CSS 重写了整个博客的 UI, 减少了 90% 的 CSS 代码,开发时间加起来只有短短数小时,就完成了这个 Mobile First 的 Redesign (如果这也算 design 的话).

传统的 CSS 框架 —— 如 Bulma 之流,会预设很多组件样式,例如你只需给 <button> 一个 btn 的 class name, 你就能得到一个好看的 button. 但 Tailwind 不同,它没有提供任何的预设样式,

所以 Tailwind CSS 声称自己为:

A utility-first CSS framework for rapidly building custom designs.

Instead of opinionated predesigned components, Tailwind provides low-level utility classes that let you build completely custom designs without ever leaving your HTML.

—— Tailwind CSS 官网

可以看出,Tailwind CSS 的目的不是直接把设计过的东西给你,而是帮助你更快地实现你的设计。我想大家或多或少也有对流行 UI 框架审美疲劳的感受,Tailwind CSS 就是为此而设的。

为了解释 utility-first 的含义,我想了很久 utility 如何翻译比较信达雅,但我没有想到。所以下面我将通过亲身体验来解释 utility-first 这一词。

一直以来我很怕写 CSS, 一是我没有什么设计天赋,我只有审美天赋 —— 我知道什么是好看,但不知道怎么做才会好看。二是写 CSS 很无聊 —— 为了给一个元素定位,我需要给 HTML 元素命名,然后到样式文件写一堆无聊又重复的 CSS, 但又不想用现有框架写好的设计。 最怕的是写响应式的页面,一想到 media query 我就很头疼。

写自己博客的 CSS,时常遇到多个元素的样式有些交集:

<div class="foo">
	字体颜色是黑色,需要加粗且文本居中
</div>
<div class="footer">
	字体颜色是灰色,需要加粗且文本居中
</div>

遇到这种情况,我有以下选择:

  1. 在 css 文件里给 .foo .footer 都写上 font-weight: bold; text-align: center;
  2. 直接给这两个 div 写 inline css font-weight: bold; text-align: center;
  3. font-weight: bold; text-align: center; 单独写成一个 class, 应用到两个 div 上

这些选择我都不喜欢,我更喜欢像这样:

<style>
.text-center {
	text-align: center
}
.font-bold {
	font-weight: bold;
}
</style>

<div class="foo text-center font-bold">
	字体颜色是黑色,需要加粗且文本居中
</div>
<div class="footer text-center font-bold">
	字体颜色是灰色,需要加粗且文本居中
</div>

我喜欢像这样把一些常用的 CSS 原子化,这样可以直接通过 class name 复用到任何的元素。这些原子化的通用的 class 我们可以称为 utility. Tailwind CSS 提供的就是一些 utility, 这就是 utility-first 的含义。

在我博客首页有一个这样的导航:

HTML 结构如下:

<nav>
  <div>
    <div :key="navItem.title" v-for="navItem in $themeConfig.navs">
      <a class="hover:text-gray-900 text-center" :href="navItem.url">
        <div>{{ navItem.title }}</div>
        <div>{{ navItem.alias }}</div>
      </a>
    </div>
  </div>
</nav>

使用 Tailwind CSS, 我不必费神给几个 div 命名,也不用给 div 写一堆 flex 布局,Tailwind CSS 提供了 flex 而已要用到的预设:

<nav>
  <div class="flex flex-col sm:flex-row w-full justify-center p-8">
    <div :key="navItem.title" v-for="navItem in $themeConfig.navs" class="mt-6 sm:mt-0 sm:ml-6 sm:mr-6 text-gray-600">
      <a class="hover:text-gray-900 text-center" :href="navItem.url">
        <div>{{ navItem.title }}</div>
        <div class="text-center text-sm font-serif">{{ navItem.alias.toUpperCase() }}</div>
      </a>
    </div>
  </div>
</nav>

如果你没看过 Tailwind CSS 的文档,你可能对这些 class 比较模糊,在这里我按顺序稍作解释:

几个 class 就能完成 flex 布局。

你还会注意到有 hover:text-gray-900, 这代表在 hover 的时候,color 为 gray.

这个导航在小屏幕时会变成竖向:

在上面的代码可以看到,这是通过 sm:flex-flow 实现的,意思是当屏幕大小超过 sm 时,就用 flex-flow. 在 Tailwind CSS 的 Responsive utility 里,预设了 sm, md, lg, xl 几个大小。这个 utility 减少了非常多的响应式设计代码量。

除了自己博客的例子,我特意到 dribbble 随便搜了一个设计来实现:

Codepen: https://codepen.io/djyde-1474473388/pen/RwwYPEv?editors=1000#0

Tailwind CSS 满足了我几点:

  1. 可以方便地做到响应式设计
  2. 丰富的预设,如字体大小,预设颜色
  3. 不用再想 class name

第二点很重要,也是为什么使用 Tailwind CSS 可以很容易做到好看的设计。读过 Refactoring UI 这本小书里面提到,Bad design 有时候是因为间距大小,字体大小,颜色的不统一导致的。如果没有一个固定的 Design system 规定了可以选用的这些参数,设计容易变得混乱。例如一个页面里面如果同时有 12px, 11px, 10px, 9px 大小的字,就会很难看。

Tailwind CSS 的 utility 对大小都有预设,像字体大小有 text-sm, text-md, text-lg 等等,颜色有 gray, pink, orange 等等(当然有可以自行扩展),这其实已经是一个很好的 Design system.

但 Tailwind CSS 毕竟不是一个组件框架,开发现代 Web App 的时候,只有 CSS 显然是不够的。如果选择 Tailwind CSS, 那就代表很有可能很多 (React, Vue) 组件需要自己动手实现。

另一个需要注意的地方是使用 Tailwind CSS 有一定的学习曲线,刚开始不可避免要不断翻文档,但是用她做一个页面之后基本就记住了,我的经验是用了一两天就不太需要看文档了。有点像学习 vim, 如果因为有一定的学习曲线所以错过这么好的东西,那未免太可惜了。

强烈推荐对 UI 设计感兴趣的朋友读一读 Refactoring UI, Refactoring UI 的两位作者,一个是 Tailwind CSS 的作者,一个是 Tailwind CSS Design system 的设计。

如果觉得这本书太贵,那至少读一读这篇 7 Practical Tips for Cheating at Design.

6318 次点击
所在节点    分享创造
18 条回复
momocraft
2019-11-12 21:44:35 +08:00
我也在用 tailwind css, 比较香

这里的 utility 可能比较接近经济学的效用?
hoyixi
2019-11-12 21:44:49 +08:00
也在用,现在写东西,最讨厌的就是写 CSS
buddie
2019-11-12 21:46:07 +08:00
本来新项目中要用,结果 team leader 一句 “我不想学别人的命名规范” 就被否了,撸纯的 css instead 😂
agdhole
2019-11-12 22:00:40 +08:00
像 sm:xx hover:xx 这种 classname 在 css 里面是怎么取的呢?
hoyixi
2019-11-12 22:01:33 +08:00
@buddie #3

这的确也是个考虑点,因为写就是一时,后面的维护才是长期的,一旦上船,想下船就能费心费力

现在我都越来越不想用那些时髦框架了,一升级,各种项目的维护扑面而来。虽说框架起到了灵活和降低复杂度的作用,但是如果框架本身折腾,带来的好处又大打折扣了

怀念 jQuery 的日子,一个字:稳
maomaomao001
2019-11-12 22:58:55 +08:00
这个好像有点像 atomic design 吧,
实践过 BEM,css modules 感觉都不是很好用
encro
2019-11-12 23:22:00 +08:00
前一阵子留意了下这个框架,发现不错,
大部分场景 bs4 已经够用了.
molvqingtai
2019-11-12 23:34:01 +08:00
这篇文章有毒,会让我手机闪退 bug
April5
2019-11-13 09:10:49 +08:00
哇擦,华软的师兄,师弟?我 13 级的哈哈哈
ssshooter
2019-11-13 09:15:12 +08:00
有意思,感谢分享
feehey
2019-11-13 10:07:40 +08:00
如果文章列表采用左对齐或许可读性更好一些...
orozot
2019-11-13 10:47:08 +08:00
这个就是之前流行过的 css 原子化吧,感觉原子化用来做定位布局是很合适的,但是不太适合组件内部细节处理
zhuoyan
2019-11-13 17:25:19 +08:00
css 原子类早就不推荐了啊
widdy
2019-11-13 19:31:27 +08:00
唉我们前端圈咋这么复古。
soseek
2020-03-27 22:34:42 +08:00
@zhuoyan 但有些时候比框架来的方便
Sapp
2020-12-18 17:09:25 +08:00
@buddie 可以尝试 css in js,然后把这些常用的样式封装成函数,直接调用函数,库会自动生成 class,解决了 class 取名问题,又有非常灵活的定制性,而且还不担心 css 污染,举个栗子
<div
css = {{
...flex(), // 自动设置 flex 相关 css
...background(url), // 自动设置类似 position,repeat 这些属性
fontWeight: 500 // 手写样式
}}
>xxx</div>

最后生成的 html 大概是
<div class={xxxx-组件名-xxxx}>xxx</div> 会是一串随机字符加你的组件名,可以设置生产环节不显示组件名,就完全是一段随机字符了,css 会自动插入

这个方案和 Tailwind 应该是一个思路,并且还能利用起来编辑器给 js/ts 做的类型推导和语法提示,同时还可以在一些需要定制的时候直接写 css,不用单独再头疼写个 class 怎么命名
djyde
2020-12-18 20:02:38 +08:00
@Sapp #16 你说的是 styled-system 吗 https://styled-system.com/
Sapp
2020-12-18 22:26:12 +08:00
@djyde 这种方案的实现多了去了,是哪个不重要,重要的是这个思路

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/618955

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX