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. STM32F4_引领入门

    Ⅰ.概述 该文写给那些想学ST芯片开发(或初级学习)的朋友,文章着重细节,或许有点简单. 笔者想告诉那些刚开始学习ST的朋友,不管你使用哪一个系列(F0.F1.F2),哪一种型号芯片,其实学习的方法和 ...

  2. 第十九章 数据访问(In .net4.5) 之 处理数据

    1. 概述 本章介绍 数据库.Json和Xml.web services 三种介质上的数据操作. 2. 主要内容 2.1 数据库 ① 建立连接 .net平台中的数据连接类都继承自DbConnectio ...

  3. python中split与join

    1.split个人最喜欢的就是它能使输入的一连串数字变为list. str=raw_input("some ") str2=str.split(" ") str ...

  4. sizeclass

    横竖9种组合,代表所有大小屏幕,在storyboard中可以把contrans与不同组合绑定,也就是说,可能横向有多一个约束,纵向就没了... 实现不同屏幕不同约束,这应该是sizeclass 的存在 ...

  5. [转载]--用Python 自动安装软件

    脚本使用了  Python 2.3 + Com 对象,所以你的系统必须安装Python2.3或更高版本同时必须安装  Mark Hammond's Win32all 模块 (特别感谢Mark Hamm ...

  6. Oracle Study Note : Users and Basic Security

    1. view the default user account SQL> select username from dba_users; 2. lock all users and set t ...

  7. Java入门到精通——基础篇之static关键字

    一.概述        static 关键字是声明静态变量,静态方法用的.static的含义是属于类且不属于类对象的变量和函数. 二.static的产生.         在创建对象的时候除非用new ...

  8. FineUI PK DWZ

    一.概述 FineUI(ExtAspNet)是基于 jQuery / ExtJS 的 ASP.NET 控件库. DWZ是基于JQuery的一个客户端框架. 二.比较 三.总结 这两个东西实质都是对控件 ...

  9. mybatis数据库基本配置包括数据源事物类型等

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  10. 怎么解决/bin/sh: arm-linux-gcc: not found make

      1.arm-linux-gcc 环境变量没有设,所以找不到这个编译器 在/etc/profile里添加arm-linux-gcc的存放路径 sudo -s gedit /etc/profile 编 ...