預(yù)處理器循環(huán)不會(huì)在空間中引起劇烈的爆炸(我希望)株茶,但它們對(duì)于編寫DRY CSS非常有用蜜笤。 盡管大家都在談?wù)摰臉邮綆旌湍K化設(shè)計(jì)屈梁,大部分重點(diǎn)一直在CSS選擇器這上面点弯。 不管你選擇什么樣的縮寫方式(BEM扇调,OOCSS,SMACSS抢肛,ETC)狼钮,循環(huán)可以幫助保持你的樣式更具可讀性和可維護(hù)性,直接加工到你的代碼中雌团。
我們將看看循環(huán)可以做什么燃领,以及如何在主要的CSS預(yù)處理器中使用它們:Sass,Less和Stylus锦援。 每種語言都提供了一種獨(dú)特的語法猛蔽,但他們都完成了工作。 有不止一種方法來循環(huán)一只貓灵寺。
貓
PostCSS也很受歡迎曼库,但它不提供它自己的任何語法。 雖然它有時(shí)被稱為后處理器略板,我稱之為元預(yù)處理器毁枯。 PostCSS允許您編寫和共享自己的預(yù)處理器語法。 如果你想叮称,你可以重寫Sass或Less在PostCSS种玛,但有人已經(jīng)先行一步了。
循環(huán)條件
無限循環(huán)是一件很可怕的事情瓤檐。 如果你不小心赂韵,無限循環(huán)可能會(huì)減慢或讓你的編譯器崩潰。 這就是為什么循環(huán)應(yīng)該總是提供限制條件的目的 —— 通常由多個(gè)增量重復(fù)或?qū)ο蠹隙x挠蛉。
在編程術(shù)語中:
- while循環(huán)是通用的祭示,并且在滿足任何條件時(shí)將保持循環(huán)。 小心谴古! 這是無限循環(huán)最可能的地方质涛。
- For循環(huán)是增量式的稠歉,對(duì)于特定數(shù)量的重復(fù)運(yùn)行。
- For-Each循環(huán)遍歷集合或列表汇陆,一次一個(gè)地遍歷每個(gè)項(xiàng)目怒炸。
每種類型的循環(huán)比前面更細(xì)粒度。 一個(gè)for-each
循環(huán)只是一種for
循環(huán)瞬测,這也是一種while
循環(huán)横媚。 但是大多數(shù)的用例都屬于更具體的類別纠炮。 我很難在其他條件下尋找真正的while
循環(huán) —— 大多數(shù)例子可以更好地處理for
或for-each
月趟。 這可能是為什么Stylus
只提供后者的語法。 Sass為三種循環(huán)方式都提供了獨(dú)特的語法恢口,Less在技術(shù)上根本沒有循環(huán)語法 - 但這不會(huì)阻止我們孝宗! 讓我們深入探討一下。
for-each循環(huán)
預(yù)處理器循環(huán)在您有要循環(huán)的項(xiàng)目(列表或數(shù)組)(如社交媒體圖標(biāo)和顏色數(shù)組)或狀態(tài)修飾符列表(success
耕肩,warning
因妇,error
等)時(shí)最有用。 因?yàn)?code>for-each循環(huán)被綁定到已知的項(xiàng)目集合猿诸,它們往往是最具體和可理解的循環(huán)婚被。
讓我們從循環(huán)一個(gè)簡(jiǎn)單的顏色列表開始,看看它是如何工作的梳虽。
在Sass中址芯,我們將使用@each指令(@each $item in $list)來獲取顏色:
<div class="darkslateblue"></div>
<div class="mediumorchid"></div>
<div class="seagreen"></div>
<div class="steelblue"></div>
scss:
// colors
$colors: darkslateblue mediumorchid seagreen steelblue;
// loop!
@each $color in $colors {
.#{$color} {
background: $color;
}
}
// styles
body {
display: flex;
}
div {
flex: 1 1 auto;
height: 100vh;
}
在Stylus中,語法(for item in list)處理集合:
HTML:
<div class="darkslateblue"></div>
<div class="mediumorchid"></div>
<div class="seagreen"></div>
<div class="steelblue"></div>
Stylus
HTML Stylus Result
EDIT ON
// colors
colors = 'darkslateblue' 'mediumorchid' 'seagreen' 'steelblue'
// loop!
for color in colors
{'.' + color}
background: unquote(color)
// styles
body {
display: flex;
}
div {
flex: 1 1 auto;
height: 100vh;
}
VIEW COMPILED RERUN
Less不提供循環(huán)語法窜觉,但我們可以使用遞歸來模擬它谷炸。 遞歸是當(dāng)從內(nèi)部調(diào)用函數(shù)或mixin中發(fā)生的。 在Less中禀挫,我們可以使用mixins進(jìn)行遞歸:
.recursion() {
/* an infinite recursive loop! */
.recursion();
}
現(xiàn)在我們添加一個(gè)guard
到mixin
旬陡,以防止它無限循環(huán)。
.recursion() when (@conditions) {
/* a conditional recursive "while" loop! */
.recursion();
}
只要滿足條件(@i <= length(@list))语婴,我們就可以通過添加一個(gè)從1開始的計(jì)數(shù)器(@i) - 其中l(wèi)ength(@list)將我們的循環(huán)迭代限制為與我們的集合相同的長(zhǎng)度描孟。 如果我們?cè)诿看蝹鬟f中提取下一個(gè)列表項(xiàng),我們將有一個(gè)手動(dòng)的for-each循環(huán):
<div class="darkslateblue"></div>
<div class="mediumorchid"></div>
<div class="seagreen"></div>
<div class="steelblue"></div>
// colors
@colors: darkslateblue mediumorchid seagreen steelblue;
// loop definition
.backgrounds(@list, @i: 1) when (@i <= length(@list)) {
// extract the right color from the list
@color: extract(@list, @i);
// apply the background to the selector
.@{color} {
background: @color;
}
// recursive call for the next color
.backgrounds(@list, @i + 1);
}
// application
.backgrounds(@colors);
// styles
body {
display: flex;
}
div {
flex: 1 1 auto;
height: 100vh;
}
可以看出在Less中實(shí)現(xiàn)這一切是很困難的一種方式砰左。
社交媒體按鈕
循環(huán)遍歷列表可能很有用匿醒,但更多時(shí)候你想循環(huán)遍歷對(duì)象。 一個(gè)常見的例子是為社交媒體按鈕分配不同的顏色和圖標(biāo)菜职。 對(duì)于列表中的每個(gè)項(xiàng)目青抛,我們需要網(wǎng)站的名稱和該社交網(wǎng)絡(luò)的品牌顏色:
SCSS:
$social: (
'facebook': #3b5999,
'twitter': #55acee,
'linkedin': #0077B5,
'google': #dd4b39,
);
使用Sass
,我們可以使用語法@each $ key
酬核,$value in $array
訪問每個(gè)對(duì)的鍵(網(wǎng)絡(luò)名稱)和值(品牌顏色)蜜另。 這是完整的循環(huán):
HTML SCSS Result
EDIT ON
<ul class="social">
<li>
<a >
Facebook
</a>
</li>
<li>
<a >
Twitter
</a>
</li>
<li>
<a >
LinkedIn
</a>
</li>
<li>
<a >
Google+
</a>
</li>
</ul>
SCSS
// establish social media colors
$social: (
'facebook': #3b5999,
'twitter': #55acee,
'linkedin': #0077B5,
'google': #dd4b39,
);
// loop, to style social media links
@each $name, $color in $social {
// selector based on href name
[href*='#{$name}'] {
background: $color;
&::before {
content: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/15542/#{$name}.png);
}
}
}
// styles
ul {
margin: 0 auto;
max-width: 30rem;
}
a {
border: 4px solid black;
border-radius: 6px;
color: black;
display: block;
font-weight: bold;
margin: 0.25rem;
padding: 0.5rem;
text-decoration: none;
&::before {
display: inline-block;
vertical-align: middle;
margin: 0 0.5em;
}
}
Stylus 也有同樣的語法:for key, value in array
<ul class="social">
<li><a >Facebook</a></li>
<li><a >Twitter</a></li>
<li><a >LinkedIn</a></li>
<li><a >Google+</a></li>
</ul>
Stylus:
// establish social media color
ssocial = {
'facebook': #3b5999,
'twitter': #55acee,
'linkedin': #0077B5,
'google': #dd4b39,
}
// loop, to style social media links
for name, color in social
// selector based on href name
[href*={name}]
background: color
&::before
content: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/15542/' + name + '.png')
// styles
ul {
margin: 0 auto;
max-width: 30rem;
}
a {
border: 4px solid black;
border-radius: 6px;
color: black;
display: block;
font-weight: bold;margin: 0.25rem;
padding: 0.5rem;
text-decoration: none;
&::before {
display: inline-block;
vertical-align: middle;
margin: 0 0.5em;
}
}
在Less中适室,我們必須手動(dòng)提取對(duì)的每一邊:
html
HTML LESS Result
EDIT ON
<ul class="social">
<li>
<a >
Facebook
</a>
</li>
<li>
<a >
Twitter
</a>
</li>
<li>
<a >
LinkedIn
</a>
</li>
<li>
<a >
Google+
</a>
</li>
</ul>
LESS:
HTML LESS Result
EDIT ON
// establish social media colors
@social:
'facebook' #3b5999,
'twitter' #55acee,
'linkedin' #0077B5,
'google' #dd4b39,
;
// for loop to iterate over array
.each(@array, @i: 1) when (@i <= length(@array)) {
// extract social names and colors
@pair: extract(@array, @i);
@name: extract(@pair, 1);
@color: extract(@pair, 2);
// selector based on href name
[href*='@{name}'] {
background: @color;
&::before {
content: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/15542/@{name}.png');
}
}
.each(@array, @i + 1);
}
// application
.each(@social);
// styles
ul {
margin: 0 auto;
max-width: 30rem;
}
a {
border: 4px solid black;
border-radius: 6px;
color: black;
display: block;
font-weight: bold;
margin: 0.25rem;
padding: 0.5rem;
text-decoration: none;
&::before {
display: inline-block;
vertical-align: middle;
margin: 0 0.5em;
}
}
循環(huán)增量
For循環(huán)可以運(yùn)行重復(fù)任意數(shù)量,而不只是對(duì)象的長(zhǎng)度举瑰。 您可以使用它來創(chuàng)建網(wǎng)格布局(從1到12的列)捣辆,循環(huán)通過色輪(色調(diào)從1到360),或者為具有nth-child
和div
生成內(nèi)容編號(hào)此迅。
讓我們開始一個(gè)循環(huán)生成36個(gè)div
元素汽畴,每個(gè)div
提供數(shù)字和背景顏色,使用:nth-child
耸序。
Sass提供了一個(gè)特殊的for循環(huán)語法:@for $ count
從$ start
到$ finish
忍些,其中$ start
和$ finish
都是整數(shù)。 如果起始值較大坎怪,Sass將向下計(jì)數(shù)而不是向上計(jì)數(shù)罢坝。
代碼展位
through
關(guān)鍵字意味著我們的循環(huán)將包括數(shù)字36.您還可以使用to
關(guān)鍵字,其中不包括最終計(jì)數(shù)器:@for $i from 1 to 36
將只循環(huán)35次搅窿。
Stylus具有與遞增類似的語法嘁酿,但是to
和through
分別替換為...
和..
代碼展位
Stylus還提供了一個(gè)range()
函數(shù),它允許您更改一個(gè)增量的大小男应。 在范圍(0,360,10)中使用色調(diào)將在每次重復(fù)時(shí)將計(jì)數(shù)增加10闹司。
Less必須再次使用遞歸混合宏(recursive mixins)去實(shí)現(xiàn)。 我們可以為迭代次數(shù)(@i
)創(chuàng)建一個(gè)參數(shù)沐飘,使用 when(@i> 0)
限制條件游桩,并在每次迭代時(shí)減去一個(gè) —— 以使其像一個(gè)遞減的for-loop:
代碼展位
值得注意的是CSS
在沒有使用預(yù)處理器的情況下也可以給我們第n個(gè)子節(jié)點(diǎn)編號(hào)。 雖然CSS沒有循環(huán)結(jié)構(gòu)薪铜,但它確實(shí)提供了一個(gè)counter()
众弓,可以根據(jù)任何數(shù)量的DOM相關(guān)條件進(jìn)行遞增,并在生成的內(nèi)容中使用隔箍。 很遺憾谓娃,它不能在content
屬性之外使用,因此我們的背景顏色不適用:
代碼展位
每個(gè)網(wǎng)格跨度是一個(gè)百分比蜒滩,使用數(shù)學(xué)span / context * 100%
——所有網(wǎng)格系統(tǒng)必須進(jìn)行的基本計(jì)算滨达。 這里再次用Stylus和Less實(shí)現(xiàn)下:
代碼展位
代碼展位
定制頭像
在OddBird,我們最近設(shè)計(jì)了一個(gè)帶有默認(rèn)用戶頭像的應(yīng)用程序 - 但我們希望默認(rèn)值盡可能的唯一俯艰。 最后捡遍,我們只設(shè)計(jì)了九個(gè)獨(dú)特的圖標(biāo),并使用循環(huán)將它們轉(zhuǎn)換成1296個(gè)不同的頭像竹握,所以大多數(shù)用戶永遠(yuǎn)不會(huì)看到重復(fù)的頭像画株。
每個(gè)頭像有五個(gè)屬性:
代碼展位
- 起始圖標(biāo)形狀(9個(gè)選項(xiàng))
- 旋轉(zhuǎn)0,90,180或270度(4個(gè)選項(xiàng))
- 深色填充(6選項(xiàng))
- 淺色背景(6選項(xiàng))
- 反轉(zhuǎn)顏色的true / false屬性(2個(gè)選項(xiàng))
代碼有六種顏色和三個(gè)循環(huán):
@for $i from 0 through 3
給我們四個(gè)旋轉(zhuǎn)
@for $i from 1 through length($colors)
允許我們循環(huán)遍歷顏色列表($ colors
)谓传,并為每個(gè)顏色分配一個(gè)數(shù)字($
i)蜈项。 通常我會(huì)使用@each
循環(huán)遍歷顏色的集合,但是@for
是更簡(jiǎn)單的续挟,當(dāng)我需要一個(gè)數(shù)字紧卒,每個(gè)項(xiàng)目以及。
嵌套的@each $ reverse(true诗祸,false)
為我們提供了為每個(gè)顏色組合翻轉(zhuǎn)前景和背景的選項(xiàng)跑芳。
它最終在Sass中的結(jié)果為:
代碼展位
將它轉(zhuǎn)換為Less
和Stylus
都是一樣的套路,不再去過多展示了直颅。
通用while循環(huán)
真正的while
循環(huán)很少博个,但我偶爾使用它們。 我發(fā)現(xiàn)它們最有用的际乘,當(dāng)我順著一個(gè)路徑坡倔,看看它的根漂佩。 我不想循環(huán)遍歷整個(gè)集合或特定數(shù)量的迭代 - 我想保持循環(huán)脖含,直到我找到我想要的。 這是我在我的抽象工具包中使用的東西投蝉,但不是你在日常使用中非常需要的東西养葵。
我構(gòu)建了一個(gè)工具包來幫助我在Sass中存儲(chǔ)和操作顏色。 在變量中存儲(chǔ)顏色可能是任何預(yù)處理器最常見的用例瘩缆。 大多數(shù)人做這樣的事情:
代碼展位
我知道粉紅色可能不是你的網(wǎng)站上唯一的顏色关拒,但它是現(xiàn)在唯一一個(gè)現(xiàn)在就需要的。 我給它多個(gè)名稱庸娱,因?yàn)樗鼘?duì)于建立抽象層是非常有用的 - 從簡(jiǎn)單的顏色(粉紅色)着绊,更廣泛的模式(品牌主)和具體的用例(站點(diǎn)背景)。 我還想把單個(gè)顏色的列表轉(zhuǎn)換成我的預(yù)處理器可以理解的調(diào)色板熟尉。 我需要一種方式去表達(dá)這些值的相關(guān)性归露,并且是該模式的一部分。 這樣做斤儿,我在一個(gè)單獨(dú)的Sass地圖存儲(chǔ)所有我需要的主題顏色和鍵值對(duì):
為何這樣做剧包? 我這樣做,因?yàn)槲铱梢杂靡粋€(gè)單一的變量指向我的樣式指南生成器往果,并自動(dòng)創(chuàng)建一個(gè)保持更新的調(diào)色板疆液。 但是權(quán)衡利弊,這對(duì)于每個(gè)人來說并不是都是正確解決方案陕贮。 這個(gè)樣式圖不允許像我可以用變量一樣在對(duì)之間進(jìn)行直接賦值堕油。 我需要一個(gè)while
循環(huán)來跟蹤鍵名的痕跡,以便找到每種顏色的值:
展位圖
我一直這樣做,但如果你搜索我的代碼為Sass
的@while
掉缺,你會(huì)找不到它福也。 這是因?yàn)槟憧梢杂眠f歸函數(shù)實(shí)現(xiàn)同樣的事情,使其可重用:
展位圖
現(xiàn)在我們可以在代碼中的任何地方調(diào)用color()
函數(shù)攀圈。
Stylus沒有while
循環(huán)的語法暴凑,但它也允許數(shù)組變量和遞歸函數(shù):
展位圖
Less沒有內(nèi)置的數(shù)組變量,但我們可以通過創(chuàng)建一個(gè)對(duì)列表來模仿相同的效果赘来,就像我們對(duì)社交媒體顏色所做的一樣:
展位圖
我們必須創(chuàng)建自己的 @ array-get mixin
來使用鍵名從數(shù)組中檢索值现喳,然后創(chuàng)建我們的遞歸while
循環(huán)以遵循以下路徑:
展位圖
這適用于演示的目的,但在Less也許有一個(gè)更好的方法來做這個(gè)犬辰,因?yàn)槟憧梢允褂脛e名和命名空間變量而不使用數(shù)組(不像Sass或Stylus):
展位圖
現(xiàn)在顏色可以用一個(gè)變量去成功實(shí)現(xiàn)嗦篱,我可以使用另一個(gè)循環(huán)來生成我的調(diào)色板。 這里有一個(gè)快速示例Sass:
展位圖
我相信你可以比我做的更好幌缝。
總結(jié)
如果你不確定什么時(shí)候在代碼中使用循環(huán)灸促,請(qǐng)留意重復(fù)。 你有多個(gè)選擇器遵循類似的模式涵卵,或一個(gè)計(jì)算你一直在做浴栽? 以下是如何判斷哪個(gè)循環(huán)是最好的:
如果你可以列出和命名循環(huán)中的項(xiàng)目,使用for-each
循環(huán)遍歷它們轿偎。
如果重復(fù)次數(shù)比任何源項(xiàng)目集更重要典鸡,或者如果您需要您的項(xiàng)目編號(hào),請(qǐng)使用for
循環(huán)坏晦。
如果您需要訪問具有不同輸入的相同循環(huán)萝玷,請(qǐng)嘗試使用遞歸函數(shù)。
對(duì)于任何其他(幾乎從不)昆婿,使用while
循環(huán)球碉。
如果你使用較少...祝你好運(yùn)!
Have fun looping!