Stylusで連番のクラスと連番の背景を作る

目次
  1. 1. こんな CSS を書きたい
  2. 2. 連番のゼロ埋めをどうするの問題
  3. 3. 力技で、ゼロを埋める
  4. 4. Stylus では、値に対してはインターポレーションは必要ないはずだが…
    1. 4.1. 歯抜けの連番をどうするか
    2. 4.2. まとめ

こんな CSS を書きたい

  • 各要素の頭に、アイコン画像を設置したい
  • アイコン画像の末尾は連番、ただし、一部歯抜けで2桁のゼロ埋め

こんな感じです。

イメージする CSS のアウトプットは、こんな感じ。

1
2
3
4
5
6
7
8
9
.hoge-01 {
background: url(/img/hoge/hoge-01.jpg) 0 0 no-repeat;
}

.hoge-02 {
background: url(/img/hoge/hoge-02.jpg) 0 0 no-repeat;
}

/* 以下続く */

今仕事している環境では、生の CSS で書かないといけないので、Codepen か WebMaker の Stylus でサクっとループ回したろうかいな、と思ったら一筋縄でいかなかったので、メモ。

連番のゼロ埋めをどうするの問題

Stylus の公式を読むと、iteration する際の連番は、こう書くようだ。

1
2
3
body
for num in (1..5)
foo num

今回はゼロ埋めをしたかったので、こう書いてみた

1
2
3
for i in (01..10)
.hoge-{i}
background url(/img/hoge/hoge-i.jpg) 0 0 no-repeat;

すると、出力されたのは、

1
2
3
4
5
6
7
8
.hoge-1 {
background: url(/img/hoge/hoge-i.jpg) 0 0 no-repeat;
}

.hoge-2 {
background: url(/img/hoge/hoge-i.jpg) 0 0 no-repeat;
}
/* 以下続く */

こんな感じ。

これだと、

  • セレクタはゼロ埋めされていない
  • 背景画像が正しく呼び出されていない

の二重苦。

とにかく、まずは連番のゼロ埋めをどうにかしたい。

力技で、ゼロを埋める

ゼロ埋めについて英語でググってみたりした(Stylus varibale zerofill など)ものの、最適解が出てこないので、自分の頭を使って凌いでみた。

とりあえず mixin にしてみる。mixin は、プログラム言語でいうところの、関数に相当する。

1
2
3
4
5
6
7
8
9
10
11
12
13
icons(i,zerofill)
if(zerofill == TRUE)
.hoge-0{i}
background: url(/img/hoge-0i.jpg) 0 0 no-repeat;
else
.hoge-{i}
background: url(/img/hoge-i.jpg) 0 0 no-repeat;

for i in (1..20)
if(i<=09)
icons(i, TRUE)
else
icons(i, FALSE)

ここでは、icons という mixin を作ってみた。第 1 引数に連番を、第 2 引数で、頭 1 桁をゼロで埋めるか否かを Boolean で設定している。

出力結果はこんな感じ。

1
2
3
4
5
6
7
8
9
.hoge-01 {
background: url(/img/hoge-0i.jpg) 0 0 no-repeat;
}

/* 以降、.hoge-09まで続く */

.hoge-10 {
background: url(/imge/hoge-i.jpg) 0 0 no-repeat;
}

これで、セレクタは意図通りになった。

あとは、background プロパティの URL 値だ。変数 i が、変数名のまま出力されているのをどうにかしないといけない。

Stylus では、値に対してはインターポレーションは必要ないはずだが…

Stylus の公式を注意深く読んで見る。上記例でも書いているが、セレクタに対して変数を与えたい場合は、{}でくくる、いわゆるインターポレーションが必要。

ただし、値に対してはそのような必要はないはずだ。

例えば、

1
2
3
4
colorRed = #f00

body
color colorRed

上記の出力結果はこうなる

1
2
3
body {
color #f00
}

つまり、値に対して、インターポレーションは不要というはずだ。

ただ、上記で私がやろうとしていたことは、通常の値と変数名を分け隔てなく交ぜ書きにしてしまっている。

ここになにかポイントがありそうだ。

そして、次のように書いてみた。

1
2
3
4
i = 1

.hoge-{i}
background url(/img/hoge/hoge- + i + .jpg) 0 0 no-repeat

しかし、これはコンパイル時点でエラーとなった。

次にこう書いてみる。

1
2
3
4
i = 1

.hoge-{i}
background 'url(/img/hoge/hoge-' + i + '.jpg) 0 0 no-repeat'

こちらはコンパイルされたが…

1
2
3
.hoge-1 {
background: 'url(/img/hoge/hoge-1.jpg) 0 0 no-repeat'
}

と、プロパティ値の前後にシンプルクォーテーションが入ってしまい、正しい CSS とはならない。

結局、紆余曲折の結果、下記のようにして、プロパティ値に対して、変数を混ぜ書きにすることができた。

1
2
3
4
i = 1

.hoge-{i}
background url(\/img/hoge/hoge- + i + \.jpg) 0 0 no-repeat

と、書くと、

1
2
.hoge-1
background: url(/img/hote/hoge-1.jpg) 0 0 no-repeat

とにかく、変数の前後を文字列とし + で挟み、文字列の頭にはエスケープの\をつけておけば良いようだ。

歯抜けの連番をどうするか

今回の要件では、連番ではあるものの、欠番がある連番という要件だった。

歯抜け連番は以下のような感じ

  • 1
  • 2
  • 3
  • 4
  • 5
  • 7
  • 8
  • 9
  • 10
  • 12
  • 13
  • 15
  • 17
  • 18
  • 19
  • 20
  • 21
  • 30
  • 32
  • 33
  • 34
  • 36
  • 38

こんな感じで、中途半端に歯抜けている。

for 文で回したあと、条件分岐を書いてみたりしたが、条件分岐の数が半端ないので、シンプルに連番ではなく、配列にしてみた。

最終的なアウトプットは以下の通り

まとめ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
icons(i, zerofill)
if(zerofill == TRUE)
.hoge-0{i}
background url(\/img/hoge/hoge-0 + i + \.jpg) 0 0 no-repeat
else
.hoge-{i}
background url(\/img/hoge/hoge- + i + \.jpg) 0 0 no-repeat

list = 1 2 3 4 5 7 8 9 10 12 13 15 17 18 19 20 21 30 32 33 34 36 38

for i in list
if (i < 10)
icons(i, TRUE)
else
icons(i, FALSE)

これのアウトプットは下記の通り

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
.hoge-01 {
background: url("/img/hoge/hoge-01.jpg") 0 0 no-repeat;
}
.hoge-02 {
background: url("/img/hoge/hoge-02.jpg") 0 0 no-repeat;
}
.hoge-03 {
background: url("/img/hoge/hoge-03.jpg") 0 0 no-repeat;
}
.hoge-04 {
background: url("/img/hoge/hoge-04.jpg") 0 0 no-repeat;
}
.hoge-05 {
background: url("/img/hoge/hoge-05.jpg") 0 0 no-repeat;
}
.hoge-07 {
background: url("/img/hoge/hoge-07.jpg") 0 0 no-repeat;
}
.hoge-08 {
background: url("/img/hoge/hoge-08.jpg") 0 0 no-repeat;
}
.hoge-09 {
background: url("/img/hoge/hoge-09.jpg") 0 0 no-repeat;
}
.hoge-10 {
background: url("/img/hoge/hoge-10.jpg") 0 0 no-repeat;
}
.hoge-12 {
background: url("/img/hoge/hoge-12.jpg") 0 0 no-repeat;
}
.hoge-13 {
background: url("/img/hoge/hoge-13.jpg") 0 0 no-repeat;
}
.hoge-15 {
background: url("/img/hoge/hoge-15.jpg") 0 0 no-repeat;
}
.hoge-17 {
background: url("/img/hoge/hoge-17.jpg") 0 0 no-repeat;
}
.hoge-18 {
background: url("/img/hoge/hoge-18.jpg") 0 0 no-repeat;
}
.hoge-19 {
background: url("/img/hoge/hoge-19.jpg") 0 0 no-repeat;
}
.hoge-20 {
background: url("/img/hoge/hoge-20.jpg") 0 0 no-repeat;
}
.hoge-21 {
background: url("/img/hoge/hoge-21.jpg") 0 0 no-repeat;
}
.hoge-30 {
background: url("/img/hoge/hoge-30.jpg") 0 0 no-repeat;
}
.hoge-32 {
background: url("/img/hoge/hoge-32.jpg") 0 0 no-repeat;
}
.hoge-33 {
background: url("/img/hoge/hoge-33.jpg") 0 0 no-repeat;
}
.hoge-34 {
background: url("/img/hoge/hoge-34.jpg") 0 0 no-repeat;
}
.hoge-36 {
background: url("/img/hoge/hoge-36.jpg") 0 0 no-repeat;
}
.hoge-38 {
background: url("/img/hoge/hoge-38.jpg") 0 0 no-repeat;
}

無事、目的どおりに意図されたコードが出力できた。

連番の CSS 出力は、mixin をうまく使って、省力化できる。使い所を知っておいて損はないと思う。

この記事が参考になったら、シェアお願いします!