ゆるふわチャット小説をGitHubで構築しましたので╭( ･ㅂ･)و ̑ 〜初めてのフロントエンド編〜

ｱｯｵｰ!　皆様、チャットしてますかっ。
そうですね。私は、ChatWorkでAPI投稿される売上レポートを眺めたり、SlackでHubotからミーティングの司会を指名されたり、LINEでりんなにちょっかい出したりする愉快な日々です。
うわっ…私のチャット相手、ボットすぎ…？

<img width="320" alt="ai_mail_woman-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/7a5d5c00-04d0-5dfe-5159-9cb3a3355a37.png">

ともかく、みんなが慣れ親しんでいるインターフェースは強いわけです。
というわけで、チャットっぽく読める小説サイトをつくってみました。こういうの。

<img width="320" alt="chapter-01-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/14e06fb2-933e-2906-b70c-1464b0596a6e.png">

[深層の令妹 ζ(*ﾟｗﾟ)ζ　〜ゆるふわチャット小説〜](https://piyo7.github.io/deep-sister/)

あとはもう実際に、会話で紡がれる物語がどういうものか読んでみてほしいのですがっ。

サイト作るにあたって初めてのフロントエンドで色々と泣きそうになったので、諸々メモしておこうと思います。
もしも表示崩れ起こす環境あったら、ごめんネ。。。


# GitHub Pages

題名のとおり、サイトの公開は[GitHub Pages](https://pages.github.com/)で行っています。

[https://github.com/piyo7/deep-sister/tree/master/docs](https://github.com/piyo7/deep-sister/tree/master/docs)

にHTMLやCSSを `git push` すれば、あら不思議、

[https://piyo7.github.io/deep-sister/](https://piyo7.github.io/deep-sister/)

が自動更新されます。これはもうホント神機能ですね。

そしてGitは、コードだけでなく小説とも相性いいです。
加筆修正の差分も、どこまで公開したかも一目瞭然です。うっかり設定矛盾を起こしてしまっても、すぐ巻き戻せますしね。

<img width="640" alt="github_diff-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/faf0f7e4-fd88-c0fe-bc95-03402a189b35.png">

なお、GitHub Pagesで一つだけハマったのが、「404 File not found」のキャッシュです。
新規ページをプッシュしたつもりでURL確認して404なことに気づき、その後プッシュしても1時間くらい404のままなことがありました。ところが、海外のバリデーションサイトからはすぐにページ確認できていたので、エッジサーバのキャッシュが効いていたようです。焦らず待ちましょう。

<img width="640" alt="github_404-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/44bb3869-0730-a6d8-65b1-afc60aa224d3.png">

ちなみにHTMLは、Scalaで書いた自作ツールで生成しています。
独自記法で執筆していて、そのテキストをパースしてテンプレートに流しこんでいるのですが、詳しくは別記事を起こすかもです╭( ･ㅂ･)و ̑


# 吹き出し表現

LINE風の吹き出しも、チャットによって色々とバリエーションがあります。
いくつか試してみたのですが、小説なので文字の表示領域はできるだけ大きくしたく、アイコンもトゲもない三隅を角丸にするだけのシンプルな形式に落ちつきました。

```css
.voice-left, .voice-right {
  border-radius: 1em;
}

.voice-left {
  border-top-left-radius: 0;
}

.voice-right {
  border-top-right-radius: 0;
}
```

<img width="640" alt="chapter-06-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/ce19b88b-76b3-a8fa-e12c-6fd70f5bb0b0.png">

行あたりの全角文字数は、各チャットアプリをiPhone 6Sで確認したところ、ChatWork 19文字、Slack 19文字、LINE 13文字、という感じで悩んだのですが、18文字にしました。

なお、電話などの生音声じゃないセリフは、枠付きにしています。

```css
.telephone {
  border: 2px solid #808080;
  border-radius: 0;
}
```

<img width="640" alt="chapter-02-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/1d0d75fe-bfff-fd64-9bcc-163aa490272b.png">

さて、セリフの背景色がそれぞれ異なりますが、これは発言したキャラクターのイメージカラーです。
色相環と睨めっこしながら、輝度を統一して設定しました。

```css
.char05 { background-color: hsl(330, 100%, 85%); }
.char06 { background-color: hsl(210,  50%, 85%); }
.char07 { background-color: hsl(  0, 100%, 85%); }
.char08 { background-color: hsl(255,  75%, 85%); }
.char09 { background-color: hsl( 90, 100%, 85%); }
```

ちなみに、この小説『深層の令妹 ζ(*ﾟｗﾟ)ζ』は、[カクヨム](https://kakuyomu.jp/works/1177354054881205412)と[小説家になろう](http://syosetu.com/usernovelmanage/top/ncode/1004908/)にも投稿しているのですが、そちらにはない情報がこの色彩なのですね。

ほぼセリフだけの小説なので、なるべく早めにキャラクターを特定できるよう工夫はしているのですが、厄介なことに主人公の妹がころころ口調を変える設定なため、「新しい口調のキャラが登場するたび、まず妹の可能性を疑わないといけない」との感想がありました。ナンテコッタイ。

<img width="320" alt="interlude-01-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/a928dc81-a43d-e4e9-211a-9a24670f310f.png">

背景色があると、色んな口調のセリフが入り混じっていても、妹の一人会議シーンなのだということが一目で分かりますね！


# フォント

フォントの設定にはだいぶ悩まされました。
`font-family` で検索したところ、201x年はこの設定！みたいな記事がいくつも出てきてオッと思ったのですが、ユーザ環境に何のフォントがインストールされているか分からないという状況が、かくも混沌を生むものとは……。

```css
font-family: sans-serif;
```

として、環境ごとのデフォルトフォントに委ねるのが正義のような気もしましたが、それが小説として読みやすいフォントかというとそうでもなく。いきおいGoogle Fontsの「[M+ 1p](https://googlefonts.github.io/japanese/#mplus1p)」を導入することにしました。

まだ早期アクセスということですが、今回の用途では充分に実用的です。
ただし `font-feature-settings: "palt"` は効かないみたいなので、カーニングしたい人は気をつけてください。

```css
font-family: arial, "Mplus 1p", sans-serif;
```

これに加えて、[Font Awesome](http://fontawesome.io/)のCSSを読んだものが、採用したフォント設定です。
Arialを先頭にしているのは、もちろん英数フォントをArialにしたかったこともあるのですが、これを指定しておかないと和文であってもルビが浮いてしまうということがありました。

<img width="640" alt="chapter-03-b-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/59641115-e800-554a-901e-00fac1a78213.png">

上図がArial指定なしで、下図がArial指定ありです。
どうしてこうなるかは分かりませんでした。。。

<img width="640" alt="chapter-03-a-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/5e3bfd4d-4a5b-91e5-b49a-770a1d4d9658.png">

なおユーザ環境に依存しないウェブフォントの弱点は、ダウンロードが終わるまで適切にテキストが表示できないことです。
「M+ 1p」は、フォントの太さごとにWOFFファイルが分かれているため、 `font-weight: 400`のものだけ使うようにして、ダウンロードサイズを抑えています。
Chromeのデペロッパーツールなどで確認しておくと安心ですね。

<img width="640" alt="chrome_developer_tool-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/0c22967c-f3e9-e21a-7b89-892a42ac7d5a.png">

とはいえ、回線状況によってはダウンロードに数秒かかることもあり、その間はブラウザによってテキストが空白にされたり別のフォントに置き換えられたりします。
この挙動は制御可能なのですが、Font Loading APIは未対応ブラウザがあり、JavaScriptライブラリを使うのはオーバーヘッドを増やすことになるので、見送りました。このあたりの事情は「[ウェブフォントの最適化 | Google Developers](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization)」が詳しいです。

＜追記＞WindowsのChromeで「M+ 1p」がガタガタに表示されることがあったので、結局メイリオを追加しましたorz

```css
font-family: arial, メイリオ, "Mplus 1p", sans-serif;
```


# hoverアニメーション

フォント以上に悩んだのが、hoverの制御です。
たとえば目次ページでは、『灼け焦がれた涙』という章題にhoverが効くと、登場キャラクターを表すバッジが下線になるアニメーションを仕掛けています。

<img width="640" alt="index-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/3e861318-49c4-57ed-db12-26ac47856ec3.png">

CSSの擬似クラス `:hover` は、名のとおりPCではマウスをかざした時に発火するのですが、スマホだとタップの指を話した時に発火したりします。これが直感と反しているのですね。
私の意図としては、ページ遷移の予兆として発火してほしくて、ページ遷移が確定したら解除されないでほしいのですが、違和感なく実現するのに試行錯誤しました。

最終的には、hoverを効かせたい要素に `hoverable` というクラスを付与しておいて、それを対象に[jQuery](https://jquery.com/)を仕掛けました。スマホの場合、タッチされると発火して、他の要素で発火するかスクロールすると解除されるようにしています。

```html
<div class="chapter hoverable">
  <div class="badges">
    <div class="badge char06"></div>
    <div class="badge char01"></div>
    <div class="badge char05"></div>
    <div class="badge char02"></div>
    <div class="badge char07"></div>
  </div>
  <p><a href="chapter-02">灼け焦がれた涙</a></p>
</div>
```

```js
$('.hoverable').on('mouseenter', function () {
  $(this).addClass('hover');
}).on('mouseleave', function () {
  $(this).removeClass('hover');
}).on('touchstart', function () {
  $(this).addClass('hover');
  $('.hoverable').not(this).removeClass('hover');
});
$(window).on('scroll', function () {
  $('.hoverable').removeClass('hover');
});
```


# シェアボタン

ソーシャルからは逃れられない時代なので、シェアボタンをフッターに設置しました。
公式のものを使いたかったのですが、それぞれサイズが異なっていて綺麗に並べられなかったので、下記サイトを参考にCSS組みました。

[おしゃれなシェアボタンをCSS＆Webフォントで作ってみた【はてなブログのPC＆スマホ用】](http://www.daipanman.com/entry/2015/07/05/080000)

<img width="640" alt="sns_share-compressor.png" src="https://qiita-image-store.s3.amazonaws.com/0/55208/1f580d68-7d99-3ca7-1011-5c997f1e7694.png">

せっかく設置したので、どなたか動作確認してもらえると＞＜


# HTML全般

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">デベロッパーツールで、期待したレイヤー位置＆重なりになるまで試行錯誤の繰りかえし。viewportもz-indexもflexも、ぶっちゃけよく分からない。俺たちは雰囲気でCSSをやっている……</p>&mdash; 夢霧もろは (@moroha_yumekiri) <a href="https://twitter.com/moroha_yumekiri/status/859106662883381252">2017年5月1日</a></blockquote>

ついでにメディアクエリも、横幅の閾値どうするのが適切かよく分かりませんでしたが、端末によらず1カラムでチャット表示できればいいので、viewport固定して事なきをえました。たぶん……！

```css
<meta name="viewport" content="width=480">
```


# 画像の圧縮

1200x630のシェア画像を、[Compressor.io](https://compressor.io/compress)に食わせたところ、259KBを55KBに圧縮するすごいやつでした。
非可逆圧縮ですが、私には違いが分からなかったです。

https://github.com/piyo7/deep-sister/commit/24ede51ee88181c46c2476269db18d4fff81f5d0


# バリデーション

バリデーションには下記サイトを利用しました。おおむね大丈夫そう。

- [The W3C Markup Validation Service](https://validator.w3.org/)
- [PageSpeed Insights | Google Developers](https://developers.google.com/speed/pagespeed/insights/)
- [Card Validator | Twitter Developers](https://cards-dev.twitter.com/validator)
- [デバッガー | 開発者向けFacebook](https://developers.facebook.com/tools/debug/)


# 感想

> それよりは、せっかく会話小説なので、いずれLINE風だったりTwitter風の見せ方をしてみたいです。
>
> [Visual Studio Codeの拡張機能を自作して、理想の執筆環境を手に入れた 〆(ﾟ_ﾟ*)](http://qiita.com/piyo7/items/4202189d523572da736a)

という前回の心残りが実現できて良かったです。
やはり見せ方は重要ですね。この小説本来の表現形式をようやく手に入れられたような気がしています。

あとは、チャットの背景にパーティクルシステムを仕込めればなぁと夢見ています。
シーンによって、雨を降らしたり、桜吹雪を舞わせたり、してみたいです。地の文ない代わりに情景描写ができれば、と。
[ParticleJS](https://ics.media/entry/11172)で実験しているのですが、ここのところ肝心の執筆を滞らせてしまっているため、開発は一段落つけようと思っています。

そろそろ物語も中盤戦。妹がXXX化する頃ですしね╭( ･ㅂ･)و ̑

- [deep-sister | GitHub](https://github.com/piyo7/deep-sister/)
- [深層の令妹 ζ(*ﾟｗﾟ)ζ　〜ゆるふわチャット小説〜](https://piyo7.github.io/deep-sister/)