なぜクライアントサイドJavaScriptにはHTML/CSSの知識が必要か？

# クライアントサイドJavaScriptにおけるHTMLとCSSの知識

とある勉強会にて

>JavaScriptを勉強したいのだけど、まず何から勉強したらよいか？

という問いがありました。

もちろんプログラミングの基礎知識やアルゴリズムの知識、ある程度の数学の知識、文章読解力が重要という意見もあるでしょう。答えは色々あると思うのですが、 **クライアントサイドJavaScript** (ブラウザやWebビューで実行されるJavaScript)において、まずひとつ押さえておきたいのは **HTML/CSS** の知識ではないかと思っています。

今回の話は、「なぜクライアントサイドJavaScriptにはHTML/CSSの知識が必要か？」というテーマで、JavaScriptとHTML/CSSがどのくらい関わっているのか解説していきたいと思います。

# どんな人に読んで欲しいか

- JavaScriptをこれから学びたい人
- HTML/CSSはわかるけどJSはイマイチな人
- プログラミングはわかるけどHTML/CSSがイマイチなWebに関わる人
- HTML/CSSとJSの関係がイマイチなWebディレクター
- HTML/CSSとJSの関係を整理したいフロントエンドエンジニア

特に「HTML/CSSはわかるけどJSはイマイチな人」には **HTML/CSSの知識がベース** になっているとわかっていただければ、かなり **親しみやすく** なるんじゃないかと思っています。

# なぜ知識が必要か

理由を最初に答えてしまうと

クライアントサイドWebサイトのJSのやってることのほとんどは、

**『HTMLとCSSのソースを書き換えること』**

だからです。

## つまり？

```html
<div id="mkbn">まかべん</div>
```

上のHTMLに対して

```javascript
$('#mkbn').css('color', 'red');
```

という(たとえばjQueryを利用した)コードを実行すると

```html
<div id="mkbn" style="color: red;">まかべん</div>
```

というように書き換わります。

たとえば

```html
<div id="fff">かわ〜ず</div>
```

上のHTMLに対して

```javascript
$('#fff').hide();
```

という(jQueryを利用した)コードを実行すると

```html
<div id="fff" style="display: none;">かわ〜ず</div>
```

というように書き換わります。

たとえば

```html
<div id="mkbn">まかべん</div>
```

上のHTMLに対して

```javascript
$('#mkbn').after('<div id="fff">かわ〜ず</div>');
```

という(jQueryを利用した)コードを実行すると

```html
<div id="mkbn">まかべん</div><div id="fff">かわ〜ず</div>
```

というように書き換わります。


(実は)こういった単純なCSSでの表示制御を上手く利用して、よくあるアニメーションやモーダルウィンドウは表現されているのです。よく利用されるjQueryプラグインのゴリゴリ動くプラグインでもこれが基本になっていることがほとんどです。

## いきなりブラウザの表示側を想像しちゃだめです

次にHTML/CSSの知識(特にCSS)がどれほど重要か見てみます。

```javascript
$('#mkbn').css('color', 'red');
```

というコードがあります。

さきほどの解説だと要素に`style="color: red;"`を付加するので、単純に

**「テキストのカラーが赤になる」**

と思うかもしれません。

しかし、それを **信じてはいけません。**

たとえば次のHTML

```html
<style>
#mkbn {
	color: blue !important;
}
</style>
<div id="mkbn">まかべん</div>
```

上の状態でさっきのJSを実行すると

```html
<style>
#mkbn {
	color: blue !important;
}
</style>
<div id="mkbn" style="color: red;">まかべん</div>
```

このようになるわけですが、ご覧のとおり`<style>`タグ側で`!important`宣言を食らっているので、いくらJSやjQueryで頑張っても「テキストの色が赤になる」ことはありません。

つまり **CSSの知識** として`!important`宣言が何よりも優先されてスタイルに反映されるということを知っていなくてはいけません。

## 考え方を整理しましょう

上記のケースからわかるように、

**JavaScriptは直接表示を制御しているではありません。**

**JavaScriptはHTMLやCSSを書き換えているだけに過ぎないのです。**

## アニメーションも然り

```html
<style>
#mkbn {
	color: #fff;
	position: absolute;
	width: 100px;
	height: 100px;
	top: 0;
	left: 0;
	background: #000;
}
</style>
<div id="mkbn">まかべん</div>
```

```javascript
$('#mkbn').animate({
	left: 100
}, {
	duration: 1200
});
```

とすると`div#mkbn`が1200ミリ秒かけて右に100ピクセル移動します。

ソースはどうなっているかというと

```html
<div id="mkbn" style="left: 0.01px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 0.06px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 0.11px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 1.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 23.11px;">まかべん</div>
                           ・
                           ・
                           ・
<div id="mkbn" style="left: 79.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 81.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 92.58px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 99.99px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 100px;">まかべん</div>
```
といったように数ミリ秒ごとに`left`の値が書き換わっているだけなのです。

### なので

```html
<style>
#mkbn {
}
</style>
<div id="mkbn">まかべん</div>
```

```javascript
$('#mkbn').animate({
	left: 100
}, {
	duration: 1200
});
```
というように`#mkbn`にスタイルが当たっていない状態で同じ処理をしても、`position`がデフォルト(`static`)の要素に対して`left`の値を反映させてもなにも起こらないので、ブラウザ表示側には何も起きません。

でもソースはがんばって置き換わってます。

```html
<div id="mkbn" style="left: 0.01px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 0.06px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 0.11px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 1.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 23.11px;">まかべん</div>
                           ・
                           ・
                           ・
<div id="mkbn" style="left: 79.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 81.23px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 92.58px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 99.99px;">まかべん</div>
                           ↓
<div id="mkbn" style="left: 100px;">まかべん</div>
```
ただ`position`が`static`のなので、表示側には全く影響が起きないだけなのです。

考え方がわかればCSSとしては **『当然』** の仕様なのです。

### Chromeなどのインスペクターで確認すると一目瞭然です。

```html
<div id="hoge"></div>
```
```css
#hoge {
  position: absolute; // ここを変えて見てみる
  top: 0;
  left: 0;
  width: 100px;
  height: 100px;
  background: blue;
}
```
```js:jQuery
function anime () {
  $('#hoge')
  .animate({ left: 80 })
  .animate({ top: 80 })
  .animate({ left: 0 })
  .animate({ top: 0 })
  .promise()
  .done(anime);
}
anime();
```

`position: absolute`の場合

![jqueryanime_1.gif](https://qiita-image-store.s3.amazonaws.com/0/5548/21eeebbe-9981-90d6-88fc-2e08e29a2b74.gif)

`position: static`の場合

![jqueryanime_2.gif](https://qiita-image-store.s3.amazonaws.com/0/5548/3a7c6513-207a-46d1-1bb2-bd25222a4f46.gif)

`static`ではソースは動いているのに、表示は全く変わらないのがわかります。

# あとはJavaScriptでどう書けばいいか調べればいいだけ

HTML/CSSの性質がわかれば、あとはJavaScriptでどうやって変更するか、ドキュメントを読んだりググったりするだけです。色々とプラクティスはありますが、動作するものは作れるはずです。

たとえば

```html
<div id="mkbn">まかべん</div>
```

を

```html
<div id="mkbn" style="position: absolute; top: 0; left: 0; width: 100%; height: 100px">まかべん</div>
```

という風に変えたいとしましょう。

jQueryを使えばこんなふうに書けます。

```javascript
$('#mkbn').css('position', 'absolute');
$('#mkbn').css('top', 0);
$('#mkbn').css('left', 0);
$('#mkbn').css('width', '100%');
$('#mkbn').css('height', 100);
```

もしくは

```javascript
$('#mkbn').css({
	position: 'absolute',
	top: 0,
	left: 0,
	width: '100%',
	left: 100
});
```
このような書き方もできます。

* * *

たとえば

```html
<div id="mkbn" class="current">まかべん</div>
<div id="fff">かわ〜ズ</div>
```

を

```html
<div id="mkbn">まかべん</div>
<div id="fff" class="current">かわ〜ズ</div>
```
と変えたいなら

```javascript
$('#mkbn').removeClass('current');
$('#fff').addClass('current');
```

jQueryをつかってこう書きましょう。

* * *

たとえば

```html
<ol>
	<li>まかべん</li>
	<li>かわ〜ズ</li>
</ol>
```

を

```html
<ul>
	<li>まかべん</li>
	<li>かわ〜ズ</li>
</ul>
```

と変更したいなら

```javascript
$('<ul />').append($('ol').find('li')).insertAfter('ol');
$('ol').remove();
```

こういう書き方ができます。

# CSSで表現できればできたも同然

目的の状態をHTML/CSSを表現できれば、どんなインタラクションもつくれます。あとはJavaScriptで状態を制御したり、クリックやホバーなどのイベントにその処理を関連付ければいいのです（イベントについてはもちろん別途勉強が必要ですが）。

## CSSで表現できないものは難しい

- 古いIEで画像を回転させたり
- ベクトルマスクをかけたり
- 乗算描画でレイヤーを重ねたり

上記のように、それぞれのブラウザでCSSで表現できないものはJavaScriptを使っても表現できません。

HTML/CSSを超えた表現をするのであれば

- SVG (古いIEではVML)
- Canvas2D
- WebGL etc...

などを駆使して表現するかありません。あるいはFlashを（笑）

# まとめ

- JavaScriptは主にHTMLとCSSのソースを書き換えることをしている
- HTML/CSSで状態を表現できれば、どんなインタラクションも作れる

JavaScriptはプログラミング言語ですが、敷居が高いものでは全然ありません。むしろHTML/CSSの表現をちょっと手助けしてくれる友達です。これまであまり手を出してこなかった方も挑戦してみてはどうでしょうか。