Wealthfront我们是一个函数式编程的超级粉丝。强调不变性和函数式风格意味着更少的“意外”(surprises),因为副作用是有限的或不存在的。我们能将独立的组件迅速构建出大型系统,通过组合的方式组合组件。

函数式编程原则直接应用在大多数语言中,即使他们不是被定义为函数式。同样适用非函数式的css。让我们看下我们最喜欢的(和最讨厌的)一些特性在样式语言中。

  • 一切都是全局作用域。
  • 一切都是可变的。
  • 优先级的计算,基于一些有趣的规则

因此让我们讨论下我们能做什么。Wealthfront的 CSS(实际是 SCSS)风格指南概述一些经验法则,让我们在CSS中获得函数式编程范式的效益。确切的说,指南通过限制副作用减少意外,提倡组合使我们的样式表更具伸缩性。在本文中,我将介绍一些我们的样式指南中的主要的规则。

引入作用域

大部分语言中,变量定义被限制在它们的作用域内。在Javascript中,变量的作用域是他们所在的函数,而其他语言中,如Java变量具有块级作用域。我在我的作用域里定义的变量不能被其他人在我的作用域外重定义或修改。

作用域是防御式编程和降低副作用的重要部分。如果您的规则、函数或变量只存在于一个受限的作用域,那么你可以放心没人会更改它,无论是有意还是无意的。

CSS没有作用域。样式定义时可能意外重写其他规则,而且无法保证你挑选的样式规则名称没被其他人使用。它可能在完全不同的文件里,并且是深度嵌套的选择符。假如你问你的样式规则选择了一个相同的名字,则意外重写其他人规则的概率骤然升高。让我们思考下面的例子:

/* profile.css */
.error { color: orange; }
.success { color: blue; }
/* signup.css */
.error { color: red; }
.success { color: green; }

假如我们在我们的HTML中引入上面的CSS文件,我们无意中用其中一个样式重写(覆盖)了另一个。随着网站的增长,这种状况变得越来越复杂和普遍。

那么我们如何在CSS中引入作用域呢?

在CSS中模拟更细粒度的作用域的安全做法是用命名约定。在这种情况下,我们为我们所有的样式规则设置命名空间通过添加一个前缀。前缀命名空间规则不是一个新的理念,但重要的是我们知道我们为什么那样做。在前缀的样式中我们创造了我们的“作用域”,你可以说我们的css是在“prefix”作用域内——我们的样式只在设置了前缀的规则中存在。

让我们用前缀符尝试修改前面的例子:

/* profile.css */
.profile-error { color: orange; }
.profile-success { color: blue; }
/* signup.css */
.signup-error { color: red; }
.signup-success { color: green; }

加前缀允许我们封装我们的规则,保护它们免受修改。有了这些附加的前缀,我们的规则不再冲突。我们使他们免受副作用,通过声明我们的规则在命名空间作用域中。

减小依赖,增大可重用性

通过使用复杂的选择符来保持我们的标记整洁和无类是很容易的。我们都见过像下面这样的CSS:

.whitepaper-link {
font-weight: bold;
font-size:12px;
} .main-nav .whitepaper-link {
font-size:16px;
} .main-footer .whitepaper-link {
font-size:9px;
}

但如果我们想在其他地方有小号的.whitepaper-link呢?上面这样的嵌套选择符我们在我们的样式中强制了DOM结构(样式规则和DOM结构紧紧耦合在一起)。这就是说”你只能在main-footer中有一个小的whitepaper链接“。在CSS规则中强制结构阻止我们重用样式,并且将我们数据的表现和它在结构中的表现混合在一起(结构和表现紧耦合)。当我们通过嵌套的选择符强制结构时,我们在它们间创造了依赖。在软件工程的任何区域管理依赖都是令人头痛和容易出错的。我们应该避免。

代替强制结构,让我们像下面这样定义它:

.whitepaper-link {
font-weight: bold;
font-size:12px;
} .whitepaper-link-large {
font-size:16px;
} .whitepaper-link-small {
font-size:9px;
}

我们的标记能添加 .whitepaper-link 和 .whitepaper-link-small 类到页脚元素来实现和旧版中一样的效果。现在我们能复用 "small"样式到站点中的任何其他元素,无论它是否在footer元素内。我们在这真正见到的是组合的魔力,我们将在一分钟后讨论。

避免突变性

在CSS中重写样式规则并非是罕见的(恰恰相反)。例如,你可能想让一个错误消息有不同的效果如果它在侧边栏里。

/* errors.css.scss */
.error { color: red; }
.sidebar .error { border:1px solid red; }

这是意大利面条式代码的东西。这不是与一群工程师使用全局变量类似。一些工程师在他们的代码中将重定义变量(样式),然而其他人仍然期望它(变量)保持原来的定义。这 .error 样式变得不再安全,无法知道它在给定的上下文中的确切行为。样式规则变得充满意外,然而我们讨厌意外。

解决方案是从不重写一个已经定义的样式规则。如果你把规则当成不可更改的——那意味着,它们是一成不变的,定义之后也永远无法改变它们——你可以避免许多由全局变量和不稳定变量引起的问题。

我们可以通过组合实现这些,无论我们通过元素的类属性或通过Sass的@extend 指令。

组合是你的福音

让我们看下我们如何用我们上面描述的来完成例子。

/* errors.css.scss */
.error { color: red; }
.sidebar-error { border:1px solid red; }
\<!-- example.html -->
\<div class="error sidebar-error">Oh no!</div>

我们没有重定义 .error 规则,而是给我们的 error div增加一个新的规则来增强它。我们的 error div 的表现将是 .error 和 .sidebar-error的组合。

这仍然让人有点迷惑,我们没有重写 .error 规则自己,但我们重写他的一个属性。如果你正在使用 Sass,更富有表现力的在你的样式中用SCSS方式定义组合是通过@extend指令。

/*errors.css.scss*/
.error { color: red; }
.sidebar-error {
@extend .error;
border:1px solid red;
}
example.html
<!-- example.html -->
<div class="sidebar-error">Oh no!</div>

现在我们的标记保持苗条,并且没有给人错误的印象,它看起来应该像 .error。任何浏览错误样式表的开发者将看到 .slidebar-error是 .error 外加一个边扩展。他们能自信的使用 .error 因为它从没被重定义,并且我们仍将有我们自定义的 .sidebar-error 表现。

FCSS

Wealthfront有一些更多的规则,我们在本文中没有讨论。但他们都融入到整个我们讨论过的指导原则中。例如,我们避免元素和过多伪类及伪对象选择符,因为他们和DOM结构紧耦合,并且我们更喜欢类选择符替代id选择符来提高可重用性(ID 选择符被用来非常特殊的,单个元素重写或样式)。

在此强调:

  • 通过前缀为你的类增加命名空间,增加伪作用域和减少意外。
  • 不要通过多次定义重写样式中的规则,而是用组合。
  • 不要用嵌套,元素选择符或过度的伪类及伪对象选择符——他们将你的CSS和DOM结构仅仅绑定在一起。

每一个团队需要自己的样式指南在缺少约束的语言中强制约束。如果运气好,我们的“函数式”方法将带给你一些灵感。

注:本文为翻译文章,原文为 Functional CSS (FCSS),如果你觉得我翻译的不错,可以在这里关注我的微博。

函数式 CSS (FCSS)的更多相关文章

  1. react第三方库

    作者:慕课网链接:https://www.zhihu.com/question/59073695/answer/1071631250来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  2. Matplotlib数据可视化(3):文本与轴

      在一幅图表中,文本.坐标轴和图像的是信息传递的核心,对着三者的设置是作图这最为关心的内容,在上一篇博客中虽然列举了一些设置方法,但没有进行深入介绍,本文以围绕如何对文本和坐标轴进行设置展开(对图像 ...

  3. css权威指南--笔记

    第1章 css和文档 1,元素:替换元素(img input),非替换元素(大多数span). 2,link:rel(代表关系:stylesheet,候选样式表:alternate styleshee ...

  4. 新手理解HTML、CSS、javascript之间的关系

    http://www.cnblogs.com/dreamingbaobei/p/5062901.html 工作多年,一直忙忙碌碌的应用各种技术,现在不忙了,问问自己究竟在做什么,究竟会什么竟答不上来, ...

  5. Web前端:HTML~CSS~JS

    网页主要由3部分组成:结构.表现.行为.目前网页的新标准是W3C,模式是HTML.CSS.JavaScript,这是前端开发最核心的3个技术.前2个技术的最新版本分别为HTML5.CSS3.  “HT ...

  6. css的一种预处理器 sass

    之前觉得关于css什么的没什么,后来让别人给问住了...然后就悲催了... sass是一种css的预处理器,是一种函数式的css的编程: 主要还是看官网 http://www.w3cplus.com/ ...

  7. 喝咖啡写脚本,顺便再加一点点CSS语法糖 1.选择环境

    经过对前端开发的初步了解,大体上发现了以下几点,前端开发需要使用脚本语言,主要是JavaScript,需要Html,需要CSS,这些东西相信很多人已经很熟了.但是仅仅只是学习一点简单的JS,配合Htm ...

  8. html css布局

    这几天有点急于求成了,原来每一门技术都像大海,只有深入其中才发现它比看到的更要深广的多. 虽然忙里偷闲的看了HTML5,NODE.JS,JAVASCRIPT核心等许多东西,但是真正掌握的不足十分之一, ...

  9. CSS权威指南-第三版--读书笔记

    第一章:CSS和文档 html是结构化语言,css是样式语言,html主要用来被强大的搜索引擎更好的索引,更好的让一个盲人通过语音浏览器来了解我们的网页,这也就是为什么说html是结构话语言,因为这是 ...

随机推荐

  1. 小课堂week13 Clean Code Part2

    Clean Code Part2 对象与数据结构 首先让我们进行一个严肃的思考,对象与数据结构的区别在哪里? 如下两段代码分别用数据结构和对象的方法来描述了一个Point. public class ...

  2. 04-树5 Root of AVL Tree

    平衡二叉树 LL RR LR RL 注意画图理解法 An AVL tree is a self-balancing binary search tree. In an AVL tree, the he ...

  3. 【Cocoa】 Initializing View Instances Created in Interface Builder

    Initializing View Instances Created in Interface Builder View instances that are created in Interfac ...

  4. printf输出格式总结

    printf函数称为格式输出函数,其关键字最末一个字母f即为"格式"(format)之意.其功能是按用户指定的格式,把指定的数据显示到显示器屏幕上. printf函数调用的一般形式 ...

  5. XMLCDataSection

    XmlCDataSection类描述XML数据中的CDATA节.CDATA节在XML数据中的作用是为文本内容定义引号和转义符,即XML解析器不解析CDATA中的任何字符. XmlCDataSectio ...

  6. MySQL快速生产表的描述

    # mysql快速生成表的描述 SELECT column_name AS `列名`, CONCAT_WS(' (', data_type, character_maximum_length) AS ...

  7. java下的redis操作

    Java操作redis(增删改查) Java代码 package sgh.main.powersite; import java.util.ArrayList; import java.util.Ha ...

  8. Environment 类

    提供有关当前环境和平台的信息以及操作它们的方法. 此类不能被继承. using System; using System.Collections; using System.Collections.G ...

  9. C# 执行Cmd窗口中的命令 [复制文件实例]

    /// <summary> /// 复制文件夹 /// </summary> /// <param name="sCmd"></param ...

  10. trap命令使用

    分享一个shell脚本技巧,大家写shell脚本的时候,一般而言仅仅保证功能可用,但程序的鲁棒性却不是太好,不够健壮,多数是脚本处理 一些中断信号导致,应对非预期的系统信号,其实系统自带的trap命令 ...