いまさらCSS/SassでFizzBuzz〜数字も出力した

# はじめに
みんなご存知**FizzBuzz** [(Wikipedia)](https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiG5M_os5XQAhUKgbwKHS6SBZ0QFggdMAA&url=https%3A%2F%2Fja.wikipedia.org%2Fwiki%2FFizz_Buzz&usg=AFQjCNG4qweRnyK6inuApzDvJrxMzNztMA)を、CSSメタ言語が普及した現在だとどうなるのか今更やってみた。

## 条件
> 1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに｢Fizz｣と、5の倍数のときは｢Buzz｣とプリントし、3と5両方の倍数の場合には｢FizzBuzz｣とプリントすること。
[どうしてプログラマに・・・プログラムが書けないのか?]
(http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm) - Jeff Atwood / 青木靖 訳

CSSはプログラムじゃないので直接HTMLを出力できないため、特別条件をプラスする。
・ HTMLは先に与えられてる
・ SEO、セマンティクス、アクセシリビティなどは無視する

HTMLは以下とする。

```HTML:emmet
ul>li{i}*100 <!-- 数字付き -->

ul>li*100    <!-- 数字なし -->
```


# CSSでFizzBuzz
CSSで行う場合、
1. 擬似クラス:nth-child(:nth-of-type)を使う
2. **先に表示されてる数字をどのように消すか**
がポイントになる。


## font-sizeでいらない数字を消す
```HTML:emmet
ul>li{i}*100
```

```scss:css
// 3の倍数と5の倍数のフォントサイズを0にして見えなくする。
li:nth-child(3n),
li:nth-child(5n){ font-size: 0; }

// 擬似要素に文字を入れる。フォントサイズを戻せば見えるようになる。
// ::beforeと::afterに分けることで、公倍数のときは両方が表示される。
li:nth-child(3n)::before {content: "Fizz"; font-size: 1rem;}
li:nth-child(5n)::after  {content: "Buzz"; font-size: 1rem;}  
```

## counter-incrementで数字も出力する
数字を出す方法を調べてるとCSSカウンタ **[counter-increment](https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Counters)**というものを見つけた。
使い道はまだよくわからない…。

```HTML:HTML(emmet)
ul>li*100
```

```scss:css
// 1)::beforeにカウンタセット
ul { counter-reset: num;} // カウンタリセット 
li { counter-increment: num;} // numカウンタを増やしていく
li::before { content:counter(num) ""; }// li::beforeにカウンタ数表示

// 3) 5の倍数の::beforeが残るので空contentにして消す。
// "Fizz"を出力する前に消さないと3*5の倍数の時に"Fizz"が消えるので注意。
li:nth-child(5n)::before  { content: "";}

// 2) ３の倍数の::before、5の倍数::afterにそれぞれ"Fizz"、"Buzz"を入れる。
// ３の倍数の::beforeは"Fizz"に上書きされるのでOK。
li:nth-child(3n)::before { content: "Fizz";}
li:nth-child(5n)::after  { content: "Buzz";}
```


**記述順に依存してるのがとても怖い。**

## 【未来】list-style-type: \<string\>が使える、ようになるかも
- [list-style-typ - CSS | MDM](https://developer.mozilla.org/ja/docs/Web/CSS/list-style-type)
> \<string\>
特定の文字列を、リストのマーカーとして使用します。

- [CSS Lists and Counters Module Level 3](https://drafts.csswg.org/css-lists-3/#list-style-type)

```ul -> ol```　にしてビュレットの数字を3n,5n,3*5nの時にstringにすればできそう。
残念ながらまだ草案で実装ブラウザないみたい？



# SassでFizzBuzz
メタ言語になると制御構文（if,each,while…）が使えるのでやれることが広がる。

## よくある余剰で解く方法
スタイルシート感はゼロ。

```scss:scss
@for $i from 1 through 100 {
  // 条件分岐で表示するものを出し分ける
  @if $i % (3 * 5) == 0 {
    li:nth-child(#{$i})::before {content: "FizzBuzz";}
  }
  @else if $i % 3 == 0 {
    li:nth-child(#{$i})::before {content: "Fizz";}
  }
  @else if $i % 15== 0 {
    li:nth-child(#{$i})::after  {content: "Buzz";}
  }
  @else {
     li:nth-child(#{$i})::before {content: "#{$i}";}
  }
}
```


## list(配列)使う方法
1〜15番目までの並びを繰り返していくので、配列にして取り出していく方法があると聞いた。
Sassでも配列と同じ機能（list,map）があるのでやってみた。

が、```nth($list, $n)```が0だとerorrが返ってくる仕様との戦いになってつらい。
拡張したところでスタイルシートはプログラム言語じゃない現実がつらい。


```scss:scss
// 3n,5n,3*5n番目には文字、それ以外は空欄のリストをセットする。
$list : "","","Fizz","","Buzz","Fizz","","","Fizz","Buzz","","Fizz","","","FizzBuzz";
```

```scss:scss
@for $i from 1 through 100 {
  // リストの長さ（15=3*5)
  $length: length($list);
  // contentに入れる値。先に書いておかないとスコープが働いてエラーになる★つらい★
  $content: "";

  // 余剰を使って割り当てる。
  // でも割り切れる（== 0）とエラーになるからその時だけ別の処理をする★つらい★

  // リストの長さ（3*5=15）で割り切れない時 → 配列の値をそのままいれる
  @if $i % $length != 0 {
    $content: nth($list, $i % $length);
  } 
  // 割り切れる時　→　$length(=１５番目)の値を入れる
  @else {
    $content: nth($list,$length);
  }
  
  // $contentが空欄""じゃないときはそのままリストの文字を表示させる
  @if $content != "" {
    li:nth-child(#{$i})::before {content: "#{$content}";}
  } 
  //　$contentが空欄""の時は$iの数字を表示させる
  @else {
    li:nth-child(#{$i})::before {content: "#{$i}";}
  }
}
```

割り切ってもnthが0にならないように1を足すとちょっとスッキリした。

```scss
@for $i from 0 through 100 {
  $content: nth($list, $i % 15 + 1);
  @if $content != "" {
    li:nth-child(#{$i + 1})::before {content: "#{$content}";}
  } 
  @else {
    li:nth-child(#{$i + 1})::before {content: "#{$i + 1}";}
  }
}
```

# さいごに
あんまり使わない機能を知る良い勉強になった。
listを使う方法は、パターンが決まってる値を無限に繰り返したい時があれば使えるかも？。
mixinを駆使する方法もあるようなので随時試してみたい。