ぼくがNES.cssから学んだこと(後編)

これは、「[ぼくがNES.cssから学んだこと(前編)](https://qiita.com/qei/items/9f18c36552366c881d90)」の後編になります。

## 前回のあらすじ
マリオはCSSで出来ている。

## NESS.cssで行なっている描画の仕組み
<img width="1121" alt="code.png" src="https://qiita-image-store.s3.amazonaws.com/0/219810/7ff5c06e-c51a-5d2b-c0be-e2bc3a46d176.png">

「[NES.css](https://github.com/nostalgic-css/NES.css)」でドット絵を表現していて、そのスタイルの中身をみてみると`color`と`box-shadow`を使っていることがわかりました。
しかし、`color`は文字色を指定するのに使うし、`box-shadow`と聞くとボタン等の矩形状に影をつけるのに使うのですが、どういう仕組みで表現しているのでしょうか？

### box-shadow プロパティについて
前述したように、`box-shadow`プロパティはその字の通り、矩形ベースで影を落とすことができます。

[box-shadowプロパティ (MDN web docsより)](https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow)
  
これによると、
**(1) 最初の2つ数値指定で、X・Y方向に影のオフセット(位置をずらす)**
(2) 3つ数値指定された場合、３つ目はぼかし半径
(3) 4つ数値指定された場合、4つ目は拡散半径
とのことで、それに色もパラメータに加えて影の色を指定したり、
**カンマ区切りで複数の影を当てることができます**。

```css
/* (1) X方向に4px、Y方向に8px影をオフセット */
box-shadow: 4px 8px;

/* (2) X方向に4px、Y方向に8pxオフセットして、影にぼかしを2px分かける */
box-shadow: 4px 8px 2px;

/* (3) X方向に4px、Y方向に8pxオフセットして、影にぼかしを2px分、6px分拡散させる */
box-shadow: 4px 8px 2px 6px;
```
ここでキーになるのは、**(1)のぼかしをかけないオフセット**、そして**カンマで複数の影をつける**ところにあります。

### box-shadow を使った描画
では、先の`box-shadow`プロパティの仕様に則して、簡単なhtmlを作ってみます。

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Box Shadow Test</title>
    <style>
      div:after{
        width: 20px; /* 影のサイズ。これを入れないと表示されない */
        height: 20px; /* 影のサイズ。これを入れないと表示されない */
        content: '';
        display: block;
        color: #f00; /* 影の色指定 */
        box-shadow: 20px 20px, 40px 40px, 60px 60px;
        /* 以下のように個別に色指定する書き方もOK */
        /*box-shadow: 20px 20px #f00, 40px 40px #f00, 60px 60px #f00;*/
      }
    </style>
  </head>
  <body>

    <div></div> 

  </body>
</html>
```

NES.cssのドット絵のように、ここではdivタグの擬似要素(after)に対しスタイルを適用しています。`width`・`height`で影のサイズを指定(他に表示されるにあたり`content`と`display`の指定も必要)し、`box-shadow`でX・Y方向のオフセットのみ・影をかけたい箇所を3箇所にするのにカンマ区切りにしています。
影の色は`box-shadow`でも設定できますが、一律同じ色にする場合実は`color`プロパティで設定できます。個別に影を指定するならコメントアウトしているように`box-shadow`プロパティ上で色を指定するのもOKです。

すると、ブラウザで表示させると、以下のような20px四方の四角形の連なりができています。

<img width="174" alt="result.png" src="https://qiita-image-store.s3.amazonaws.com/0/219810/36674709-9bc6-0db8-9865-ba1c9d9e6f9f.png">

ちなみに、`color`でなく`background`で色指定を行うと、オフセットのない領域(上画像だと最左上の少し空いている部分)に色がつきます。これはbox-shadowがかかっていない、単純なafter擬似要素で作った領域を塗りつぶすようです(以下画面は`background`で緑色を指定、右から2つ目のドッドを`box-shadow`で個別に色を塗ったもの)。

```css
      div:after{
        width: 20px;
        height: 20px;
        content: '';
        display: block;
        color: #f00;
        background: #0f0;
        box-shadow: 20px 20px, 40px 40px #00f, 60px 60px;
        /* box-shadow: 20px 20px #f00, 40px 40px #f00, 60px 60px #f00; */
      }
```

<img width="217" alt="result_2.png" src="https://qiita-image-store.s3.amazonaws.com/0/219810/214cfcdc-cd21-701f-fc68-1134ca07d366.png">

これをいくつも影をつなげ時に色を変えることでドット絵的な見せ方をしているわけですね。
`border`で三角形を作る要領にも近く、CSSはアイディア次第でプロパティ名に即した使い方以外のアプローチができます。


## それ CSS Paint で出来...?
ますん。。というのが現時点の仕様を鑑みた個人的見解です。
[CSS Paint API](https://developers.google.com/web/updates/2018/01/paintapi) とは、JSを使ってグラフィックを背景画像を描ける仕様になっていて、Canvas描画と同じような記述で、かつ通常のCanvasと違ってcanvasタグ以外でも使えるのが特徴的です。

[どんな背景でも自由に描ける! CSS Paint APIの使い方](https://ics.media/entry/18733)

これを使えば自由にドット絵を描けそうだと思ったものの、
2018年12月時点の対応ブラウザが以下になっています...

<img width="1095" alt="can i use.png" src="https://qiita-image-store.s3.amazonaws.com/0/219810/baa4bed6-068b-ab0c-ece9-8341f8933b19.png">
[Can I Use](https://caniuse.com/#search=CSS%20Paint)

Chromeおよび息のかかったAndroid系ブラウザ以外全滅となっています。
これらのブラウザ限定であればそれでも良いのですが、サポートブラウザの広範性も求められる点から実用化されるのはまだ先になりそうです。

## メリット・デメリット

`color`と`box-shadow`を使った描画によって、考えられるメリット・デメリットを整理しました。

### 【メリット】

- **ドット絵画像のアセット精査**
CSSとして書けるものであれば、画像ファイルとして用意するのは不要になりそうです。

- **リクエスト数の削減**
上記に関連して、画像アセットファイルが減る事でリクエスト数を削減することができそうです。
画像ファイルは減らせる分には減らした方がいいですが、スタイルについてはリセットCSS含め最低限ファイルが必要なためその中に含められるならそうした方が良さそうです。

- **読み込み表示スピードの向上？**
こちら仮説ではありますが、CSSで描画することから画像のリクエスト・描画に比べ比較的早く表示されるのではと推察しています。とはいえ、`box-shadow`による処理負荷自体にもよります。

- **ユーザインターフェース(UI)要素のカスタマイズ**
ドット絵にターゲットを置いてきましたが、これまで若干細かめのデザインをしたボタンとかは画像化する必要がありましたが、`box-shadow`で点描できる点を活用して、CSSでより細かいデザインをカバーすることもできそうです。

### 【デメリット】

- **コードベース管理になる煩雑性**
`box-shadow`で座標指定するため、作るサイズや粒度によって長大な記述になりそうに思われます。また、作った絵に微調整が入った際の更新性も。逆にコードだからこそルールを知っていたら誰でも扱える利点も秘めています。

- **CSSファイルサイズの増大**
こちらも作るドット絵のサイズやドットの粒度によって記述が増え、結果全体のCSSファイルのサイズが大きくなる点も考えられます。合わせて、それなら各ドット絵ごとにコンポーネント別に管理するのか、scss/stylusファイルとして分けて管理するのか、スタイルの管理方針も検討が必要になりそうです。

- **ベクターイメージには負ける**
ドット絵や多少粒度の細かいグラフィックであればある程度できそうなものの、曲線の輪郭をジャギらないようにしたいのであれば、やはりSVGのようなベクターイメージになりそうではあります。  

## まとめ

CSSだけでちょっとしたドット絵や装飾を作るにあたり、`color`と`box-shadow`が有効に思えました。
ただ、手打ちで作成・調整するのも大変なので、また近日番外編としてそのツールを作ってみようと思います(年内までに)。ツール名は「Shadow Paint Generator」(仮)で考えてます。

【番外編】
https://qiita.com/qei/items/105319ced192af566f74