CSS 前處理器中的迴圈

敘帝利發表於2017-04-13

如果你看過老的科幻電影,你一定知道迴圈的強大之處。給你的機器人剋星設定無限迴圈,它就會爆炸,然後機器人灰飛煙滅了。

前處理器的迴圈並不會在太空中發生劇烈爆炸(我希望),但是它有利於書寫 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.

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 實現遞迴:

現在我們向 mixins 中新增 when 關鍵字,保證迴圈可以停止。

我們可以這樣建立 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 中,你做每件事都會遇到困難(原文評論中有很多人提出了反對意見)。這是它的特點。

社交媒體按鈕

遍歷列表很有用,但是很多時候你想遍歷物件。一個普通的例子就是給社交媒體按鈕新增不同的顏色和圖示。對於列表中的每一項,我們需要社交網路的名稱以及品牌顏色。

如果使用 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.

特殊的頭像

OddBird 上,我們設計了一個生成使用者預設頭像的程式——但是希望預設圖儘可能與眾不同。最後,我們只設計了 9 個獨特的圖示,使用迴圈生成 1296 個不同的頭像,所以大部分使用者不會看到重複的影象。

每個頭像有 5 個屬性:

  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 可能不是你網站的唯一色,但是現在用一個就夠了。我使用了多個變數名,因為有利於建立抽象的圖層——從基本色(pink)到更寬泛的模式(brand-primary)以及具體的使用場景(site-background)。我還想把單色列表轉換成前處理器可以編譯的調色盤。我需要一種方法保證所有數值是相關聯的並且是一種模式。我使用的方法是在單獨的 Sass map 中,以鍵值對的形式儲存主題顏色。

為什麼要多此一舉?我這樣做是因為我可以使用一個單獨的變數指定樣式生成器,並且自動建立實時更新的調色盤。但是這是一把雙刃劍,並不適合任何人。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 沒有內建的陣列變數,但是可以建立鍵值對模仿同樣的效果,和社交媒體顏色的做法一樣:

我們將建立 @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 前處理器中的迴圈

相關文章