Medium的CSS 方案:简直完美

  • 发表于
  • 前端

不管是气质、穿着还是行为,我总是想要做到最好。就算是我扔进垃圾桶的垃圾,也要比其他人扔的东西好。

— Lil Wayne

下面是我们把Medium的CSS代码一步步优化的过程,对于我们是如何做成现在这样、以及今后的规划,都可以在下文中略见一斑。

the best

初识阶段(一点小历史)

大约2年前我加入了Obvious公司,参与 medium.com 的产品开发中来。那时,Medium已经经历过一系列的“重设计”(意味着设计师把之前的方案完全推翻,重写大量的CSS/LESS/SASS等等,做出更漂亮的设计来)。也正是由于这些“重设计”,反而多了很多糟粕——大量地依赖LESS的语言特性,不使用雪碧或高清技术处理图片素材等等不好的习惯。

我把以前的页面翻了出来,放了一个配置页上来,大概检讨了下旧版本有哪些我们值得注意的缺失:

  • 所有的元素都嵌套在了一个名为 .profile-page 的类中,没有任何可用组件(几乎所有类名都把 .profile 做前缀);
  • 变量名超级无意义,类似于 @link-color 这种不知道它关联的是什么元素,但貌似也只在 profile-page.less 中出现了;
  • 嵌套过深(像.profile-page .profile-posts .home-post-summary .home-post-collection-image img 实在不该出现);
  • 没用CSS雪碧技术调用图像;
  • z-index、字体、颜色等等都没用缩放……

https://gist.github.com/fat/a4af78882d0003d2345e

第一阶段:图小事大

那时,我对于代码库(Bootstrap、Ratchet等等)已经了解了不少,把它们都努力学习透彻了之后,尝试用这些工具编写出力所能及最完美的CSS。当时的Medium CSS代码跟那些代码库不仅完全不一样,还糟的不成型,我得想办法弥补弥补。

首要任务,从整理图片资源开始。我还记得,都已经是2012年了,旧版本竟然完全没用雪碧技术……那可是上百张大大小小的图啊,占位图、箭头、图标各种,全扔在 /img/ 目录下了,简直跟乱坟岗似的。

为了早日从混乱的图片堆中解脱出来,我做了两件事——首先,我写了个小的CSS功能脚本,起名叫SUS(直到现在我们都还在用,我把它开源放在这里了),这个脚本是在Guillermo Rauch的帮助下完成的,作用是在样式表中提取图片并把它们分别延迟加载到了单独的 data-uri 文件中。这个想法不是我原创的,我只是觉得这个脚本放在这里用更适合。

做的第二件事,就是Geoff Teehan和我两个一起设计了Medium历史上第一个icon font。那时,我们根本不知道自己在做什么……在iconmoon(github上的一篇博文)的帮助下,熬了几个晚上,我们终于把Medium设计得看上去有那么点美感了。这可是个不小的改进——有了它们,我们不仅可以删了图片库中97%的图,节省大量的空间,而且图像改进后,在我的retina版MacBook Pro上变得好看多了。

第二阶段:尺度设置

下一个重要的任务就是解决z-index属性。这家伙调教得不好很容易失控,每次到最后总会把我逼疯,我可不想在Medium上也重蹈覆辙。

在整改之前,代码中遍布着各种混乱的z-index属性值,你都无法想象 z-index: 5 的同层元素竟然跟着 z-index: 1000000 、 z-index: 1000001 、 z-index: 99999 这类的值,我完全不知道该怎么去把这些杂乱的样式分类。所以,我只好做出艰难的决定——把整个代码库里的所有z-index值通通手动审查一遍。之后,我引入了一个内部尺度(写在了内部文件z-index.less中),它可以把使用z-index的元件值限制在1-10。我把代码库里所有z-index都关联上了这个尺度,你才会看到现在不同组件位于不同层次的效果(使用起来也很方便)。

下面这个z-index文件是medium.com现在用的版本:

https://gist.github.com/fat/1f6da6b3bd0311a1f8a0

当然,我们把这种给z-index添加尺度方式也用在了颜色(比如黑、灰、白、品牌色等变量)和字体(比如字体大小、字重、字距、字高等变量)的设置上。你可能还会注意到,这些变量名会使用更为严格及语意化的值,这个我们稍后详述……

第三阶段:全新样式指南

第二阶段过后没多久,我们开始了又一轮的大型重设计计划——代号为“茧”。“茧”计划推翻了几个旧的日志模板(Medium不仅仅只有单文章模板,最初还提供过图片和引用模板),引入了日志列表,替换了以前的日志“卡片”功能。我们冒险尝试退一步思考,给Medium写了新的样式指南。

花了很长一段时间,我们都把精力集中用CSS/LESS开发一次重要升级上:

  • 限制LESS的变量和mixin(不用嵌套、guard、extend等等)使用——虽然这些语言功能很强大,但如果碰上的是经验不足的LESS开发者,反而会让其陷入棘手的困境。我们更青睐pure CSS的视觉效果(统一性也不错),打算把代码库往那个方向努力优化。
  • 使用小写字母书写Class和ID,单词之间用破折号隔开——我们大多数人用Bootstrap、Skeleton、Ratchet这些框架时会有这种习惯,那么这里也同样适用。还一个原因,因为CSS自己的属性命名就是这样的格式,如border-radius-top-left这种,跟着它走总是没错的。
  • 元件等级高于页面样式——尽量把前端开发看成是个由多个元件组成的代码库,把一个页面整体(类似profile.less)打散成小而专的代码片段文件(类似button.less、dialog.less、tooltip.less等等)。

查看全文请点击:

https://gist.github.com/fat/b27700946c777adacdf4

这些不见得适用于所有开发,但起码帮我们厘清了一些基本原则,跟着走总不会走错。

可是,即使经历了这次样式升级,很多同事似乎还是不太会用,还是搞不清什么时候该创建元件、什么时候该创建子元件;当然,我们也会偶尔犯傻,起些不合适的class名,如 .nav-on-light-background-button 或者 .button-primary-sidebar-over-blur 之类的。

但大家已经不会把页面作为class的前缀名了,取而代之的是一长串用破折号分割的随意的单词: .button → .button-primary → .button-primary-dark →.button-primary-dark-container → .button-primary-dark-container-label ……这么长,都快看晕了。

第四阶段:蓝图

现在,我怀着成为“世界上最棒的站点”这一崇高理想,开始着手书写Medium的内部代码。虽然我不知道这样做会不会成功,但我确定,起码我们是朝着对的方向在努力。

……大家都很困惑。更糟的是,我以为大家都很会写CSS,但实际上并没有。

所以,我开始四处寻求解决之道——调一调框架、试试不同的工具、求助于哲学、询问朋友以及朋友的朋友……后来终于有了结论,提出了三个主要的改进方面,需要逐个击破:

  1. 引入新的CSS变量、混写和类名含义,来提升可读性,也避免了随意取的可能;
  2. 抛弃LESS,投入 Rework 的怀抱,它有更强的混写支持,语法跟vanilla CSS也更类似;
  3. 启用一些提升CSS性能(从像载入时间、帧数、布局时间等入手)的工具,可以更快捷地进行样式变化追踪和回溯。

第五阶段:语义提升

鉴于我们团队的规模并不大,如果有了规范,应该会更容易执行才对,所以我想把代码中的语义做更严格的规定。并且,我希望把规则定的复杂点,这样大家在新建class时就会更加小心谨慎。无论如何,我就是想避免随意起名的事情发生,即使不行也至少多增加点难度。

我和好友Nicolas聊了很久,经过了几个晚上的讨论,我终于被他的用 SUITCSS 画的一个样式给说服了,跟我的方案很像但又稍微好一些。我抛弃了旧版样式规范,借用了他的方案,在此基础上修改了部分细节,最终形成了我们现有的样式。增添的部分主要有:

  • JS专用class选择器名以 .js- 为前缀;
  • 单一功用class名以 .u- 为前缀,如 .u-underline、.u-capitalize 等;
  • 引入有意义的连字符和驼峰法,以此强调元件、子元件、修改器名的分隔;
  • 状态类class(一般由JS来控制)名以 .is- 为前缀,如 .is-disabled 等;
  • 使用新的CSS变量名规则: [属性]-[值]--[元件] ;
  • 混写只在万不得已的补漏时出现,只能以 .m- 作为前缀。

查看样式规范全文请点击:

https://gist.github.com/fat/a47b882eb5f84293c4ed

拷贝修改出一个新的样式方案事小,重写所有CSS代码事大。感谢公司对本项目的支持,但愿我没有做出错误的决定——如果你一直有关注我们项目的进展,你会知道整理新的CSS规范只占了我们工作的一小部分而已。代码重写就像一次宣泄,它清理掉了许多早已用不上的样式,把庞大的文件打散成小型的功能元件,让站点简化。当然,重构的还有模板——封装了更多部件,严格地控制语义使用。就像现在,你再也看不到成百上千个<IMG>标签以及随机头像class名,取而代之的是,统一使用头像模板,通过布尔值触发不同的修改器,如尺寸、样式等等,这样操作起来更容易,细节bug出现的频率也会大大降低。

第X阶段:未来会是怎样?

毫无疑问,我们相比2年前来说已经有了天翻地覆的变化。在Medium开发CSS,跟有着不同经验的同事一起开发也有着不同的乐趣。尽管如此,性能优化将会是下一阶段的任务。我将不断地在这篇文章后面添加新的想法和记录,你可以看到,选择可靠的布局测量和性能渲染工具是非常重要的……这点我在2014还没意识到呢。

你能坚持看到这里真是奇迹,谢谢你的耐心。最后感谢Katie、Dave、Mark、Koop、Kristofer、Nicolas等等各位朋友对我的帮助,没有你们,就没有现在的成功 ❤

原文:Medium’s CSS is actually pretty f***ing good.