理解函数式 CSS

译者:ZenDay
链接:http://www.zcfy.cc/article/1109
原文:https://marcelosomers.com/writing/rationalizing-functional-css/

发现和讨论函数式 CSS 的优点

函数式 CSS 的概念似乎是我这辈子听过的最疯狂的东西了。“我怎么会用这种玩意?CSS 已经十分出色了。”我这样跟我自己说。

如果你从来没有听说过,函数式 CSS (或者说原子 CSS/通用类/不可变的 CSS —— 我可以一直说下去。这里没有一个好的名字)是一种不去在我的 CSS 中编写庞大臃肿的组件,而去写能被组装到 HTML 中大型组件的小型的,单一属性,不可变的类的概念。

你的 CSS 可能看起来像这样:

.p1 { padding: 0.5rem; }
.flex { display: flex }
.red { color: red; } 

然后在你的 HTML 中被组装起来:

<div class="flex p1 red">
  Hi, I'm a flexbox div with 1 unit of padding and red text!
</div>

简直是疯了,对吧?

我热爱编写真的灵活,强大的 CSS 类。我主张它因为“开发者开销的降低”。我的目标曾是一个开发者可以给一个元素加一个单独类然后它会为他们自动地做好所有事情。基本上跟函数式 CSS 完全相反。

然后我拜读了 Adam Morse 的史诗巨作,CSS 和可扩展性。Adam 带你经历了一段非常丰富的旅行,所以我推荐流出 20 分钟时间来跟随他的思考阅读,但如果我必须总结一下,那就是下面的这段:

在[大型]模型中,你将永远不会停止编写 css。重构 css 是困难而且耗费时间的。删除不必要的 css 是困难而且耗费时间的。而且往往不止于不——这不是人们都热衷去做的。所以发生了什么?人们开始写越来越多的 css。

🤔

好吧,Adam。我认输了。你是对的。开始一个新项目以及编写所有这些美丽的架构良好的 CSS 组件很有趣,但事实在于,我不会永远都呆在这个状态中,并且在大型模型中,团队将永远不会停止编写 CSS

如果你曾经走进过一个真正有优秀架构的 CSS 代码库的话请举起你的手。

我也没有。

通常来说这并不是因为代码库开了一个坏头。是因为作为 CSS 的作者,我们被教导为了解决问题要抛出更多代码。

就像 Adam,我已经碰触到了我职业生涯中的这个点:

我对于我能使用 css 做什么已经不太感兴趣。我对于我能帮助团队里的人们使用 css 来做什么更感兴趣。

Basscss 和 Adam 自己的 Tachyons 是实验的一个优秀的起点。我在尝试过之后被说服了,而且我有机会通过使用这个编写 CSS 的方法来为一个新的客户项目开球。

三个月里把函数式方法应用在 CSS 架构中之后,我已经上瘾了。我曾经使用老整体方法的时代,它变成了不断地在不同文件里跳来跳去的乏味挑战。我想我已经信服了,但是我仍然尝试去合理化当我的函数式代码库增长和发展时的可扩展性问题。

我希望能收到任何关于我考虑到或是没考虑的问题的反馈

益处

速度

我的天啊,我能够快速工作了。我过去常常说我不能“在代码中设计”并且更喜欢在像 Sketch 这样的工具中开始任何白板设计。我开玩笑说这感觉起来就像我大脑中的两个不同方面,只是不会相互协调。

在使用函数式 CSS 的过程中我意识到是情境的切换扼杀了我的创造力。 I'd have a great design idea,我会有美妙的设计念头,但是紧接着我不得不切换到我的 CSS 文件中然后从草稿开始构建一个组件 —— 命名,思考盒子模型的影响,DOM 结构,最佳架构实践等等。这就像我的创造力以一百英里每小时的速度撞到墙上。

相反,我浏览 DOM,编写 HTML 而且轻而易举地快速赋予每一个元素样式。使用 Basscss 加上一些自定义 CSS 类用于我的主题色,我可以在一个小时内构建一个经得起时间考验的项目主页。

仅此感觉就足够让我使用这种方法。这十分令人上瘾,我都不知道我是否能够回去了。 Jon Gold 是对的:

"最好的 CSS 就是尽可能少的 CSS。"

— gold (@jongold) April 22, 2016

从设计的观点来说,函数式 CSS 把你从在设计的时候不得不作代码抉择中解放出来。抉择已经做出,而你只需要简单地混合和匹配来以你在 Sketch 中使用形状、颜色和间距的相同方式实现你想要的样式。

可转移性

在这些天里我工作的大多数项目上,我们的设计和开发团队已经选定了设计提供 HTML/CSS 原型和开发团队把它移植到真实环境中的想法。

这些项目的效率收益是巨大的。

一个代码原型给了我们的设计师实践来使用户界面更完美而不会因为不得不学习在高级 JS 框架例如 React 或者 Angular 中工作而头疼。

我们在这个方法中发现的问题是 HTML 需求上的一点不同:类似于需求一个会包裹在一个标签中的组件或者指令会快速破坏掉你的 CSS 级联。

在过去,这意味着维护一个重载的应用程序特定的集合,会随着时间的推移出现越来越多的 bug (以及坏的 CSS 会被编写出来)。

相反,细微的调整,例如 margin,能通过在你的 HTML 一个单独的类变化来实现。 It allows you to fix bugs without writing any additional CSS.这允许你不用编写任何额外 CSS 来修正 bug。我甚至不能告诉你这种感觉是多么的美妙。写更多的代码来修正 bug 是一种错误地修复你的 CSS 的方法。

停止做出(毫无意义的)选择

Basscss 提供了一套标准的间距和大小的通用工具。消除选择实际上就是解放。通过只提供 8px, 16px, 24px 等的间距,你只要选择大/中/小就可以跟它一起摇摆了。

我过去以为这会带走我所有的创造力,但是它只是使我作为设计师的生活更加愉快。我能够专注于正确的问题上。

坏处

在进入关于函数式 CSS 问题之前,我想要变得清晰 —— 这一点上,这些都是问题而不是批评。我确信那些比我聪明的多的人们已经找出了这些问题的解决方案(或者理由)。

我很想听听其他人是如何解决这些问题的。

失去级联

将组装我们样式代码的责任转移到 HTML 上意味着我们失去了所有级联的好处。当你第一次创建一个组件的时候这是绝妙的,但是为现存的系统更新样式就会变成搜索和替代以及其他快捷键的一团糟。

一个更新在一个文件一些相近样式的简单方法是使用多个光标在 Sublime Text 和 Atom 中,选择一个字符串然后敲击 ⌘-D (在 Mac 上) 会选择这个字符串的下一个实例。

但是这假定了你以相同的顺序放置通用类来创建多个相同的“组件”,尤其是在跨越多个页面做搜索和替代的时候。否则,没有一个简单的方法来跨越你的整个页面搜索以寻找类似组件实现的位置。

这可能是我关于在大型应用中应用函数式 CSS 的唯一的最大顾虑。想像一下一个标准的“盒子”组件由 7-10 个通用类组成。如果你想要改变所有盒子的字体大小,你需要跨越你的应用来寻找所有实例而且手动地去更新他们每一个的样式。

这给错误留下了很大的空间。

组件的可重用性

使用了函数式 CSS,创建“组件”就是简单地把一堆类放在一起捣碎。重用组件要求你在不同的地方再次使用相同的类。

再次强调:给错误留下了很大的空间。

这里长期的解决方案可能是实现一个模式库来编档组件以及提供简单的代码片段复制和粘贴。更胜一筹的是,通过文档,你轻易的提供了需要时的“选项”,通过描述可以混合和匹配的类的准确类型来实现组件的变化。例如,可能一个卡片可能有不同的顶部颜色,可以轻易地通过使用 bg-color 类切换。

结合之前有关失去级联,长期可重用性和更新的能力的问题就是我在使用函数式 CSS 工作时遇到的主要挑战。

如果你使用组件工作,一个可能的修复方法会使给每一个组件添加一个命名类。这会是描述性的因此你实际上不会应用任何 CSS 在这个类上,但是这会用于贯穿你的代码库来寻找一个特定组件的实例。

<div class="box-component flex p2 bg-blue white h4 bold">
  .box-component 类没有赋予任何样式,它仅仅是一个搜索关键字用于寻找盒子组件用到的地方。
</div>

通用类易于实现,但是应该尽早考虑其长期可用性,可重用性以及在大型团队中更新的能力。

响应式

如果你的设计在断点处改变了太多的话,你的类字符串将会变得十分复杂。在早期,做一些像是 class="m2 md-m0" 这样的事情使中间断点之下有两个单位的 margin 和使中间断点之上margin 为 0 是非常好的。

但是在我的测试项目里有一个情况就是在移动端上把我的导航栏改变样式变成一个滑动菜单,然而它在桌面端是一个标准的水平列表。这很快就失去控制了:

<nav class="fixed top-0 right-0 bottom-0 left-0 z4 bg-red flex-start md-relative md-flex-auto md-min-width-0">

</nav> 

这仅仅是开端,更多的类会在以后出现用于定义颜色。当你的设计在断点之间有很大的变化,实现类可能是一个挑战(而你的类的顺序是另外一个问题 —— 我们之后会讨论一下)。

为了解决它,我们需要在早期建立一套有关如何处理响应式的标准 —— 例如命名约定,断点,以及标准化最小或者最大宽度。

管理状态

我在自己身上发现的一个普遍状况是默认情况下隐藏一个组件,然后点击了某个地方之后把它展示出来。我可能会写一个像这样的庞大 CSS 类:

.nav { display: none; }

.nav.is-open { display: block; }

在这里 JavaScript 会切换 .is-open 来展示我的导航栏。相反,我的 JavaScript 现在会切换一个通用类 .block 或者类似的类:

<nav class="hide block">
  .block 被 JavaScript 切换来展示这个元素。这样可读性也不太糟糕。
</nav>

为了示范,这个小组件并没有太复杂。 然而即使在这个例子中,你也必须保证 .block 覆盖 .hide 或者将 .hide 完全删除(记得把它切换回来)。在更复杂的组件里,位置和样式也会发生变化,这导致有大量通过 JavaScript 来切换的东西需要记住。

这不影响大局,但在 CSS 中制定你的组件以及只要切换一个单独的类来处理所有样式一定要更加简单。

标准的类顺序

任何多于一个开发者的项目都不得不设置一些关于类放置顺序的标准。否则你在类的列表中寻找被应用的类时会感觉十分费劲。我个人推荐 包含模式。但在源顺序之上,你的团队应该决定所有的断点是否应该放在一起:

<div class="flex m0 p0 md-m2 md-p2">
  把断点放在一起
</div>

或属性本身:

<div class="flex m0 md-m2 p0 md-p2">
  把属性放在一起
</div>

我还没找到哪一个更好,所以我很好奇其他的团队是如何处理的。

文档

在我的 CSS 里,我会常常编档奇怪的属性和为什么我把东西放在一个特定的地方。例如:

噢 IE11,我还有需要为你做的事 🖕🏻 pic.twitter.com/Kca4VgHIJl

— Marcelo Somers (@marcelosomers) June 1, 2016

我能编档为什么一个一个不可变的类存在于我的 CSS 里,但是把为什么我给一个特定的 HTML 元素添加这个类放到我的 HTML 标记中显得有些奇怪。

结论

总的来说,我在使用 CSS 的函数式方法时还是很开心的。这是那些一旦你看见了你就再也忘不掉的东西之一,而且每一次当我大脑的不想改变部分尝试去写一个庞大的 CSS 类时,我发信我自己在构架 CSS 方面变得优柔寡断和不感兴趣。

我发现我自己想要结束编写 CSS。我想要在项目的早期写下一些类,然后通过把他们像乐高一样组装起来得到想要的设计效果。在项目的晚期才不得不去做代码抉择总是感觉不到位 —— 就像我在浪费我的时间用于写 CSS 而不是实际地去解决真正的可用性问题。

我希望得到采用了这个方法的你的反馈。如果你有兴趣学习更多有关函数式 CSS 的东西,我强烈推荐 Adam MorseJon Gold,和 Brent Jackson,他们是真正在推动着函数式 CSS 前进的人。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 11月28日晚上,我在朋友圈看到了文章《耶稣,请别让我做你的敌人》,认真地阅读了之后,深深地为这个不幸的女孩——罗...
    沐璎阅读 253评论 2 1
  • 海明威说过:“只有阳光而无阴影,只有欢乐而无痛苦,那就不是人生。” 莹说她要跟军子结婚了。祝福她,终于苦尽甘来,有...
    熟年与君共阅读 205评论 0 0
  • 概述: 我们如果对字符串进行拼接操作,每次拼接,都会构建一个新的String对象,既耗时,又浪费空间。而Strin...
    frankisbaby阅读 563评论 0 0