1年目のスタッフ向けにCodePenとVueでクイズを作ってみた

この記事は <a href="https://qiita.com/advent-calendar/2018/vuejs-3" target="_blank">Vue.js #3 Advent Calendar 2018</a> の 3 日目の記事です。

#はじめに
無事にフロントエンド研修が終わって、各プロジェクトで働いている1年目の皆様。お元気ですか？
そろそろ、先輩のチェックなしで、一人でお仕事ができるようになってきた頃でしょうか。

実は皆さんに、お伝えしなければならないことがあります。
それは、研修生時代にやらなかった、とある学習内容があります。

![food_vegetable_sald.png](https://qiita-image-store.s3.amazonaws.com/0/157683/03b6d284-f878-6766-327d-6a2cdbebd5fe.png)

この学習内容は、技術研修の内容を、厳選に厳選を重ねた結果、「優先順位の関係」で省かれたものです。

今後、様々なお仕事を経験することで、ある程度は獲得できる知識ではあります。

しかし、どんなプロジェクトにアサインされるのかは、会社の都合によるところが大きく、
この学習内容について、簡潔にまとまったサイトや書籍が見つけられませんでした。。。

そこで今回、この場を借りて出題させていただきますね～

#ルール

まずは、CodePenに書かれた「HTML」「CSS」「JS」の内容を見てください。

以下の3点について、いろいろ設定を変えています。
・文字の色
・文字の背景色
・文字の内容

<p data-height="265" data-theme-id="0" data-slug-hash="MzLXPv" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="VueSample" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/MzLXPv/">VueSample</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

内容を見たら、自分の頭の中で「出力結果」を想像してみてください。
想像できたら「Result」を押して、「自分が想像した結果」と「出力結果」が一致しているか確認してください。

最後に、必ず「問題の解説」が書かれています。
なぜ、その出力結果になるのか？しっかり解説を読んでから、次の問題にお進みください。

#フロントエンドQuiz 全12問 の はじまりはじまり～

<details><summary>第1問</summary><p data-height="265" data-theme-id="0" data-slug-hash="MzLeOP" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue1" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/MzLeOP/">Vue1</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第1問-解説</summary>
<div>HTML5では非推奨になった「bgcolor」属性を使用しています。
「bgcolor」によって、背景色が「red」になっています。

もしかして、初めて見る人もいるかもしれません。

きちんと開発体制が整った現場ですと、まず見ないパターンです。
もしあっても、コードレビューで指摘されて修正されます。

私の感覚で大変恐縮ですが、実際には「bgcolor」属性よりも「width」属性の方がよく見る気がします。

なぜ、そのような古いコードが現在でも見られるのか？
それには、以下のような「深い理由」があります。

・システム開発会社などでは、フロントエンド専門のエンジニアがいないことがある
・システム開発会社などでは、バックエンドのエンジニアが作った「汚いフロントエンドの実装」を、納期を優先するために許してしまう（中小企業のお客様は、システムの中身がどう作られているか、よくわからない）
・エンジニアが1つのプロジェクトに長期で所属し、新しい技術を使えないシチュエーションが長く続いたため、勉強意欲がなくなった
・エンジニアの業務歴が長くなってきて、だんだんと指摘してくれる先輩エンジニアがいなくなり、昔のやり方のままコードを書いている

ということで、現在でも「古い書き方」が混じったコードを見ることがあります。

もし今のプロジェクトで、GitHubのプルリクエストに、厳しいフィードバック受けている方は、大変ありがたいシチュエーションですので、しっかり学んでくださいませ～</div></details></details>

<details><summary>第2問</summary><p data-height="265" data-theme-id="0" data-slug-hash="qQgoBv" data-default-tab="html,result" data-user="satoshi_hayashi" data-pen-title="Vue2" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/qQgoBv/">Vue2</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第2問-解説</summary>
<div>「bgcolor」によって、背景色に「red」を指定しています。
しかし、スタイルシート「background-color」によって「blue」に上書きされています。

第1問で「bgcolor」は「非推奨の属性」ということを書きました。
普段は使用される機会は少ないですが、もし「非推奨属性とスタイルシート」がバッティングした場合、いったいどちらが勝つのか？実際やってみたのがこの問題です。

「非推奨の属性」<「スタイルシート」

というのが今回の答えです。</div></details></details>

<details><summary>第3問</summary><p data-height="265" data-theme-id="0" data-slug-hash="YRBjEw" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue3" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/YRBjEw/">Vue3</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第3問-解説</summary>
<div>「style」属性の「background-color」によって、背景色に「red」を指定しています。
しかし、スタイルシート「background-color」によって「blue」を指定しています。

ここらへんのスタイルの優先順位について、研修中は

「要素」<「クラス」<「ID」

を覚えて、なぜかスタイルが当たらない場合は「style属性」で直接書いたり「!important」を付けよう
と習ってきたかもしれません。

これは「簡略化したルール」で、初心者用の書籍やWebスクールでも、このように教えています。
実は、このルールでも8割くらいは大丈夫なのですが、残りの2割を切り捨てています。

そのため、たまに、なぜかスタイルが適用されないから、「style属性」で直接書いたり「!important」を付けているコードがあります。

業務歴1年目は、それでもかまわないのですが、2年目以降は「詳細なルール」を勉強して、汚いスタイルの上書き合戦を避けなければなりません。

詳細なルールで解説しますと
「background-color: red」は「スタイル属性」ですので、詳細度は「0.1.0.0.0」。
「background-color: blue」は「要素セレクタ」ですので、詳細度は「0.0.0.0.1」。

「0.1.0.0.0」>「0.0.0.0.1」

その結果、詳細度が大きい「background-color: red」が勝ちます。</div></details></details>

<details><summary>第4問</summary><p data-height="265" data-theme-id="0" data-slug-hash="QJYBoB" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue4" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/QJYBoB/">Vue4</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第4問-解説</summary>
<div>第3問では「style属性」の詳細度が大きいことによって、「style属性」の色が表示されていました。
今回は「!important」を付けることによって、「style属性」に勝とうとしています。

それでは、詳細度のチェックをしてみましょう。
「background-color: red」は「スタイル属性」ですので、詳細度は「0.1.0.0.0」。
「background-color: blue」は「要素セレクタ + !important」ですので、詳細度は「1.0.0.0.1」。

「0.1.0.0.0」<「1.0.0.0.1」

その結果、詳細度が大きい「background-color: blue」が勝ちます。

このように「!important」は最強の詳細度「1.0.0.0.0」をプラスします。
そして、ほとんどの場合にスタイルが適用されることになります。

裏を返せば、安易に「!important」を付けると、その後の改修では常に「!important」を付けて上書きする必要が出てきて、ソースがどんどん汚くなってきます。

「!important」は、最終兵器であり、安易に使用すべきではありません。
もし「!important」を使用して良いシチュエーションをあえて挙げるとすれば、
自分でソースを変更できない「外部の広告タグ」のスタイルによって、サイト本体のスタイルが崩れた場合に、他に方法がなくて、仕方なく「!important」を使用します。
</div></details></details>

<details><summary>第5問</summary><p data-height="265" data-theme-id="0" data-slug-hash="RqvYxQ" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue5" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/RqvYxQ/">Vue5</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第5問-解説</summary>
<div>第4問では「!important」の詳細度が大きいことによって、「style属性」が負けました。
今回は「style属性」の方でも「!important」を付けることによって「CSS」側に勝とうとしています。

それでは、詳細度のチェックをしてみましょう。
「background-color: red」は「スタイル属性 + !important」ですので、詳細度は「1.1.0.0.0」。
「background-color: blue」は「要素セレクタ + !important」ですので、詳細度は「1.0.0.0.1」。

「1.1.0.0.0」>「1.0.0.0.1」

その結果、詳細度が大きい「background-color: red」が勝ちます。

このコードは末期状態です。
もし現場のコードがこんな状態になったら、担当のエンジニアは、改修作業にストレスを感じると思われます。
（ブラウザゲームの現場では、実際にあるのですが。。。）</div></details></details>

<details><summary>第6問</summary><p data-height="265" data-theme-id="0" data-slug-hash="GwzXLY" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue6" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/GwzXLY/">Vue6</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第6問-解説</summary>
<div>第5問では「!important」の詳細度が大きいことによって、「style属性」が勝ちました。
今回は、CSS側が反撃した結果になります。
　
本来「style属性」+「!important」の組み合わせは、詳細度「1.1.0.0.0」と最強に近く、「style属性」+「!important」でないと勝てません。

CSS側は「!important」は作れても、「style属性」が作れないため、詳細度「1.1.0.0.0」を超えることができません。

万事休すか？

背景色が「red」のまま、何もできないのかというと、実はそうではありません。
工夫次第で、CSS側から「blue」にすることができます。

そうです、どうしても「red」が勝つなら、勝たせてやればよい。
その「red」を生かしつつ、「色相」をずらして「blue」にしてしまえば良いのです。

※ご参考
右側に書いてある「色相スケール」や「色相環」で見ると分かりやすいです。
<a target="_blank" href="https://ja.wikipedia.org/wiki/%E8%89%B2%E7%9B%B8">色相 - Wikipedia</a>

「色相」はWebデザイナーの方にとっては「色の基礎知識」として、学生時代に勉強した内容かもしれません。
「red」から色相を240度ずらすと「blue」になります。
</div></details></details>

<details><summary>第7問</summary><p data-height="265" data-theme-id="0" data-slug-hash="yQZQxR" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue7" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/yQZQxR/">Vue7</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第7問-解説</summary>
<div>「background-image」と「background-color」の宿命の対決です。
今回は、詳細度の大きさは関係ありません。CSSの仕様としてどちらが優先されるかです。

ということで、結果は「background-image」が優先されるようです。

本来「background-image」のサンプルを作るなら、赤色の画像を使用するところです。しかし、画像を準備する手間があったため、横着をしてグラテーションで背景を作りました。
</div></details></details>

<details><summary>第8問</summary><p data-height="265" data-theme-id="0" data-slug-hash="LXqMYN" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue8" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/LXqMYN/">Vue8</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第8問-解説</summary>
<div>「computed」を使用して「小数の精度が悪い」というテーマで出題しました。
一見すると「0.3」で「blue」になりそうですが、実は「0.30000000000000004」が合計となり「red」になります。

ということなので、もしJavaScriptで小数の計算をする場合は、一度「10」や「100」を掛けて整数にしてから、最後に「10」や「100」で割り戻すと、きちんとした計算が出ます。
また、「BigNumber.js」という便利なライブラリもありますので、こちらを利用することも検討してみてくださいませ。

※<a href="https://github.com/MikeMcl/bignumber.js/" target="_blank">BigNumber.js</a>
</div></details></details>

<details><summary>第9問</summary><p data-height="265" data-theme-id="0" data-slug-hash="pQGqKz" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue9" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/pQGqKz/">Vue9</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第9問-解説</summary>
<div>JSONが出てきました。一見すると正しそうですが、実は不正なJSON形式です。
実はJSONは、HTMLみたいに「''」と「""」を両方使用できません。「""」のみ使用できます。

もし9行目の内容を、「''」と「""」を入れ替えて書けば、正しいJSONとなります。
</div></details></details>

<details><summary>第10問</summary><p data-height="265" data-theme-id="0" data-slug-hash="pQGqmJ" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue10" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/pQGqmJ/">Vue10</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第10問-解説</summary>
<div>「日付」というJavaScriptで、誰もが一度はハマるポイントです。
今回も一見すると、正しいように見えますが、「result_date」の中身は「1999/9/11 12:13:14」となります。
　
原因は「getMonth()」が「0～11」の値を返すからです。

しかし「getFullYear()」や「getDate()」は「-1」されないため、なぜ「getMonth()」だけそのような動きをするのか、まったく不思議です。
</div></details></details>

<details><summary>第11問</summary><p data-height="265" data-theme-id="0" data-slug-hash="eQxxBv" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue11" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/eQxxBv/">Vue11</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第11問-解説</summary>
<div>初見殺しの問題です。一見すると、両方とも「11」になりそうですが、そうはなりません。
　
「age」は単なる数字で、プリミティブ型と呼ばれます。
プリミティブ型は、文字やtrueなどがあり、関数の引数に設定すると、コピーが使用されます。
→「birthday」の内部では「ageのコピー」が使用される。
　
「boy」は連想配列で、オブジェクト型と呼ばれます。
オブジェクト型は、配列や日付などがあり、関数の引数に設定すると、それ自身が使用されます。
→「birthday」の内部では「boyそのもの」が使用される。
　
つまり「ageのコピー」に対して「+1」しても「ageそのもの」には影響しません。
その結果「age」が「10」、「boy.age」が「11」となって、背景色は「red」になります。
</div></details></details>

<details><summary>第12問</summary><p data-height="265" data-theme-id="0" data-slug-hash="GwzzPK" data-default-tab="html" data-user="satoshi_hayashi" data-pen-title="Vue12" class="codepen">See the Pen <a href="https://codepen.io/satoshi_hayashi/pen/GwzzPK/">Vue12</a> by satoshi hayashi (<a href="https://codepen.io/satoshi_hayashi">@satoshi_hayashi</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script><details><summary>第12問-解説</summary>
<div>初見殺しの問題です。一見すると、例外が発生して「red」になりそうですが、そうはなりません。
　
実は、「setTimeout」で関数を実行すると、関数内で例外が発生しても、catchでは捕らえられなくなります。
これがもし、「setTimeout(this.work, 0);」ではなく「this.work();」という普通の実行だったら、catchが実行されて「red」になります。
</div></details></details>

#最後に

全12問、大変お疲れ様でございました。
　
「フロントエンドQuiz」の全12問は、
前半は「CSS」寄りの内容、後半は「JS」寄りの内容になっておりました。
　
これは、私の周りだけかもしれませんが、男子は「JS」が得意で「CSS」が苦手、女子は「CSS」が得意で「JS」が苦手という傾向が見られます。

フロントエンドにおいて「CSS」と「JS」は車の両輪です。
もし今回のQuizを通して、何かしら得るものがありましたら、Quizの作者として大変うれしく思っております。