本文由 叙帝利 翻译,黄利民 校稿。未经许可,禁止转载!

英文出处:Loops in CSS Preprocessors

发表地址:http://web.jobbole.com/91016/

如果你看过老的科幻电影,你一定知道循环的强大之处。给你的机器人克星设置无限循环,它就会爆炸,然后机器人灰飞烟灭了。

预处理器的循环并不会在太空中发生剧烈爆炸(我希望),但是它有利于书写 DRY CSS(译者注:详细介绍可以参考这篇文章 http://vanseodesign.com/css/dry-principles/)。每个人在讨论模式库以及模块化设计的时候,大部分人的关注点是 CSS 选择器。无论你使用哪种模式的选择器(BEM、OOCSS、SMACSS 等等),循环可以使设计模式易读并且可维护,直接编译到代码中。

我们先看一看循环能做什么,以及在主流的 CSS 预处理器(SassLessStylus )中如何使用。每一种语言都有特殊的语法,但是最终的效果是相同的。有多种方式制作 一只循环走动的猫

See the Pen Walkcycle with music loop by Rachel Nabors (@rachelnabors) on CodePen.

(animation by Rachel Nabors)

PostCSS 也很流行,但是本身并没有语法。它被称为后处理器,我喜欢称它为 meta-preprocessor。PostCSS 允许书写并分享你自己的预处理器语法。如果你愿意,你可以在 PostCSS 中重写 Sass 或者 Less,但是 已经有人在你之前这样做了

循环条件

星际迷航并非完全虚构。如果你不小心,无限循环可能会使编译器变得卡顿或者毁坏编译器。虽然这不是一个消灭邪恶机器人好办法,但是它会惹恼使用你代码的人。所以循环的使用是有限度的——通常是由一些递增的循环体或者对象集合定义。

在编程术语中:

  1. While 循环是通用的,循环一直运行直到满足条件。请小心!这里容易出现无限循环。
  2. For 循环是递增的,运行特定数量的循环体。
  3. For-Each 循环遍历集合或者列表,每次循环一项。

上述循环的使用范围依次递减。for-each 循环是 for 循环的一种形式, 它们也是 while 循环的一种形式。但是大多数的使用场景可能需要更具体的分类。我很难在实际工作中找到 while 循环——大多数例子使用 for 或者 for-each 处理的更好。所以 Stylus 只提供了后者的语法。Sass 的语法则提供了这三种方法,而 Less 并没有循环语法——但这并不会妨碍我们!开始吧。

遍历集合的 for-each 循环

当有一个项目集合(列表或者数组)的时候,预处理器的循环是非常有用的——比如一组社交媒体图标和颜色,或者一列状态修饰符(success, warning, error, 等)。因为 for-each 循环本身就是处理项目集合,它是最可靠并最容易理解的循环。

我们通过循环一个简单的颜色列表来看看它是如何工作的。

Sass 中,我们将使用 @each 指令(@each $item in $list)来获取颜色:

See the Pen Sass ForEach List by Miriam Suzanne (@mirisuzanne) on CodePen.

Stylus 中,使用 for 语法(for item in list)处理集合:

See the Pen Stylus ForEach List by Miriam Suzanne (@mirisuzanne) on CodePen.

Less并没有提供循环的语法,但是我们可以使用 recursion (递归)来替代。递归就是调用自身的函数或者 mixin 。在 Less 中,我们使用 mixins 实现递归:

.recursion() {
/* an infinite recursive loop! */
.recursion();
}

现在我们将向 mixins 中添加 when 关键字,保证循环可以停止。

.recursion() when (@conditions) {
/* a conditional recursive "while" loop! */
.recursion();
}

我们可以这样创建 for 循环,添加一个从 1 开始的计数器(@i),然后依次递增(@i + 1),直到满足条件结束(@i <= length(@list)),其中 length(@list) 表示项目集合的总数。如果每一次循环提取下一个列表项,我们将手动创建 for-each 循环:

See the Pen Less ForEach List by Miriam Suzanne (@mirisuzanne) on CodePen.

在 Less 中,你做每件事都会遇到困难(原文评论中有很多人提出了反对意见)。这是它的特点。

社交媒体按钮

遍历列表很有用,但是很多时候你想遍历对象。一个普通的例子就是给社交媒体按钮添加不同的颜色和图标。对于列表中的每一项,我们需要社交网络的名称以及品牌颜色。

$social: (
'facebook': #3b5999,
'twitter': #55acee,
'linkedin': #0077B5,
'google': #dd4b39,
);

如果使用 Sass,我们可以使用语法 @each $key, $value in $array 来获取 key 值(网站名称)和 value 值(品牌颜色)。以下是全部的循环:

See the Pen Sass Social Media Loop by Miriam Suzanne (@mirisuzanne) on CodePen.

Stylus 有相同的语法:for key, value in array

See the Pen Stylus Social Media Loop by Miriam Suzanne (@mirisuzanne) on CodePen.

Less 中,我们必须手动提取每一对:

See the Pen LESS Social Media Loop by Miriam Suzanne (@mirisuzanne) on CodePen.

递增的 for 循环

For 循环可以运行任意数量的循环体,并不局限于对象的长度。你可能会使用它创建一个栅格系统(for columns from 1 through 12),遍历色轮(for hue from 1 through 360)或者使用 nth-child 给 div 编号并生成内容。

下面我们遍历 36 个 div 元素,使用 :nth-child 给每一项添加编号及背景色。

Sass 提供了一个特殊的 for 循环语法:@for $count from $start through $finish,其中 $start$finish 都是整数。如果初始值比较大,Sass 会递减而不是递增。

See the Pen Sass "for" loop by Miriam Suzanne (@mirisuzanne) on CodePen.

through 关键字表示循环包含数字 36 。你也可以使用 to 关键字,它不包含最后一个元素,只会循环 35 次:@for $i from 1 to 36 。

Stylus 也有同样的递增的语法,但是 tothrough 需要替换成 ... and ..

See the Pen Stylus "for" loop by Miriam Suzanne (@mirisuzanne) on CodePen.

Stylus 也提供了一个 range() 函数,可以改变递增的步数。使用 for hue in range(0, 360, 10) 可以每次以 10 的倍数递增。

Less 需要使用递归 mixins 。我们可以创建一个迭代数的参数(@i),使用 when (@i > 0) 条件结束循环,每次迭代减一,这样看上去像是递减的 for 循环。

See the Pen Less "for" loop by Miriam Suzanne (@mirisuzanne) on CodePen.

值得注意的是 CSS 也可以实现 nth-child– 编号,不需要预处理器。然而 CSS 并没有循环结构,它提供了一个 counter() 方法,根据 DOM 的数量递增,可以用于生成内容。然而在 content 属性之外使用是无效的,所以背景色并没有变化。

See the Pen CSS counter by Miriam Suzanne (@mirisuzanne) on CodePen.

栅格系统

我通常在抽象的 Sass 工具包中使用递增循环,几乎不在具体的样式表中使用。其中一个例外是生成带编号的选择器,可以是 nth-child (像我们上面做的一样),也可以是自动生成的类名(通常用在栅格系统中)。我们将创建一个简单的不带间距的响应式栅格系统。

See the Pen Sass For-Loop Grids by Miriam Suzanne (@mirisuzanne) on CodePen.

每个栅格都是百分比,使用 span / context * 100% 计算——所有栅格系统使用的基本计算方法。以下是 Stylus 和 Less 的语法:

See the Pen Stylus For-Loop Grids by Miriam Suzanne (@mirisuzanne) on CodePen.

See the Pen LESS For-Loop Grids by Miriam Suzanne (@mirisuzanne) on CodePen.

特殊的头像

OddBird 上,我们设计了一个生成用户默认头像的程序——但是希望默认图尽可能与众不同。最后,我们只设计了 9 个独特的图标,使用循环生成 1296 个不同的头像,所以大部分用户不会看到重复的头像。

每个头像有 5 个属性:

<svg class="avatar" data-dark="1" data-light="2" data-reverse="true" data-rotation="3">
<use xlink:href="#icon-avatar-1" xmlns:xlink="http://www.w3.org/1999/xlink"></use>
</svg>
  1. 初始图标形状(9 个选项)
  2. 可以选装 0, 90, 180, 或者 270 度(4 个选项)
  3. 深色填充色(6 个选项)
  4. 浅色背景色(6 个选项)
  5. 可以反相颜色的 true/false 属性(2 个选项)

代码中有 6 个颜色,3 个循环:

  1. @for $i from 0 through 定义四个旋转角度
  2. @for $i from 1 through length($colors) 可以循环颜色集合($colors),给每个颜色赋值($i)。通常我会使用 @each 循环遍历颜色集合,但是如果每一项需要一个数值的时候,使用 @for 更简单。
  3. 嵌套的 @each $reverse in (true, false)可以让我们选择是否将每个颜色组合的前景色和背景色反转。

以下是使用 Sass 编写的最终结果:

See the Pen 1296 avatars using multiple loops by Miriam Suzanne (@mirisuzanne) on CodePen.

你可以在课后把它转成 LessStylus 的代码。我已经看腻了。

特殊的 while 循环

真正的 while 循环很少见,但是我偶尔会使用。当我看一条路径指向何处时会非常有用。我并不想遍历整个集合或者特定数量的迭代——我想在找到需要的元素时就停止循环。我通常在抽象的工具包中使用,而在日常编写样式表时并不需要。

我使用 Sass 创建了一个帮助我储存及控制颜色的工具包。使用变量存储颜色可能是任何预处理器最普通的使用场景。大多数人会这样做:

$pink: #E2127A;
$brand-primary: $pink;
$site-background: $brand-primary;

我知道 pink 可能不是你网站的唯一色,但是现在用一个就够了。我使用了多个变量名,因为有利于创建抽象的图层——从基本色(pink)到更宽泛的模式(brand-primary)以及具体的使用场景(site-background)。我还想把单色列表转换成预处理器可以编译的调色板。我需要一种方法保证所有数值是相关联的并且是一种模式。我使用的方法是在单独的 Sass map 中,以键值对的形式存储主题颜色。

$colors: (
'pink': #E2127A,
'brand-primary': 'pink',
'site-background': 'brand-primary',
);

为什么要多此一举?我这样做是因为我可以使用一个单独的变量指定样式生成器,并且自动创建实时更新的调色盘。但是这是一把双刃剑,并不适合任何人。map 不允许我像使用变量一样给直接给键值对赋值。为了找到每个颜色的 value 值,我需要使用 while 循环检索 key 值。

See the Pen Sass "while" loop by Miriam Suzanne (@mirisuzanne) on CodePen.

我经常这样做,但是如果你在我的代码中搜索 Sass 的 @while, 你是找不到的。

See the Pen Sass "while" recursive function by Miriam Suzanne (@mirisuzanne) on CodePen.

现在我们可以在代码的任何地方调用 color() 函数。

Stylus 没有 while 循环的语法,但是可以使用数组变量和递归函数:

See the Pen Stylus "while" loop by Miriam Suzanne (@mirisuzanne) on CodePen.

Less 没有内置的数组变量,但是我们可以创建键值对模仿同样的效果,和社交媒体颜色的做法一样:

@colors:
'pink' #E2127A,
'brand-primary' 'pink',
'site-background' 'brand-primary'
;

我们将创建 @array-get mixin ,使用 key 值从数组中检索 value 值,然后创建递归的 while 循环来跟随路径:

See the Pen Less "while" list loop by Miriam Suzanne (@mirisuzanne) on CodePen.

作为示例可以运行,但是在 Less 中还有更好的方法,你可以不使用别名和命名变量构成的数组(不像 Sass 或者 Stylus):

See the Pen Less name-spaced variables by Miriam Suzanne (@mirisuzanne) on CodePen.

既然颜色在一个变量中可行,我可以使用循环生成调色板。以下是使用 Sass 做的例子:

See the Pen Sass color palette by Miriam Suzanne (@mirisuzanne) on CodePen.

我相信你可以比我做的更漂亮。

Getting Loopy!

如果你不知道该什么时候使用循环,时刻留意循环体。你是不是有大量遵循相同模式的选择器,或者重复的计算?下面告诉你如何判断哪个循环是最好的:

  1. 如果你可以列出并命名循环中的项目,使用 for-each 遍历。
  2. 如果循环的次数比循环体本身重要,或者如果你需要给每一项编号,请使用 for 循环。
  3. 如果您需要访问同一个循环,只是输入值不同,尝试递归函数。
  4. 对于其它情况(几乎从来没有),使用 while 循环。
  5. 如果你使用 Less… 祝你好运!

尽情的享受循环吧!

CSS 预处理器中的循环的更多相关文章

  1. CSS预处理器——Sass、LESS和Stylus实践

    CSS(Cascading Style Sheet)被译为级联样式表,做为一名前端从业人员来说,这个专业名词并不陌生,在行业中通常称之为“风格样式表(Style Sheet)”,它主要是用来进行网页风 ...

  2. 20190421-那些年使用过的CSS预处理器(CSS Preprocessor)

    写在前面的乱七八糟的前言: emmm,不得不说,早上七点是个好时间,公园里跳广场舞的大妈,街边卖菜刀看报的大爷,又不得不说,广州图书馆是个好地方,该有的安静,该有的人气,听着楼下小孩子的声音,看着周围 ...

  3. CSS预处理器Sass、LESS 和 Stylus

    CSS 预处理器技术已经非常的成熟,而且也涌现出了越来越多的 CSS 的预处理器框架.本文向你介绍使用最为普遍的三款 CSS 预处理器框架,分别是 Sass.Less CSS.Stylus. 首先我们 ...

  4. 为您详细比较三个 CSS 预处理器(框架):Sass、LESS 和 Stylus

    CSS 预处理器技术已经非常的成熟,而且也涌现出了越来越多的 CSS 的预处理器框架.本文向你介绍使用最为普遍的三款 CSS 预处理器框架,分别是 Sass.Less CSS.Stylus. 首先我们 ...

  5. 详细比较三个 CSS 预处理器(框架):Sass、LESS 和 Stylus

    [大伽说]如何运维千台云服务器 »   CSS 预处理器技术已经非常的成熟,而且也涌现出了越来越多的 CSS 的预处理器框架.本文向你介绍使用最为普遍的三款 CSS 预处理器框架,分别是 Sass.L ...

  6. CSS预处理器的对比 — Sass、Less和Stylus

    本文根据Johnathan Croom的<sass vs. less vs. stylus: Preprocessor Shootout>所译,整个译文带有我们自己的理解与思想,如果译得不 ...

  7. 比较三个 CSS 预处理器:Sass、LESS 和 Stylus(下)

    五.Mixins (混入) Mixins 有点像是函数或者是宏,当你某段 CSS 经常需要在多个元素中使用时,你可以为这些共用的 CSS 定义一个 Mixin,然后你只需要在需要引用这些 CSS 地方 ...

  8. 三个 CSS 预处理器(框架):Sass、LESS 和 Stylus

    CSS 预处理器技术已经非常的成熟,而且也涌现出了越来越多的 CSS 的预处理器框架.本文向你介绍使用最为普遍的三款 CSS 预处理器框架,分别是 Sass.Less CSS.Stylus. 首先我们 ...

  9. css预处理器和后处理器

    因为我是前端刚入门,昨天看了一个大神写的的初级前端需要掌握的知识,然后我就开始一一搜索,下面是我对css预处理器和后处理器的搜索结果,一是和大家分享下这方面的知识,另一方面方便自己以后翻阅.所以感兴趣 ...

随机推荐

  1. 第22篇 js中的this指针的用法

    前面把js的相关知识总结了下,今天把js中的上下文的this,对于强类型语言,this的用法非常的单一,因为他们没有js特有的动态绑定. 首先看下面代码: function funcA() { thi ...

  2. 关于zepto在chrome中触发两次的解决方案

    复现条件:chrome 55+ 1.zepto tap的实现及double fire的原因 在监听DOM根节点的时候,touchStart后通过XY的坐标偏差,与tapTime的计时判断Tap/Lon ...

  3. 根据WaitType诊断故障

    在查询执行时,等待次数和等待时间在一定程度上指示查询的瓶颈,甚至非常有助于对系统进行诊断.偶尔一次的异常等待,不足以表明系统存在瓶颈,但是,SQL Server实例经常出现特定的等待类型,并且等待时间 ...

  4. hdoj 1257 DP||贪心

    最少拦截系统 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  5. bat文件的一些小技巧

    bat文件的简介: bat文件是dos下的批处理文件.批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键入批处理文件的名称,或者双击该批处理文 ...

  6. wemall app商城源码中基于PHP的ThinkPHP惯例配置文件代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  7. Webpack单元测试,e2e测试

    此篇文章是续 webpack多入口文件.热更新等体验,主要说明单元测试与e2e测试的基本配置以及相关应用. 一.单元测试 实现单元测试框架的搭建.es6语法的应用.以及测试覆盖率的引入. 1. 需要安 ...

  8. rpm包相关操作

    1.查找已安装的rpm:rpm -qa|grep ewp2.卸载已安装的rpm: 先切换到虚拟机共享路径,执行卸载命令: rpm -e 已安装rpm包名称3.安装新rpm包:rpm -ivh(更新的话 ...

  9. 【G】系列导航

    G.开源的分布式部署解决方案 [G]开源的分布式部署解决方案 - 预告篇 [G]开源的分布式部署解决方案(一) - 开篇 [G]开源的分布式部署解决方案(二) - 好项目是从烂项目基础上重构出来的 [ ...

  10. ubuntu查看安装的cuda toolkit自带的工具及其他安装文件

    原创作品,转载请注明来源:http://www.cnblogs.com/shrimp-can/p/5253672.html 1.查看工具 默认目录为:local,进入local:cd /usr/loc ...