HTML/CSSで書籍の図を作ってみた

この記事は [CSS アドベントカレンダー 2019](https://qiita.com/advent-calendar/2019/css)の19日目の記事です。

フリーランスでデザインやイラストをしている becolomochi と申します。
HTML/CSS で書籍の図を作ったので、図版担当の視点で作成時のテクニック的なものを書きます。

ざっくり言うと、こういう図を作りました。
<img width="941" alt="スクリーンショット 2019-12-19 0.07.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/207a3fe6-650d-2536-8b28-2cd57b0cf013.png">


## 何の本か ＆ なぜやるのか

プログラミング初学者向けの書籍 『[Railsの教科書](https://tatsu-zine.com/books/rails-textbook)』（著者：五十嵐邦明さん  発行：達人出版会さん）を Rails のバージョンアップで改訂するため、このタイミングで図を HTML/CSS で書き換えたいとのことでした。

以下のリンクで現在改訂中の内容を見ることができます。

- [Rails Textbook](http://igarashikuniaki.net/rails_textbook/)
- [igaiga/rails_textbook](https://github.com/igaiga/rails_textbook) GitHub

### メリット

HTML/CSS で図を書くメリットとしては、

- 図のパーツをコードで管理できるので管理が楽（な気がしました。）
- コードなので差分を GitHub で確認しやすい
- ベースをデザイナーが作る必要はあるが、HTML がわかれば分担できる
- 今後の改版で図を直す必要が出てきても著者さん側で直接修正できる

『Railsの教科書』では HTML/CSS で作成した図はだいたい40個くらいあったようです。
※数え間違いしていなければ……
デザイナーの私がベースとなる20個程度を作成し、残りの半分の図をコピペと調整で著者さんが作成しています。

技術系同人誌の図の作成でも便利そうです〜


### デメリット

デメリットを挙げるとすると、

- 複雑な図は作れない（なので、Illustrator で作った画像もあります）
- できあがった図はカラーモードが RGB なので紙版をフルカラーで印刷する場合は色味が変わってしまう

が挙げられるかなと思います。


## HTML を画像化にするには

1. **HTML/CSS で図をつくる** <- この記事ではここについて書きます。
2. selenium-webdriver + Headless Chrome でスクショを保存（すばらしき自動化〜〜）
3. 図が中央に来るようにトリミング（これからの作業になります※12/19現在）


## HTML/CSS で図をつくる

Headless Chrome ということで、Chrome で表示さえきちんとできていれば問題ない！
クロスブラウザとか気にしなくて済む！
普段のコーディング作業から比べると安心して進められたと感じていますw

### サンプル

私が作った部分のコミットコメントがダサダサでお恥ずかしいのですが、
GitHub のこのディレクトリ以下に図が入っています。
[rails_textbook/\_figures/assets at master · igaiga/rails_textbook](https://github.com/igaiga/rails_textbook/tree/master/_figures/assets)

- 図のサンプル一覧を作りました。[figure-sample.html](https://github.com/igaiga/rails_textbook/blob/master/_figures/assets/figure-sample.html) clone なりしていただけると見れます。
- CSS は SCSS で gulp でコンパイルしています（相談して一番慣れているやり方にさせてもらいました）

### デザイナーとして個人的に気をつけたこと

- テキストの増減にも耐えられるであろう CSS にする
- CSS でトリッキーな装飾はしない
- 必要に迫られたときだけ絶対値指定する。その場合は HTML 側で style 属性を使う

2つ目は、今後ブラウザのバージョンが上がったときに表示が崩れる可能性あるためなのですが、
正直なところ今後どうなるか少し心配しています……
3つ目は、矢印の位置を合わせたいときにやってみています。
今後もし位置の調整をしたいときにわざわざ SCSS をいじらなくても済みます。

例えばこれで矢印になるのですが、（[コード全体はこちら](https://github.com/igaiga/rails_textbook/blob/master/_figures/assets/new-create/new_view_form_memo_html.html)）

```html
<div class="arrow-right is-memo arrow-right__position" style="top: 170px;"></div>
```

style 属性で、親要素を基準にして上から170pxのところに来るように絶対値指定しています。

![アートボード 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/d2e5315a-f5ca-78c7-d1bb-a995399e9594.png)


## CSSで矢印を作る

さきほどの図で矢印を例に出しましたが、
div に付与した3つのクラスにはそれぞれ以下のような装飾を持たせています。

- `arrow-right` 矢印の形状を指定するクラス
- `is-memo` メモ用の色（水色）を指定クラス
- `arrow-right__position` 位置を絶対値指定する必要があるときのクラス

これがかいてあるコードはココです。
[rails_textbook/\_arrow-right.scss at master · igaiga/rails_textbook](https://github.com/igaiga/rails_textbook/blob/master/_figures/assets/scss/item/_arrow-right.scss)

`arrow-right`クラスの矢印の形状を作るのは before と after の疑似要素で作りました。
画像よりコードのほうが大きさや色を変えるときに簡単ですし。
上記リンクから必要なところだけ抜き出したものは以下です。

```scss
$arrow-right-width-value: 30px;
$arrow-right-height-value: 50px;

.arrow-right {
  height: $arrow-right-height-value;
  &::before, &::after {
    display: inline-block;
    content: '';
  }
  &::before {
    // 胴体の棒の部分
    width: $arrow-right-width-value + $arrow-right-height-value;
    height: 45%;
    background: $arrow-color;
  }
  &::after {
    // 三角の部分
    width: $arrow-right-height-value;
    height: $arrow-right-height-value;
    border: $arrow-right-height-value / 2 solid transparent;
    border-left-color: $arrow-color;
    margin-bottom: - $arrow-right-height-value / 4;
  }
}
``` 

変数も多くだらだらと長いので分割して見てみます。

### SCSSを細かく見てみる

```scss
$arrow-right-width-value: 30px;
$arrow-right-height-value: 50px;
```

で、一応でですが縦と横の初期値を設定しています。

```scss
  height: $arrow-right-height-value;
  &::before, &::after {
    display: inline-block;
    content: '';
  }
```

ここで矢印全体の高さを設定し、beforeとafterの疑似要素を召喚しました。
（display プロパティは block でもいいのですが、他でインラインにする必要があってこうなっています）

```scss
  &::before {
    // 胴体の棒の部分
    width: $arrow-right-width-value + $arrow-right-height-value; // こう書かなくても良かったかも…
    height: 45%;
    background: $arrow-color;
  }
```

before 疑似要素で棒の幅と高さ、色を指定しています。
幅は `width: $arrow-right-width-value` でシンプルに書けば良さそうです。

```scss
  &::after {
    // 三角の部分
    width: $arrow-right-height-value;
    height: $arrow-right-height-value;
    border: $arrow-right-height-value / 2 solid transparent;
    border-left-color: $arrow-color;
    margin-bottom: - $arrow-right-height-value / 4;
  }
```

最後に after 疑似要素で三角の部分を表現しています。
高さの変数 `$arrow-right-height-value` を基準にして、正方形のボックスを作り、正方形の半分のサイズの透明のborderを指定し、leftだけ色を付けると三角が現れます。

リセット CSS は [ress](https://github.com/filipelinhares/ress) を使っているので、以下が効いてます。

```
box-sizing: border-box;
```

これをつけるとボックスの内側に border がつくので、上のサンプルがちゃんと矢印風の表示になってくれます。
疑似要素ごとに分解するとこんな感じになっています。
<img width="1234" alt="スクリーンショット 2019-12-18 23.03.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/c1a94223-b6f6-69b0-0822-9d8325f3ddb9.png">


## パーツの半透明化

説明する部分を強調するため、他のパーツを半透明にできます。

以下の図は Controller を説明するときの図です。
<img width="638" alt="スクリーンショット 2019-12-18 23.24.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/8e34b119-187d-b085-e305-39ab012a91fe.png">

サンプルHTML

```html
<div class="box opacity">
  <h2 class="box__headline">リクエスト</h2>
  ...
</div>
```


SCSSはこれ

```css
.opacity {
    opacity: 0.3;
}
```

`opacity` というクラスをつけるだけで半透明化するようになりました。簡単ですね！




## 矢印の長さをボックスの長さに追随させる

右側の赤い矢印にご注目ください。
<img width="626" alt="スクリーンショット 2019-12-18 23.15.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/6cf89d75-3322-5363-5369-7705863365f1.png">
内容が増えても伸びるようにしました。
<img width="631" alt="スクリーンショット 2019-12-18 23.14.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/0a4dd0a6-7227-5cd2-756c-2018f2e1c701.png">

サンプルHTML

```html
<div class="wrapper">

<div class="box">
  <h2 class="box__headline">リクエスト</h2>
  ...
</div>

<div class="box app-box relative">
  <h2 class="box__headline">Rails App</h2>
  ...

  <div class="arrow arrow__position-right-top"></div>

</div>

<div class="box">
  <h2 class="box__headline">レスポンス</h2>
  ...
</div>
</div>
```

SCSS

```scss
.arrow__position-right-top {
  // 右上から大きく表示する
  $position-value: -40px;
  position: absolute;
  right: 20px;
  top: $position-value;
  height: calc(100% - #{$position-value * 1.6});
}
```

親要素を基準にして、矢印の位置と矢印の長さを調整できるようにしました。

## ファイル構造を作る

<img width="482" alt="スクリーンショット 2019-12-18 23.33.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/0df1efc9-33e2-e3d3-e8e9-a2ed4b97d511.png">

アイコンは [Font Awesome](https://fontawesome.com) のアイコンです。色をつけると見違えるように図っぽくなりますね。
ファイル構造は当初 ul の入れ子で書いてみたところ、入れ子になりすぎてぱっと見て理解しづらくなってしまったため、div 要素で囲んで margin-left をつけて疑似的な階層をつくりました。Web サイトならコードの意味が大事なのでサイトを作る場合は真似しないでください…⚠️

サンプル HTML

```html
<div class="files__column">
    <div class="files__item is-1">
      1階層
    </div>
    <div class="files__item is-2">
      2階層
    </div>
    <div class="files__item is-3">
      3階層
    </div>
    ...
</div>
```

## まとめ

HTML/CSS で図を作るなんてなかなか無い案件なのでめちゃくちゃ楽しかったです!!!
ちょっと大変だなーと思ったのが、図の中にコードを載せることですね。
タグのエスケープが必要になる箇所を、量がそれほど多くないからと手動で書き換えてました。
半端にアナログ野郎ですみません……。

この記事で書いたことが最善とは思っていません。
もっといい方法があったらぜひ教えていただけますと幸いです:pray:

### Railsの教科書について

『Railsの教科書』は現在も販売していて、改訂作業中です。
全作業が終わり次第、新版が購入およびバージョンアップ可能になります。
改訂前に買った方も改訂後に新版をダウンロード可能です。
[Railsの教科書 - 達人出版会](https://tatsu-zine.com/books/rails-textbook)
2020年2月29日・3月1日に開催される[技術書典8](https://techbookfest.org/event/tbf08)の1日目（2/29）でも紙版を頒布予定とのことです。
※電書版はフルカラーですが、紙版の本文はモノクロになるそうです。
デザイン担当からの告知になってしまいましたが、こちらもどうぞよろしくお願いします〜。