<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>kongxiangyan (孔祥岩)</title>
    <link>https://beta.w2solo.com/kongxiangyan</link>
    <description/>
    <language>en-us</language>
    <item>
      <title>Mobius UI -  Neumorphism 风格 UI 框架预览版发布</title>
      <description>&lt;h2 id="Mobius UI Preview Release"&gt;Mobius UI Preview Release&lt;/h2&gt;
&lt;p&gt;(｡･∀･) ﾉﾞ 嗨，别来无恙呀！疫情期间，希望大家一切都好 🖖&lt;/p&gt;

&lt;p&gt;开门见山，这次主要跟大家分享三件事情：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;「Thoughts Lab」的近况和后续&lt;/li&gt;
&lt;li&gt;「Mobius UI」预览版本发布及简单介绍&lt;/li&gt;
&lt;li&gt;「&lt;strong&gt;Coding the World&lt;/strong&gt;」计划 —— &lt;strong&gt;我的就是你的&lt;/strong&gt;！！！&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Thoughts Lab"&gt;Thoughts Lab&lt;/h2&gt;
&lt;p&gt;按照新年之初的打算，今年上半年我的主要精力应该是实习 + 兼职开发 Thoughts Lab，但因为疫情原因呆在家中，手头只有一部 Intel Core m3 的超极本，不足以流畅进行复杂项目的开发工作，故该项目也被迫停滞，无法及时更新，在这里先跟关心项目进展的朋友们说声抱歉。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💬 如果你不知道 Thoughts Lab 是什么，请移步： &lt;a href="https://mp.weixin.qq.com/s?__biz=MzIyODcyNjQ4NA==&amp;amp;mid=2247483658&amp;amp;idx=1&amp;amp;sn=1321880380f99b67f9b848b66111cc25" rel="nofollow" target="_blank" title=""&gt;Thoughts Lab 发布啦！&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;略让人伤心的是，Thoughts Lab 自 1 月 1 日发布至今，在没有任何推广的情况下，累计用户共 652 人，其中 99% 都是通过推送获悉的开发者朋友们 ❤。由于采用邮箱认证，只有本校的同学才能够获得发布信息的权限，所以小程序首页的消息仍然停留在我发布初写的介绍内容，甚是荒凉。&lt;/p&gt;

&lt;p&gt;看着一门心思做的小玩意儿无人问津，心里也有点不甘，接下来我会上手做一些推广工作，让同学们知道有这样一个东西为大家提供浏览、发布信息的功能 💌，希望能够正常运作起来，收集反馈为后续的优化和更新工作做准备。&lt;/p&gt;

&lt;p&gt;特别感谢这段时间跟我讨论技术 “架构” 和服务选型的朋友，使我不至于将这个项目的细节完全遗忘 😛 同时，也有一个好消息跟大家分享，宅家期间，我找到了适合盈利的新产品，主体是一款浏览器扩展，目前是 Side Side Project 的状态。我完全相信它的潜力，所以 Thoughts Lab 也不必再纠结于用爱发电和维持生计的矛盾，大家能够顺利地用起来对我来说就是最开心的事情。 &lt;/p&gt;
&lt;h2 id="Mobius UI"&gt;Mobius UI&lt;/h2&gt;
&lt;p&gt;🎨 Mobius UI 是我为新产品准备的 UI 框架，目前初具雏形，今天早些时候整合了近期的开发工作、补充了文档，更新了 GitHub Repo 正式与大家见面。&lt;/p&gt;

&lt;p&gt;&lt;img src="/uploads/photo/2020/634af961-bbe8-4252-9aaa-d1db2b715ebc.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;速览链接：🌟 &lt;a href="https://github.com/we-mobius/mobius-ui" rel="nofollow" target="_blank" title=""&gt;GitHub Repository&lt;/a&gt;、💻 &lt;a href="https://mobius-ui.21yunbox.com/" rel="nofollow" target="_blank" title=""&gt;Mobius UI Preview Page&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;决定动手造轮子之前，我花了不少功夫寻找现有的优秀方案，包括样式库、组件库和设计系统，考察的标准主要是以下三点：赏心悦目；样式和组件低耦合，可定制、易扩展；开源、稳定维护、社区活跃，结果都不是很理想，虽然最主要的原因可能只有一个：「&lt;strong&gt;不是自己写的&lt;/strong&gt; 😕」，而  Mobius UI 将具备以上所有优点。&lt;/p&gt;

&lt;p&gt;设计上，Mobius UI 参考了  &lt;a href="https://uxdesign.cc/neumorphism-in-user-interfaces-b47cef3bf3a6" rel="nofollow" target="_blank" title=""&gt;Neumorphism&lt;/a&gt; 风格，使用「近似的前景色和背景色 + 亮度适当的阴影」来呈现一种「接地气」的质感，同时又独具意料之外的「来自未来的美感」。但这种风格的缺点非常明显，大片近似的颜色导致页面可访问性较差，元素与元素之间的区隔度不够，层次的滥用也会导致页面内容缺乏关注点，用户的眼睛眨巴眨巴不知何处安放 👀 等。对于这些问题，我在实现的时候基于不断尝试进行了权衡，一方面使用特定组合的颜色提升了内容元素的观感，尽量采用多种方式而非单纯颜色的改变来标识元素的状态，另一方面，总结了一系列「要与不要」设计规范来提供使用建议。尽管如此，它的使用效果也是因人而异的，上下限差距极大，这是我在文档中建议大家优先在 Toy Projects 中投入使用的原因之一。&lt;/p&gt;

&lt;p&gt;技术上用「&lt;strong&gt;中规中矩&lt;/strong&gt;」来形容恰到好处，使用基本的 CSS 实现样式 + 使用 PostCSS 做预处理器优化编写状态逻辑的体验，无他。&lt;/p&gt;

&lt;p&gt;目前来说，Mobius UI 具备以下特色：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Utility First，推崇使用「功能类」组合出组件，而不是直接定义组件样式；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verbose Variables 居多，目前可以使用 Minify + Gzip/Brotli 达到 80% 以上的压缩比，本地构建的话使用 PurgeCSS 体积更小；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持了 Dark Mode、&lt;strong&gt;Light Source&lt;/strong&gt;（设置光源方向以调整阴影）；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持引入 Houdini 和 JavaScript 做局部或全局的渐进增强；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;具备完全可定制性，变量随处可见但逻辑得体，支持任意粒度的调节；&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;设计了简单的算式，可以通过给定的种子值，生成独特的配色方案，&lt;strong&gt;Mobius UI 的默认配色方案由本人生日生成&lt;/strong&gt; 🤐&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;var-color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* --seed: 624;
  --cigaret: calc(var(--seed) - 360);
  --mobius: calc(360 - 264); */&lt;/span&gt;

  &lt;span class="py"&gt;--dark-color-darker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;7%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dark-color-darker-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;12%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dark-color-normal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;17%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dark-color-lighter-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;22%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--dark-color-lighter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;27%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="py"&gt;--light-color-darker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;68%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color-darker-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;73%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color-normal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;83%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color-lighter-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;93%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--light-color-lighter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;98%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="py"&gt;--cigaret-color-darker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;17%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--cigaret-color-darker-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--cigaret-color-normal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--cigaret-color-lighter-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;70%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--cigaret-color-lighter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;264&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;83%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="py"&gt;--mobius-color-darker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;17%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--mobius-color-darker-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--mobius-color-normal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--mobius-color-lighter-m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;70%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;--mobius-color-lighter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;83%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;了解更多详细的内容请移步 🌟 &lt;a href="https://github.com/we-mobius/mobius-ui" rel="nofollow" target="_blank" title=""&gt;GitHub Repository&lt;/a&gt;，或者访问 💻 &lt;a href="https://mobius-ui.21yunbox.com/" rel="nofollow" target="_blank" title=""&gt;Mobius UI Preview Page&lt;/a&gt; 重温一下（我非常喜欢在晚上的时候盯着夜间模式反复打量）。&lt;/p&gt;

&lt;p&gt;当下 Mobius UI 还在预览阶段，仅仅完成了样式基本框架的搭建和逻辑的梳理，下一个阶段的开发重点是基础元素的丰富和补充，将历时两周左右，下下个阶段的开发重点是渐进增强、MicroAnimation、和复杂组件，更具体的信息我会更新在 Repo 中的 Todos &amp;amp; Roadmaps，大家不妨点个 Star、加个 Watch 追踪 Mobius UI 的最新进展。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;虽说 Mobius UI 是为新产品准备的，我也希望它能够应用在我开发的所有作品中，为大家提供一致的体验，这是一个次要的目标，但毫无疑问它将会出现在同一系列的文章中 🤔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="Coding the World"&gt;&lt;strong&gt;Coding the World&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Coding the World 是一个「&lt;strong&gt;工作坊&lt;/strong&gt;」，按期举行，在这里你可以跟我一起实现 Thoughts Lab 的下一个应用，仅有的参加条件就是手头有一台电脑、以及每天两小时左右（每周 10 小时左右）的时间。对我来说，这是一个将知识和经验结构化输出的过程，对你而言，将获得包括但不限于：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;一款精美、别致、实用的小程序；&lt;/li&gt;
&lt;li&gt;腾讯云开发赠送的精美礼品；&lt;/li&gt;
&lt;li&gt;一次「&lt;a href="https://mp.weixin.qq.com/s/YwV2GG0rvnpGjRM1YBOOuQ" rel="nofollow" target="_blank" title=""&gt;高校微信小程序应用开发大赛&lt;/a&gt;」参赛经验；&lt;/li&gt;
&lt;li&gt;不止一项终身收益的技能；&lt;/li&gt;
&lt;li&gt;一个看待世界的新视角；&lt;/li&gt;
&lt;li&gt;一群可爱的小伙伴；&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;第一期的主题由我擅自决定了，我们将「&lt;strong&gt;各自&lt;/strong&gt; | &lt;strong&gt;共同&lt;/strong&gt;」完成一个「&lt;strong&gt;头像定制&lt;/strong&gt;」小程序，按照难度大致划分为三个阶段：简单版本、自定义版本、社交化版本。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;简单版本的预览、参加方式（第一期不超过 20 人，本校同学优先）、进度大纲等详细信息请访问：&lt;a href="https://www.yuque.com/docs/share/85a6966a-77fa-4d1e-a034-85fc115c0a48" rel="nofollow" target="_blank" title=""&gt;Coding the World Ⅰ&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="Thoughts"&gt;Thoughts&lt;/h2&gt;
&lt;p&gt;我非常害怕死亡，害怕到极致，但也许正出于对死亡的恐惧，才让我表现得一副「无所畏惧」的样子。2003 年非典的伤塑造了今天的我，现在是否也有孩子在遭受同样的苦楚，我不知道，祝福他（她）们未来一切都好。&lt;/p&gt;

&lt;p&gt;希望自己一直善良、一直热血，永远向往自由。&lt;/p&gt;

&lt;p&gt;&lt;img src="/uploads/photo/2020/3cfcc63b-0263-4e94-9e26-528e6d9adf28.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>kongxiangyan</author>
      <pubDate>Tue, 07 Apr 2020 10:00:54 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/396</link>
      <guid>https://beta.w2solo.com/topics/396</guid>
    </item>
    <item>
      <title>[TailWind CSS] CSS 工具类和 “关注点分离”</title>
      <description>&lt;p&gt;计划中准备使用 TailWind CSS 重构 Thoughts Lab 的 UI 系统，在操作之前，有必要说服自己确实要这样做！Adam Wathan 是 TailWind CSS 的作者，在他发布 TailWind 之前写过一篇文章，这篇文章详实地梳理了 CSS 诸多方案之间的演变历程和权衡取舍，深有感触，想来大家概有相似的考虑，故译为中文分享给大家！&lt;/p&gt;

&lt;p&gt;文中无法添加外链，而我不喜欢将链接作为注释添加的做法，所以将相关的资料梳理成了文档上传到云端，包含文中涉及到的所有相关组件和文章的链接，以及逐句逐段翻译的文档，供大家学习参考！公众号后台回复 TailWind20200105 获取！公众号叫 &lt;strong&gt;Cigaret&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://tailwindcss.com/img/twitter-large-card.png" title="" alt=""&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;这篇文章译自：&lt;a href="https://adamwathan.me/css-utility-classes-and-separation-of-concerns/" rel="nofollow" target="_blank" title=""&gt;CSS Utility Classes and "Separation of Concerns" - Adam Wathan - August 7, 2017&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在过去的几年里，我书写 CSS 的方式已经从一种非常 “语义化” 的方法转变为一种更类似于 “功能性 CSS” 的方法。&lt;/p&gt;

&lt;p&gt;这种新的方式能够引起广大开发者由衷的反应！我想解释一下我如何做到这一点，并且分享我在此过程中获得的经验和教训。&lt;/p&gt;
&lt;h2 id="阶段一：“语义化” CSS"&gt;阶段一：“语义化” CSS&lt;/h2&gt;
&lt;p&gt;当你想要学习如何更优雅地写 CSS 时，“关注点分离” 将是你听到的最佳实践之一。它提倡，HTML 中只应该包含有关内容的信息，而所有的样式都应该交给 CSS 来实现。以下面这段 HTML 为例：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Hello there!
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它违反了 “关注点分离” 的原则，&lt;code&gt;.text-center&lt;/code&gt; 是样式信息，而我们将它泄露到了 HTML 中。推荐的方式是按照内容对样式类进行命名，然后在 CSS 中完善这些类的样式定义，像下面这样：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"greeting"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Hello there!
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遵循这种方式的典型案例是 &lt;a href="http://www.csszengarden.com/" rel="nofollow" target="_blank" title=""&gt;CSS Zen Garden&lt;/a&gt;，它旨在向我们展示，一个良好遵循 “关注点分离” 的站点，仅仅通过替换样式表就能重新对其进行设计。这种方式下，工作流程大概如下：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;为新 UI 编写 HTML，以 “作者信息卡片” 为例：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn-images-1.medium.com/max/1600/0*o3c1g40EXj65Fq9k."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Adam Wathan&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
      Adam is a rad dude who likes TDD, Active Record, and garlic bread with cheese. He also hosts a decent podcast and has never had a really great haircut.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;根据内容添加描述性的 CSS 类：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn-images-1.medium.com/max/1600/0*o3c1g40EXj65Fq9k."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Adam Wathan&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        Adam is a rad dude who likes TDD, Active Record, and garlic bread with cheese. He also hosts a decent podcast and has never had a really great haircut.
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;在 CSS 或者 Less、Sass 中完善类的样式以在 HTML 中呈现出来：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.author-bio&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;85%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="nf"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="mi"&gt;.75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式很合我的胃口，有一段时间我一直以这种方式写 HTML 和 CSS。&lt;/p&gt;

&lt;p&gt;但是最终，开始感觉有点不太对劲，我确实遵循了 “关注点分离”，但是 CSS 和 HTML 之间仍然存在着明显的耦合。大多数时候 CSS 就像是 HTML 的一面镜子，HTML 的结构在 CSS 选择器的嵌套中体现的淋漓尽致。&lt;/p&gt;

&lt;p&gt;用一句话来描述就是：&lt;strong&gt;我的 HTML 确实不用关注样式了，但是我的 CSS 却不得不非常关心 HTML 的结构。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;也许是我没有成功地彻底分离关注点吗？&lt;/p&gt;
&lt;h2 id="阶段二：将样式与结构解耦"&gt;阶段二：将样式与结构解耦&lt;/h2&gt;
&lt;p&gt;为这种耦合寻找解决方案花了不少时间，许多人的建议都是向 HTML 中添加更多的类，这样我就可以直接定义它们，同时，尽可能降低 CSS 选择器权重以降低 CSS 对于 DOM 结构的依赖。&lt;/p&gt;

&lt;p&gt;最提倡这种想法的方法是 BEM（&lt;a href="http://getbem.com/introduction/" rel="nofollow" target="_blank" title=""&gt;Block Element Modifer&lt;/a&gt;），按照 BEM 的书写方式，之前的作者信息卡片的 HTML 可以变成：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio__image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn-images-1.medium.com/max/1600/0*o3c1g40EXj65Fq9k."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio__name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Adam Wathan&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author-bio__body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Adam is a rad dude who likes TDD, Active Record, and garlic bread with cheese. He also hosts a decent podcast and has never had a really great haircut.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时 CSS 如下：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.author-bio&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;85%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.author-bio__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.author-bio__content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.author-bio__name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.author-bio__body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这确实带来了巨大的进步，我的 HTML 依然保持 “语义化” 并且不包含任何样式信息，同时 CSS 也不必过于关注 DOM 结构了，还降低了不必要的 CSS 选择器权重的使用！&lt;/p&gt;

&lt;p&gt;但我很快又左右为难了 😥&lt;/p&gt;
&lt;h3 id="处理相似的组件"&gt;处理相似的组件&lt;/h3&gt;
&lt;p&gt;假设我要为网站添加一个新功能：用卡片布局展示文章预览。文章的预览卡片顶部有一个完整出血的图像，下面有一个填充内容部分，一个粗体标题和一些较小字号的正文。其实跟作者信息卡片看起来差不多：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/4323180/29088772-342696c0-7c48-11e7-877d-9f28b52a7a51.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;在遵循关注点分离的原则下如何处理这种问题呢？显然，我们不能直接将 &lt;code&gt;.author-bio&lt;/code&gt; 套用到文章预览上，这不符合语义化。我们需要单独定义一个 &lt;code&gt;.article-preview&lt;/code&gt; 的类来表示这个新的组件。完成后， HTML 看起来如下：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-preview"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-preview__image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://i.vimeocdn.com/video/585037904_1280x720.webp"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-preview__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-preview__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Stubbing Eloquent Relations for Faster Tests&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"article-preview__body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      In this quick blog post and screencast, I share a trick I use to speed up tests that use Eloquent relationships but don't really depend on database functionality.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如何处理 CSS 呢？&lt;/p&gt;
&lt;h3 id="第一种方式：Ctrl + C &amp;amp; Ctrl + V"&gt;第一种方式：Ctrl + C &amp;amp; Ctrl + V&lt;/h3&gt;
&lt;p&gt;最直接的实现方式就是复制 &lt;code&gt;.author-bio&lt;/code&gt; 的样式，然后改个名字，就像下面这样：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.article-preview&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;85%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式非常不优雅，也会带来另外的隐患，即这些组件之间很容易产生表现不一致的情况，哪怕只是稍微改动一点间距或者字体颜色。&lt;/p&gt;
&lt;h3 id="第二种方式：拓展作者信息卡片组件"&gt;第二种方式：拓展作者信息卡片组件&lt;/h3&gt;
&lt;p&gt;另外一种方式是使用预处理器的 &lt;code&gt;@extend&lt;/code&gt; 特性，复用在 &lt;code&gt;.author-bio&lt;/code&gt; 组件中已经定义好的样式：&lt;/p&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.article-preview&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.author-bio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.author-bio__image&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.author-bio__content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.author-bio__name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.article-preview__body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@extend&lt;/span&gt; &lt;span class="nc"&gt;.author-bio__body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一般来说这样使用 &lt;code&gt;@extend&lt;/code&gt; 并不是&lt;a href="https://csswizardry.com/2014/11/when-to-use-extend-when-to-use-a-mixin/" rel="nofollow" target="_blank" title=""&gt;推荐的方式&lt;/a&gt;，但它确实能够解决我们面临的问题。我们得以避免 CSS 的简单复制，HTML 也免于掺杂样式信息。&lt;/p&gt;

&lt;p&gt;此外，我们其实还有另外一种选择 😁&lt;/p&gt;
&lt;h3 id="第三种方式：创建一个内容无涉的组件"&gt;第三种方式：创建一个内容无涉的组件&lt;/h3&gt;
&lt;p&gt;从 “语义化” 角度考虑，我们的 &lt;code&gt;.author-bio&lt;/code&gt; 和 &lt;code&gt;.article-preview&lt;/code&gt; 两个组件之间确实没有什么共同之处。但从设计的角度来说，它们保持着高度一致。我们可以基于它们的共同之处创建一个新的组件，并在两种类型的内容中都使用这个新的组件类，不妨把他叫做 &lt;code&gt;.media-card&lt;/code&gt;，CSS 如下：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.media-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;85%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.media-card__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.media-card__content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.media-card__title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.media-card__body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在作者信息卡片的 HTML 看起来是这样的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn-images-1.medium.com/max/1600/0*o3c1g40EXj65Fq9k."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Adam Wathan&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Adam is a rad dude who likes TDD, Active Record, and garlic bread with cheese. He also hosts a decent podcast and has never had a really great haircut.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文章预览卡片的 HTML 是这样的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__image"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://i.vimeocdn.com/video/585037904_1280x720.webp"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Stubbing Eloquent Relations for Faster Tests&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"media-card__body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      In this quick blog post and screencast, I share a trick I use to speed up tests that use Eloquent relationships but don't really depend on database functionality.
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式确实也解决了 CSS 复制的问题，但我们是不是混合了关注点呢？冥冥之中，HTML 中内置了我们想要这些内容全部添加 “媒体卡片” 样式的意图，另外一个问题是现在我们如何在不改变文章预览卡片样式的情况下改变作者信息卡片的样式呢？&lt;/p&gt;

&lt;p&gt;但反过来想一想，如果我们需要添加一种新的内容，它也恰巧使用同样的样式呢？如果遵循 “语义化” 方式的话，我们需要编写新的 HTML，添加新的基于特定内容的类名，在 CSS 样式表中为它创建新的样式类，然后通过复制或 &lt;code&gt;@extend&lt;/code&gt; 抑或混合起来复用共通的样式。假如使用我们内容无涉的 &lt;code&gt;.media-card&lt;/code&gt; 样式类，我们只需要编写新的 HTML，然后将类写上去就好了，甚至都不需要打开样式表文件 ┑(￣Д ￣)┍ 如果我们真的混合了关注点，我们不应该忙于修改多处文件吗 🧐&lt;/p&gt;
&lt;h3 id="“关注点分离”是一个稻草人"&gt;“关注点分离” 是一个稻草人&lt;/h3&gt;
&lt;p&gt;当你基于 “关注点分离” 的原则去考虑 HTML 和 CSS 的关系时会发现，它们是非黑即白的。你要么遵循了关注点分离，要么没有遵循，我相信这不是正确的权衡方式。&lt;/p&gt;

&lt;p&gt;或者我们应该考虑一下 “依赖方向”，归纳一下，我们写 HTML 和 CSS 的时候有两种方式：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CSS 依赖 HTML&lt;/strong&gt;，基于内容定义类名，将 HTML 作为 CSS 的依赖。HTML 是独立的，它毫不关心自己长什么样子，它只是开放了一个可用来定义样式的类。CSS 必须知道 HTML 暴露的类名是什么，然后根据这些类名来定义 HTML 的样式。在这种模式中， HTML 是很方便修改样式的，但 CSS 很难重用！&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTML 依赖 CSS&lt;/strong&gt;，以一种内容无涉的方式命名样式类，将 CSS 作为 HTML 的依赖。CSS 是独立的，它完全不用关心有哪些内容将会使用它，它只是开放一系列内置的样式块，你可以将它们应用到 HTML 标记中。HTML 需要关心 CSS 开放了那些类给它，它如何将这些类组合起来以达到预期的效果。在这种模式中，CSS 是可复用的，但 HTML 修改样式不那么方便了。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CSS Zen Garden 采用了第一种方式，像 &lt;a href="http://v4-alpha.getbootstrap.com/" rel="nofollow" target="_blank" title=""&gt;Bootstrap&lt;/a&gt; 或 &lt;a href="http://bulma.io/" rel="nofollow" target="_blank" title=""&gt;Bulma&lt;/a&gt; 这样的 UI 框架采用了第二种方式。&lt;/p&gt;

&lt;p&gt;两种方式都不能说是错误的，它体现的是一种抉择而已，你需要考虑在你的应用情境中，哪一种更加重要。在你参与的项目中，什么更有价值呢？是便捷地重设计 HTML 样式吗？还是 CSS 样式的复用呢？&lt;/p&gt;
&lt;h3 id="选择复用性"&gt;选择复用性&lt;/h3&gt;
&lt;p&gt;Nicolas Gallagher 写的 『&lt;a href="http://nicolasgallagher.com/about-html-semantics-front-end-architecture/" rel="nofollow" target="_blank" title=""&gt;关于 HTML 语义化和前端架构&lt;/a&gt;』 对我来说是一个转折点。这里我不打算复述他的观点，感兴趣的同学可以去看。对我而言，从这篇文章中，我更加确信了优化可复用的 CSS 是我目前做的各种项目的最佳选择。&lt;/p&gt;
&lt;h2 id="阶段三：内容无涉的 CSS 组件"&gt;阶段三：内容无涉的 CSS 组件&lt;/h2&gt;
&lt;p&gt;在这一点上，我的目标是尽可能避免基于内容创建样式类，而不是一味追求样式的最大化复用。现在类名看起来是这样子的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.card&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.btn&lt;/code&gt;, &lt;code&gt;.btn--primary&lt;/code&gt;, &lt;code&gt;.btn--secondary&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.badge&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.card-list&lt;/code&gt;, &lt;code&gt;.card-list-item&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.img--round&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.modal-form&lt;/code&gt;, &lt;code&gt;.modal-form-section&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;……&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我注意到，当我专注于创建可复用的样式类时，&lt;strong&gt;一个组件做的事情越多，或者说一个组件越明确、具体，它就越难复用&lt;/strong&gt;。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more a component does, or the more specific a component is, the harder it is to reuse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这里有一个直观的例子，假设我们要构建一个表单，它有很多个部分，最后是一个提交按钮。如果我们把所有的部分都视为 &lt;code&gt;.stacked-form&lt;/code&gt; 组件的一部分，那么提交按钮的类名会是 &lt;code&gt;.stacked-form__button&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但在我们的网站中，也许还会有其它的按钮，它可能不是表单的一部分，但是样式却是雷同的。在这些按钮上沿用 &lt;code&gt;.stacked-form__buttom&lt;/code&gt; 类显然没有多大意义，因为它们不是表单的一部分。不过，既然这些按钮在各自的页面中都承担着主要的操作，我们是否可以尝试按照这一共同特性将它命名为 &lt;code&gt;.btn--primary&lt;/code&gt; 呢，尝试如下：&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;form class="stacked-form" action="#"&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
    &amp;lt;div class="stacked-form__section"&amp;gt;
&lt;span class="gd"&gt;-     &amp;lt;button class="stacked-form__button"&amp;gt;Submit&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     &amp;lt;button class="btn btn--primary"&amp;gt;Submit&amp;lt;/button&amp;gt;
&lt;/span&gt;    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后，我们想让这个表单看起来像是在一个浮动卡片中。第一种实现方式是创建一个修饰符，将它运用在表单上：&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- &amp;lt;form class="stacked-form" action="#"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;lt;form class="stacked-form stacked-form--card" action="#"&amp;gt;
&lt;/span&gt;    &amp;lt;!-- ... --&amp;gt;
  &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但如果我们已经有一个 &lt;code&gt;.card&lt;/code&gt; 样式类的话，为什么我们不将它们组合使用呢？&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;+ &amp;lt;div class="card"&amp;gt;
&lt;/span&gt;    &amp;lt;form class="stacked-form" action="#"&amp;gt;
      &amp;lt;!-- ... --&amp;gt;
    &amp;lt;/form&amp;gt;
&lt;span class="gi"&gt;+ &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，我们的 &lt;code&gt;.card&lt;/code&gt; 可以作为任何内容的载体，而 &lt;code&gt;.stacked-form&lt;/code&gt; 也不必被扩展，还可以放置在任何容器的内部。&lt;/p&gt;

&lt;p&gt;基于此，我们从组件中获得了更多的复用性，并且免于编写新的 CSS。&lt;/p&gt;
&lt;h2 id="提取子组件"&gt;提取子组件&lt;/h2&gt;
&lt;p&gt;假设我们需要在表单的底部添加另外一个按钮，它跟已有的按钮之间应该有一定的间隔：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Need some space in here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一种实现方式时创建一个新的子组件，比如 &lt;code&gt;.stacked-form__footer&lt;/code&gt;，然后为每个按钮添加额外的类名，叫做 &lt;code&gt;.stacked-form__footer-item&lt;/code&gt;，然后使用后代选择器实现间距的添加：&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;form class="stacked-form" action="#"&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
&lt;span class="gd"&gt;-   &amp;lt;div class="stacked-form__section"&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+   &amp;lt;div class="stacked-form__section stacked-form__footer"&amp;gt;
&lt;/span&gt;&lt;span class="gd"&gt;-     &amp;lt;button class="btn btn--secondary"&amp;gt;Cancel&amp;lt;/button&amp;gt;
-     &amp;lt;button class="btn btn--primary"&amp;gt;Submit&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+     &amp;lt;button class="stacked-form__footer-item btn btn--secondary"&amp;gt;Cancel&amp;lt;/button&amp;gt;
+     &amp;lt;button class="stacked-form__footer-item btn btn--primary"&amp;gt;Submit&amp;lt;/button&amp;gt;
&lt;/span&gt;    &amp;lt;/div&amp;gt;
  &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CSS 如下：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stacked-form__footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.stacked-form__footer-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;&amp;amp;:last-child&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们在次级导航和标题栏也有同样的需求呢？该怎么办。&lt;/p&gt;

&lt;p&gt;在 &lt;code&gt;.stacked-form&lt;/code&gt; 组件之外，&lt;code&gt;.stacked-form__footer&lt;/code&gt; 没有复用的意义，我们要在标题栏组件中创建新的子组件吗?&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  &amp;lt;header class="header-bar"&amp;gt;
    &amp;lt;h2 class="header-bar__title"&amp;gt;New Product&amp;lt;/h2&amp;gt;
&lt;span class="gi"&gt;+   &amp;lt;div class="header-bar__actions"&amp;gt;
+     &amp;lt;button class="header-bar__action btn btn--secondary"&amp;gt;Cancel&amp;lt;/button&amp;gt;
+     &amp;lt;button class="header-bar__action btn btn--primary"&amp;gt;Save&amp;lt;/button&amp;gt;
+   &amp;lt;/div&amp;gt;
&lt;/span&gt;  &amp;lt;/header&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在创建新的 &lt;code&gt;.header-bar__actions&lt;/code&gt; 组件时做的事情跟创建 &lt;code&gt;.stacked-form__footer&lt;/code&gt; 组件时完全一样，仿佛回到了最初基于内容为样式类命名的时候面临的问题。&lt;/p&gt;

&lt;p&gt;解决问题的一种方式是创建一个全新的易复用的组件来满足组合使用的需求，比如创建一个 &lt;code&gt;.actions-list&lt;/code&gt; 组件：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.actions-list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.actions-list__item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;&amp;amp;:last-child&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;.actions-list&lt;/code&gt; 可以完全替换 &lt;code&gt;.stacked-form__footer&lt;/code&gt; 和 &lt;code&gt;.header-bar__actions&lt;/code&gt;。&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Stacked form --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Header bar --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New Product&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再考虑一下，如果这两个行为列表有稍微不同的表现呢，比如一个左对齐，一个右对齐，通过修饰符实现吗？其中一个使用 &lt;code&gt;.actions-list--left&lt;/code&gt;，另一个使用 &lt;code&gt;.action-list--right&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="阶段四：内容无涉的组件和工具类"&gt;阶段四：内容无涉的组件和工具类&lt;/h2&gt;
&lt;p&gt;不停提取可复用组件和添加修饰符实现组件之间微小差异性的方式让人筋疲力竭，当我们使用修饰符的时候，相当于仅仅是为了修改一个 CSS 属性就创建了一个全新的组件。 &lt;/p&gt;

&lt;p&gt;组件会有更多个，如果它们也需要区分左对齐和右对齐呢，要创建同样的修饰符吗？我们再次陷入到了提取相同特性的困境中，就像我们当初从 &lt;code&gt;.stacked-form__footer&lt;/code&gt; 和 &lt;code&gt;.header-bar__actions&lt;/code&gt; 中提取出 &lt;code&gt;.actions-list&lt;/code&gt; 一样。&lt;/p&gt;

&lt;p&gt;显然，我们更喜欢组合而不是无谓的重复。考虑一下，我们应该如何从组合的思想出发，解决行为列表不同对齐方式的实现呢？&lt;/p&gt;
&lt;h3 id="对齐工具类"&gt;对齐工具类&lt;/h3&gt;
&lt;p&gt;我们需要创建一个可复用的类，让它可以为组件提供期望的效果。这些类完全可以叫做 &lt;code&gt;.align-left&lt;/code&gt; 和 &lt;code&gt;.align-right&lt;/code&gt;，就像我们之前创建修饰符一样，它们的样式定义如下：&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.align-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.align-right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在可以通过组合来实现列表中按钮的不同对齐方式了！&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- our stacked form buttons left-aligned --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list align-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- ...and our header buttons right-aligned --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New Product&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list align-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"actions-list__item btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="不要害怕"&gt;不要害怕&lt;/h3&gt;
&lt;p&gt;如果在 HTML 中看到单词 “left” 和 “right” 会让你不舒服，请记住，目前为止我们已经在 UI 中使用了以视觉模式命名的组件。&lt;code&gt;.stacked-form&lt;/code&gt; 并没有比 &lt;code&gt;.align-right&lt;/code&gt; 更加 “语义化”，它们都是根据它们如何影响 HTML 的表示而命名的，并且我们也确实使用它们实现特定的样式表现需求。&lt;/p&gt;

&lt;p&gt;这就是 HTML 依赖 CSS，如果我们想将表单从 &lt;code&gt;.stacked-form&lt;/code&gt; 改为 &lt;code&gt;.horizontal-form&lt;/code&gt;，需要修改的地方是 HTML，而不是 CSS。&lt;/p&gt;
&lt;h3 id="删除无用的抽象"&gt;删除无用的抽象&lt;/h3&gt;
&lt;p&gt;有趣的是，我们先前创建的 &lt;code&gt;.actions-list&lt;/code&gt; 组件已经基本没用了，它之前提供的功能就是将其中的内容右对齐。现在完全可以把它删掉：&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- .actions-list {
-   text-align: right;
- }
&lt;/span&gt;  .actions-list__item {
    margin-right: 1rem;
    &amp;amp;:last-child {
      margin-right: 0;
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但删掉之后，&lt;code&gt;.actions-list__item&lt;/code&gt; 成为了孤儿类，显得很奇怪。是否有更好的方式可以解决我们创建它们所有解决的问题呢？&lt;/p&gt;

&lt;p&gt;回过头来想，创建它们的目的就是为了在两个按钮之间添加一点间距。&lt;code&gt;.actions-list&lt;/code&gt; 在当时看来确实是不错的抽象，具备一定的通用性且复用性良好，但说实话，如果其它情境中也需要实现类似的功能呢，即在列表项之间添加间距，而这些列表项可能不是 "actions"。&lt;/p&gt;

&lt;p&gt;要让它具备更进一步的复用性，或许可以叫做 &lt;code&gt;.spaced-horizontal-list&lt;/code&gt;? 但我们已经把这个组件删除了，实际上只有它的后代需要样式。&lt;/p&gt;
&lt;h3 id="间距类"&gt;间距类&lt;/h3&gt;
&lt;p&gt;如果只有后代需要添加样式的话，或许直接为它们指定样式会比通过按组使用伪类添加更加简单直接。在两个元素之间添加间距复用性最高的表述应该是 “该元素附近应该有一些间距”，这将是我们要创建的类的特征。&lt;/p&gt;

&lt;p&gt;我们已经创建过 &lt;code&gt;.align-left&lt;/code&gt; 和 &lt;code&gt;.align-right&lt;/code&gt; 这样的类了，或许我们也可以创建只添加右边距的功能类 🤔&lt;/p&gt;

&lt;p&gt;操作起来，创建一个 &lt;code&gt;.mar-r-sm&lt;/code&gt;，它可以在一个目标右边添加一些边距：&lt;/p&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- .actions-list__item {
-   margin-right: 1rem;
-   &amp;amp;:last-child {
-     margin-right: 0;
-   }
- }
&lt;/span&gt;&lt;span class="gi"&gt;+ .mar-r-sm {
+   margin-right: 1rem;
+ }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后我们的表单和标题栏是这个样子的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Stacked form --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"stacked-form__section align-left"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--secondary mar-r-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Header bar --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header-bar__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New Product&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"align-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--secondary mar-r-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn--primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;.actions-list&lt;/code&gt; 现在已经无影无踪了，我们的 CSS 文件也更小了，创建的类也具有了前所未有的高复用性。&lt;/p&gt;
&lt;h2 id="阶段五：工具类优先的 CSS"&gt;阶段五：工具类优先的 CSS&lt;/h2&gt;
&lt;p&gt;Get 到这个点不久之后，我便创建出一整套的常用工具类，用以解决常见的视觉呈现需求：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text sizes, colors, and weights&lt;/li&gt;
&lt;li&gt;Border colors, widths, and positions&lt;/li&gt;
&lt;li&gt;Background colors&lt;/li&gt;
&lt;li&gt;Flexbox utilities&lt;/li&gt;
&lt;li&gt;Padding and margin helpers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;令人惊奇的是，在不了解它的情况下，您可以构建全新的 UI 组件，而无需编写任何新的 CSS。比如这个 “产品卡片” 组件：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/4323180/29088813-62ff9b86-7c48-11e7-9854-9c966ffbf9c4.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;它的 HTML 是这样的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card rounded shadow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block fit"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-3 px-4 border-b border-dark-soft flex-spaced flex-y-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-ellipsis mr-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-lg text-medium"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                Test-Driven Laravel
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"link-softer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            @icon('link')
        &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex text-lg text-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-2 px-4 border-r border-dark-soft"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            @icon('currency-dollar', 'icon-sm text-dark-softest mr-4')
            &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;$3,475&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-2 px-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            @icon('user', 'icon-sm text-dark-softest mr-4')
            &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;25&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上用到的样式类可能在一开始会让你感到厌烦，让我们不妨想一下，如果要让它成为一个真正的 CSS 组件而不是由工具类拼凑而成，该怎么做呢？&lt;/p&gt;

&lt;p&gt;我们不想根据内容来为样式类命名，这样会让我们的组件局限于单一的情景，下面这样如何？&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.image-card-with-a-full-width-section-and-a-split-section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;太荒谬了 😂 按照之前讨论过的内容，我们可能希望它由一些较小的组件组成。这些组件会是什么样子呢？&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;它可能寄宿在一个卡片之上。并不是所有的卡片都具有阴影，所以我们需要通过修饰符实现（&lt;code&gt;.card--shadowed&lt;/code&gt;），或者创建一个 &lt;code&gt;.shadow&lt;/code&gt; 的工具类，它可以应用在任何一个目标上，显然后一种方式复用性更强。 &lt;/li&gt;
&lt;li&gt;同样的，并不是所有的卡片都是圆角的，所以我们需要区分开来，使用修饰符或者工具类，显然后一种更优雅，即定义一个 &lt;code&gt;rounded&lt;/code&gt; 工具类。&lt;/li&gt;
&lt;li&gt;上方的图片呢？使用 &lt;code&gt;.img--fitted&lt;/code&gt; 让它撑满卡片吗？网站中或许还有其它地方需要撑满父元素，它们可能并不是图片，这样的话，将它叫做 &lt;code&gt;.fit&lt;/code&gt; 会更好一些！&lt;/li&gt;
&lt;li&gt;……你可以看出来我在干什么。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;如果你对可复用性的关注度足够高，将组件类逐步拆分为工具类就是很自然的选择。&lt;/p&gt;
&lt;h3 id="强制一致性"&gt;强制一致性&lt;/h3&gt;
&lt;p&gt;使用小的、可组合的工具类的一个好处是，团队中的成员可以从一个固定的集合中取值。&lt;/p&gt;

&lt;p&gt;回想一下你平时会如何将样式的改进意见传递给你的同事，“这段文本需要更暗一点”，“这里的字号需要更小一点”……看起来像是正确的方式，因为你使用了相对颜色或者相对字号，而不是随意指定的值。&lt;/p&gt;

&lt;p&gt;但经常发生的情况是，你想让某个组件的文本暗 10%，而你的同事却让它暗了 12%，最终你会发现在你们的样式表中会有 &lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2F51ce5f8445dece60ef49d6b7dcc4e538%2Fraw%2Fe5349db6f1ccbd175f7dd7c581e061b4d49c1ff4%2Fgitlab.css" rel="nofollow" target="_blank" title=""&gt;402 中独特的文本颜色&lt;/a&gt; 🤣 这种情况会发生在每个通过编写新的 CSS 设置样式的代码库中：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2F51ce5f8445dece60ef49d6b7dcc4e538%2Fraw%2Fe5349db6f1ccbd175f7dd7c581e061b4d49c1ff4%2Fgitlab.css" rel="nofollow" target="_blank" title=""&gt;GitLab&lt;/a&gt;： 402 种文本颜色，239 种背景颜色，59 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2F51ce5f8445dece60ef49d6b7dcc4e538%2Fraw%2Fd560c4dadb9e85197d6e33ac0cb55c2435c45c65%2Fbuffer.css" rel="nofollow" target="_blank" title=""&gt;Buffer&lt;/a&gt;： 124 种文本颜色，86 种背景颜色，54 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2F51ce5f8445dece60ef49d6b7dcc4e538%2Fraw%2F1a12773f211891f4199d03c59bde97e814e044f0%2Fhelpscout.css" rel="nofollow" target="_blank" title=""&gt;HelpScout&lt;/a&gt;： 198 种文本颜色，133 种背景颜色，67 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fstatic-1.gumroad.com%2Fres%2Fgumroad%2Fassets%2Fapplication-f7ade6b83ca73dcd02cc9762068df43c4ea824e0c94babde8e4c9ecfc2653acb.css" rel="nofollow" target="_blank" title=""&gt;Gumroad&lt;/a&gt;： 91 种文本颜色，28 种背景颜色，48 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2Fca146a9dbe99754159c07c6599ea45d2%2Fraw%2F90d64ed31422e9c4fc8b08b035b47ea048275ad1%2Fstripe.css" rel="nofollow" target="_blank" title=""&gt;Stripe&lt;/a&gt;： 189 种文本颜色，90 种背景颜色，35 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?url=http%3A%2F%2Fgithub.com&amp;amp;name=GitHub" rel="nofollow" target="_blank" title=""&gt;GitHub&lt;/a&gt;： 163 种文本颜色，147 种背景颜色，56 种字号&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://cssstats.com/stats?link=https%3A%2F%2Fgist.githubusercontent.com%2Fadamwathan%2F4ca6aafc50342ad87a98970204053b71%2Fraw%2Fbb42e4fda01d9933afff7225b33e77dbfbd559ff%2Fconvertkit.css" rel="nofollow" target="_blank" title=""&gt;ConvertKit&lt;/a&gt;： 128 种文本颜色，124 种背景颜色，70 种字号&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这是因为每次写新的 CSS 的时候几乎都是从零开始，不可避免地会出现很多在设计体系之外的任意值。&lt;/p&gt;

&lt;p&gt;当然可以尝试使用变量或者混入来强制一致性，但是每一行新的 CSS 都有可能带来新的复杂性，不断添加更多的 CSS 从一开始就不会让你的 CSS 更加简单。&lt;/p&gt;

&lt;p&gt;但反过来，如果添加新样式的方式仅仅是应用已存在的样式类，所有从零开始会带来的意外都能够解决掉啦。想要让暗色文本更柔一点，只需要添加 &lt;code&gt;.text-dark-soft&lt;/code&gt; 类，想要让字号更小一点，使用 &lt;code&gt;.text-sm&lt;/code&gt; 类即可。当每个人都从一组预设中选择样式的时候，项目中 CSS 的大小就不会随项目增长而继续膨胀，而我们也就获得了天然的一致性。&lt;/p&gt;
&lt;h3 id="你仍然需要创建组件"&gt;你仍然需要创建组件&lt;/h3&gt;
&lt;p&gt;我的立场和一些真正固执的 “Functional CSS” 的倡导者还有区别，我并不认为所有的东西都只应该使用工具类构建。&lt;/p&gt;

&lt;p&gt;如果你查看一些流行的基于工具类的框架，像是 &lt;a href="http://tachyons.io/" rel="nofollow" target="_blank" title=""&gt;Tachyons&lt;/a&gt;（这是一个相当优秀的项目），它们的按钮都是用最基本的工具类实现的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"f6 br3 ph3 pv2 white bg-purple hover-bg-light-purple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Button Text
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让我们来分解一下上面的示例：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;f6&lt;/code&gt;： 在字体大小梯度中使用第六种（在 Tachyons 中为 .875rem）&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;br3&lt;/code&gt;： 在圆角大小梯度中使用第三种（.5rem）&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ph3&lt;/code&gt;： 水平内边距使用边距梯度中的第三种（1rem）&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pv2&lt;/code&gt;： 垂直内边距使用边距梯度中的第二种（.5rem）&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;white&lt;/code&gt;： 使用白色文本&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bg-purple&lt;/code&gt;： 使用紫色背景&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hover-bg-light-purple&lt;/code&gt;： 鼠标悬浮时的背景颜色是淡紫色&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果你需要多个相同的按钮，Tachyons 推荐的做法是使用模板抽象组件而不是通过 CSS。以 &lt;a href="https://vuejs.org/" rel="nofollow" target="_blank" title=""&gt;Vue.js&lt;/a&gt; 为例，使用起来是这个样子的：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ui-button&lt;/span&gt; &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"purple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/ui-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个组件的定义如下：&lt;/p&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"f6 br3 ph3 pv2"&lt;/span&gt; &lt;span class="na"&gt;:class=&lt;/span&gt;&lt;span class="s"&gt;"colorClasses"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;colorClasses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;purple&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;white bg-purple hover-bg-light-purple&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;lightGray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mid-gray bg-light-gray hover-bg-light-silver&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
      &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于大多数项目来说，这是一种非常好的方式，但我坚持认为，在很多用例中，创建 CSS 组件比创建模板组件更为实用。还是以我在做的项目为例，将七个工具类组合在一起创建一个新的 &lt;code&gt;.btn-purple&lt;/code&gt; 样式类要比将其抽象为一个单独的组件方便地多。&lt;/p&gt;
&lt;h3 id="但是优先使用工具类构建它们"&gt;但是优先使用工具类构建它们&lt;/h3&gt;
&lt;p&gt;之所以将这种方式称作工具类优先的 CSS，是因为我&lt;strong&gt;尽可能使用工具类搭建我想要的一切，并且只在存在重复模式的时候进行提取和抽象！&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果你使用  &lt;a href="http://lesscss.org/" rel="nofollow" target="_blank" title=""&gt;Less&lt;/a&gt; 作为预处理器，你可以使用 mixin 来组合已存在的类。这意味着创建 &lt;code&gt;.btn-purple&lt;/code&gt; 组件类只需要移动几下光标而已 😋&lt;/p&gt;

&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/4323180/29084097-f16c97c6-7c38-11e7-92dd-d20c1364d869.gif" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;遗憾的是你并不能在 Sass 或者 Stylus 中执行这样的操作，在这两种处理器中你需要为每个工具类单独建立 mixin。&lt;/p&gt;

&lt;p&gt;当然了，并不是组件中的所有声明都需要使用已有工具类。像鼠标悬浮在父元素时改变子元素的样式这种复杂的交互，单单依赖工具类是难以实现的，我的观点是，根据你自己的判断选择对你而言最简单的方式。&lt;/p&gt;
&lt;h3 id="不过早做抽象"&gt;不过早做抽象&lt;/h3&gt;
&lt;p&gt;组件优先的编写 CSS 的方式意味着你通常需要事先创建好可能有必要的组件，即使它们可能永远也不会用到。这种过早的抽象是样式表膨胀和复杂度爆炸的源头。&lt;/p&gt;

&lt;p&gt;以导航栏为例，你会经常用到它吗？显然不是，最起码在我的项目中，这通常只会做一次，写在主布局文件中。如果你采用组件类优先的，仅在出现难以忍受的重复时提取组件，导航组件也许永远都不会出现。相反，它会是以下这样，并且可预见的未来都不会发生变动：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-brand py-4 flex-spaced"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!-- Logo goes here --&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Menu items go here --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并没有什么东西是值得提取的。&lt;/p&gt;
&lt;h2 id="这不就是内联样式吗？"&gt;这不就是内联样式吗？&lt;/h2&gt;
&lt;p&gt;这种方式很容易被理解为与内联样式无异，因为我们在做的事情就像是直接将需要的属性添加到标记中，但在我的实践中，二者是&lt;strong&gt;完全不同&lt;/strong&gt;的。&lt;/p&gt;

&lt;p&gt;在内联样式中，属性的取值没有任何的限制。一个标签的字号可能是 &lt;code&gt;font-size: 14px&lt;/code&gt;，另一个有可能是 &lt;code&gt;font-size: 13px&lt;/code&gt;，还有 &lt;code&gt;font-size: .9em&lt;/code&gt;、&lt;code&gt;font-size: .85rem&lt;/code&gt;……这和为每一个新组件书写新的 CSS 一样，面临着从零开始的 “空白画布” 问题。&lt;/p&gt;

&lt;p&gt;而组件类强制你进行选择：字号是 &lt;code&gt;text-sm&lt;/code&gt; 还是 &lt;code&gt;text-xs&lt;/code&gt;？该使用 &lt;code&gt;py-3&lt;/code&gt; 还是 &lt;code&gt;py-4&lt;/code&gt;？想要 &lt;code&gt;text-dark-soft&lt;/code&gt; 还是 &lt;code&gt;text-dark-faint&lt;/code&gt;？你必须从一个预设列表中选择其中一项，而不是信手拈来一个任意值。你最终只会有 10 - 12 种颜色，而不是 380 种。&lt;/p&gt;

&lt;p&gt;我的经验是，&lt;strong&gt;基于工具类优先的方式比基于组件优先的方式更容易维护一致性程度高的设计体系&lt;/strong&gt;，虽然它一开始并不那么直观。&lt;/p&gt;
&lt;h2 id="从哪里开始"&gt;从哪里开始&lt;/h2&gt;
&lt;p&gt;如果你对这种方式感兴趣，以下是一些值得尝试的框架：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://tachyons.io/" rel="nofollow" target="_blank" title=""&gt;Tachyons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://basscss.com/" rel="nofollow" target="_blank" title=""&gt;Basscss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://buildwithbeard.com/" rel="nofollow" target="_blank" title=""&gt;Beard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://turretcss.com/" rel="nofollow" target="_blank" title=""&gt;turretcss&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最近，我也在准备我的开源 PostCSS 框架，它叫做 &lt;a href="https://tailwindcss.com/" rel="nofollow" target="_blank" title=""&gt;Tailwind CSS&lt;/a&gt;，就是围绕工具类优先的想法设计的，只在必要的时候提取重复模式。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://tailwindcss.com/img/twitter-large-card.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;如果你对它感兴趣，请前往 Tailwind CSS 的&lt;a href="https://tailwindcss.com/" rel="nofollow" target="_blank" title=""&gt;官网&lt;/a&gt;，并上手尝试一下！&lt;/p&gt;

&lt;p&gt;&lt;img src="/uploads/photo/2020/5cf44a3c-54fd-4472-9944-b4a94c190030.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>kongxiangyan</author>
      <pubDate>Sun, 05 Jan 2020 17:49:19 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/171</link>
      <guid>https://beta.w2solo.com/topics/171</guid>
    </item>
    <item>
      <title>关于想象力的讨论</title>
      <description>&lt;p&gt;2020年1月3日，一群独立开发者们发起了一场关于想象力的讨论，归纳一下，基本是围绕技术本质和应用生态展开。&lt;/p&gt;

&lt;p&gt;有一些内容我还不是很理解，单就我稍微有点想法的部分记录一下，也大概分为&lt;strong&gt;应用生态&lt;/strong&gt;和&lt;strong&gt;技术本质&lt;/strong&gt;两部分。&lt;/p&gt;
&lt;h2 id="致谢"&gt;致谢&lt;/h2&gt;
&lt;p&gt;我所认识的大多数开发者都是最可爱的人，感谢诸位前辈带来的思考，感谢你们在做这样美好的事情。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;奥特饭 dogedoge.com 一定要去尝试的一款搜索引擎&lt;/li&gt;
&lt;li&gt;cmlance indiehackers.net 就算不说话也能学到很多东西的独立开发者社区&lt;/li&gt;
&lt;li&gt;无登 苦口婆心适合当老师的大哥！&lt;/li&gt;
&lt;li&gt;潇湘 半吊子前端&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="应用生态"&gt;应用生态&lt;/h2&gt;
&lt;p&gt;如今我们讨论应用生态，大抵涉及到 Web、App、MiniApp 三种（IoT 设备上的应用也算，但不在今天的讨论范围中）。相较而言，前两者比 MiniApp 更加基础，MiniApp 是二者混合的产物，兼具 App 的体验和 Web 的便捷性。不考虑技术层面，就使用意义来说， Web 作为重内容的载体，其核心能力是连接信息，进而连接人，App 作为重功能的载体，其核心能力是垂直拓展人的行为。Web 和 App 之间没有绝对的优劣，各有其存在的意义和特定的使用情景，在实际的应用中，两者也是互通有无，互相增强。比如，Web 逐步发展到 SPA、PWA……，App 内置 Web、开放 SDK、建立 MiniApp。从生态发展的角度讲，我认可奥特饭的观点，&lt;strong&gt;MiniApp 的兴起，本质上就是超级 App 巩固自己应用生态的一种方式而已&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;早先，App 通过 SDK（的方式）开放能力给 Web 来发展应用生态，&lt;strong&gt;开放能力的同时也是限制能力&lt;/strong&gt;，App 通过限制能力的方式来保护应用生态。如果你曾经有过开发经历的话会知道，这里所说的能力不单单指 App 的基础设施，还包括 Web 原生能力的阉割，这是想要进入生态的开发者的第一道坎！但起码，对于我们这些一无所有的人来说，开放是件好事儿，于是我们低头了。结果是，应用生态壮大起来，开发者们前赴后继为大厦添砖加瓦，同时也从庞大的蛋糕中拿走我们认为的其中一小块儿，回头看其实大部分开发者拿到的不过是完成蛋糕的边角料而已。&lt;/p&gt;

&lt;p&gt;然后，他们推出了小程序，美其名曰解决了入口的问题，利益驱使下，我们再次冲到了一线，同时对他们的慷慨大加赞扬，却很少去反思背后的逻辑。刚开始，他们限制 Web 的活动范围，而现在，Web 的原生能力已经被束住手脚直接端上案板，对于内置 Web 的限制，则更加剧烈。超级应用诞生了，这次，我们需要学习小程序的 DSL、熟悉新的能力和接口，随着小程序的壮大，加上没有统一的标准，我们的开发精力被牵制地所剩无几，国内传统 Web 应用的关注者变得越来越少，&lt;strong&gt;当初那种分享和传播的精神仿佛已经淡化了&lt;/strong&gt;。在新的大厦中，大部分开发者拿到的，仍然是蛋糕的边角料。&lt;/p&gt;

&lt;p&gt;小程序的出现无疑是技术的进步，我们也不能只看到代价而忽略它带来的价值。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;最大的价值是开发的门槛极大地降低了，现在是个人就能开发并上线自己的小程序，拥有 “自己的” 用户。&lt;/li&gt;
&lt;li&gt;超级应用对于生态拥有了更大的控制权，也让我们能够更方便地触及到更多的基础设施和技术能力。&lt;/li&gt;
&lt;li&gt;用户的体验提升了？此处划个问号，的确，应用的能力更多元了、应用的获取更加方便了，但应用的质量呢，真的提升了吗？如果没有这些限制，用户又会获得怎样的体验，我们无法比较。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我&lt;strong&gt;无意谴责&lt;/strong&gt;超级应用是多么无良，事实上我完全没有这个意思，同样作为一无所有的开发者，我自认为从中获益良多。四年前我想上线自己的网站应用，技术和基础设施是一座不可逾越的大山，而现在，我几乎弹指间就能将自己的想法落地并发布上线，个人能力的提升是一方面，平台的发展和生态的进步也发挥了至关重要的推力。&lt;/p&gt;

&lt;p&gt;开放是件好事，这是发展的必然趋势，不会回头，平台方在尽力做维护生态的事情，也没有错。很多时候我们觉得他们限制了我们的能力，总觉得自己的思路在所有人之前，我不敢肯定这种状态，我们之中的很多人，对于生态完全没有哪怕只是一点点的感恩和反馈，同样像奥特饭所说的，开发者的心智还不到位。不妨在索取之前，先问问自己付出了什么，开放可不是无条件的开放，作为生态的一份子，我们都是要负起维护生态的责任的，而不是两眼尽是利益、行事不计后果。&lt;/p&gt;

&lt;p&gt;另外，我也反对开发者们潜意识里将自己的作品当作超级应用的附属，流量和用户它是客观存在的，不属于哪个特定应用，只不过是，超级应用将这些资源开放给我们，让我们可以触达这些价值，为这些用户提供服务，从而达到巩固和维护生态的目的。但凡有这样的认知，最初的目标就不会是索取价值，而是尽可能好好利用平台提供的资源，为用户提供最好的服务，在这个过程中，&lt;strong&gt;真正大的蛋糕是用户对于我们的认知，利益才是边角料&lt;/strong&gt;，我想无登大哥所表述的 “&lt;strong&gt;品牌&lt;/strong&gt;” 指的也是如此。“&lt;strong&gt;再小的个体，也有自己的品牌&lt;/strong&gt;”，这是微信公众号推出伊始就确定的 Slogan，重新思考这句话或许能有新的启发。&lt;/p&gt;

&lt;p&gt;总结，平台方和开发者和用户，都想要一个更加开放、更加共享、更加先进的社区，这个目标的实现少不了任何一方的努力，平台方绝不吝啬，开发者群体也没有想象中的那么弱小和高尚，为用户服务、为共同目标添砖加瓦，大多数用户也不是你们自认为的那么无辜，不要自欺欺人。完善、开拓自己的认知和心智，而不是只盯着利益，才是共赢正确的方式。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;我想我发表这样的观点是有立场、站得住脚的，我正在身体力行为这个目标做贡献，相关内容请了解 &lt;a href="https://mp.weixin.qq.com/s?__biz=MzIyODcyNjQ4NA==&amp;amp;mid=2247483658&amp;amp;idx=1&amp;amp;sn=1321880380f99b67f9b848b66111cc25&amp;amp;chksm=e84cc2b1df3b4ba7827b059dc4887d1a4148dae429f381fc8c253e98f455dd6ce4a54db79d24&amp;amp;token=172842095&amp;amp;lang=zh_CN#rd" rel="nofollow" target="_blank" title=""&gt;Thoughts Lab&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="技术本质"&gt;技术本质&lt;/h2&gt;
&lt;p&gt;技术本质这个主题远比应用生态要深入地多，讨论起来也更加形而上。&lt;/p&gt;

&lt;p&gt;无登和潇湘认为程序是新维度的信息，可以与文字、图片、音频、视频并列，拥有巨大的想象力，并以微信聊天内置地图应用、发票应用为程序例证。我不认可这种字面上的划分方式，但我能够理解其中包含的程序应当具有的价值远未体现出来的观点。地图和发票均是线下到线上的转移，同时程序将交互能力赋予了这些应用，这是程序最 “平庸” 的能力，只不过由于个别开发者个人水平和价值观的原因，导致 “程序” 整体质量低下，换一个角度想一下，这些功能同样都有平台原生版和第三方版本，明明用到的基础能力都一样，为什么原生版体验比第三方版本的体验明显好一大截，显然开放的入口绝对不是主要的原因。&lt;/p&gt;

&lt;p&gt;无登强调的小程序的想象力，也不完全是上面提到的这种 “平庸” 的能力，而是小程序作为区别于短信、彩信、图片、短视频之外的一种新的载体形式，除了将传统信息形式融合传递外，还将更多的社会性、物质性的东西包含在内，包括人际关系、支付信息、人和物的联系等，我同意这也是小程序的爆发点所在。更深层次是指基于平台基础能力和客观上社交关系的实现和开发的新应用场景的想象力，举几个不那么精确的例子，“抽奖助手” 和出现过的 “七度人脉” 这种，我非常认可这种看法！&lt;strong&gt;基础能力和应用场景在不断扩展，我们对于关系的探索还远远不够。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在我看来，只有与人类感官直接直接对应的信息单元才算是 “信息形态”，目前有画面和声音。文字和图片只不过是画面的表现形式而已，老早的时候我们通过符号和文字将视觉信息记录下来，随着技术的发展逐渐有了图片，文字之所以没有消失的原因是人类将其和语言结合起来，并赋予其意义。我们交流的基础是意义互通，语言和文字只不过是载体而已。广播大大扩展了我们听觉感官的能力，就像文字、符号、图片曾经补偿我们视觉的跨时间体验一样。&lt;/p&gt;

&lt;p&gt;在应用领域，许多 App 对我们的生活造成了翻天覆地的变化，而真正作用于人类社会进步的意义，大都是无心插柳而已。IM 真是因为它为我们提供了即时通信能力而改变了我们的生活吗？显然不是，真正带来改变的是让我们更方便地分离思考和行为，让你近乎无感地、顺其自然地将活生生的自己包裹起来，并苦心孤诣的经营着一副人前的样子，最让我们割舍不下的，不正是这种感觉吗？短视频的兴起主要得益于技术的进步，我们苦 IM 久矣，短视频音形具备的特点让它能够弥补我们的想象力空间，同时也为我们提供了更大的想象空间，就像一个球，你补的越大，能够接触到的外部空间就越大。&lt;/p&gt;

&lt;p&gt;也许，技术的发展还能够为我们带来更多的新奇体验，比如&lt;strong&gt;触觉互联网&lt;/strong&gt;，这是一场建立在感官上的革命，当它真正兴起的时候，按摩疗养都会成为新的红海，身体将是每个人最大的财富。也许 10 年？也许 20 年？谁知道呢。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;技术是不会倒退的，正是基于这样的考虑，我始终认为，一片常常被我们忽略的应用创新的增长空间在于对人性需求的弥补。&lt;/strong&gt;一方面技术曾经让它四分五裂，另一方面我认为技术也一定可以让它完整如初。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;也许当初也并尽然就是那般美好，但 Who cares，我向往的是美好的部分。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="Thoughts"&gt;Thoughts&lt;/h2&gt;
&lt;p&gt;希望自己永远知道自己想要什么。&lt;/p&gt;

&lt;p&gt;希望自己永远坚定要去往的方向。&lt;/p&gt;

&lt;p&gt;And，希望自己永远善良。&lt;/p&gt;

&lt;p&gt;共勉。&lt;/p&gt;

&lt;p&gt;另外，欢迎大家关注我的公众号噢 ~
&lt;img src="https://img.way2solo.com/uploads/photo/2020/750c6287-3f06-4a62-b92f-3b1698d7553d.png" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>kongxiangyan</author>
      <pubDate>Fri, 03 Jan 2020 17:54:23 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/169</link>
      <guid>https://beta.w2solo.com/topics/169</guid>
    </item>
  </channel>
</rss>
