初心者向けCSSべからず集・すべし集

　
　CSSを勉強していてそろそろ初心者を脱出して初級者へレベルアップしたかな、という実感を得たので、CSS初心者向けのTIPS記事を書きます。
　思い付きで追加・変更することもあるかもしれません。

　この記事は、初心者向けにわかりやすさを重視して書いていますので「厳密に言うと違うけど」みたいな記述がありますので、ご了承ください。
　また、「よくわからないならこうしておけ」というスタンスで書いていますので、読んで「え？こうした方がいいんじゃね？」と思ってしまうあなたは、すでに初心者ではなく、この記事の対象じゃないかもしれないです。

「こうした方が初心者にはよくね？」というご意見はぜひ教えてください。

# べからず集

### float は使うな

　要素を横並びにする目的では使わない方がいいです。いいことはないです。
　10年前ならともかく、2022年にやることじゃないです。~~こんなの教えてるprogateとか何考えてんのかな~~

　浮動は、テキストの回り込みのためのプロパティです。
　横並びにする目的ではグリッドレイアウトかフレックスレイアウトがいいと思います。

参考：[CSSレイアウトにfloatは古い! 初心者でも始められるFlexbox入門 - ICS MEDIA](https://ics.media/entry/13117/)

### inline-block は使うな

　要素を横並びにする目的では使わない方がいいです。
　インライン要素はアセンダー・ディセンダーやベースラインの関係から、微妙な位置のずれが出ます。しかもOSによって異なったりします。レイアウトには心底向いていないです。フォントが混在する行のベースラインとか`line-height`とか完全に落とし穴です。避けましょう。

　アイコンのように「要素を文字として扱いたい場合」などに使うのであれば、使ってよいと思います。

### absolute は使うな

　中央配置の目的では絶対配置を使わない方がいいです。
　こういうやつ。

```css
div{
  position: relative;
}
div>p{
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
}
```

　グリッドレイアウトを使って以下のようにするか、

```css
div{
  display: grid;
  place-items: center;
}
```

　フレックスレイアウトで以下のようにするのがいいと思います。

```css
div{
  display: flex;
  place-content: center;
  flex-wrap: wrap;

/*IE11の場合
  align-content: center;
  justify-content: center; */
}
```

　中央配置以外でも、レイアウトのために安易に使うと収拾がつかなくなりますので、使う場合は包含ブロックを生成して影響範囲を限定して使用することをおすすめします。

### table / display: table は使うな

「はいはい、SEOによくないとか、セマンティックじゃないとか、そういうことでしょ？」
と思ったあなた。それもありますが、違います。

そもそもレイアウトがずれるからです。
CSS2 の仕様はこのようになっています。（CSS3は[こちら](https://www.w3.org/TR/css-tables-3/)）

> This algorithm reflects the behavior of several popular HTML user agents at the writing of this specification. UAs are not required to implement this algorithm to determine the table layout in the case that table-layout is auto; they can use any other algorithm even if it results in different behavior.
> [CSS 2](https://drafts.csswg.org/css2/#auto-table-layout)

（意訳）_このアルゴリズムはこの仕様を書いた時点のいくつかのブラウザを反映したものです。ブラウザはこの`table-layout: auto`時のテーブルレイアウト決定アルゴリズムを実装する必要はないですし、**違う動作をするアルゴリズムを使ってもかまいません**。_

つまり、レイアウトの仕様は定められていないということですので、同じコードを書いてもブラウザによって表示が異なります。
ちょっと古いですが、こんな話もあります。
[中堅コーダーがハマった「display:table」の落とし穴3つ。 | ネクストページブログ](https://nxpg.net/blog/tech/?p=10764)

そのような差異を許容できる範囲でのみ使ってよいと思います。

---

# すべし集

### box-sizing を使え

　とりあえず何も考えずに

```css
* {
  box-sizing: border-box;
}
```

　としておくべきです。

### img 要素には display: block を使え

　とりあえず何も考えずに

```css
img {
  display: block;
}
```

　としておくべきです。

### リセットCSS を使え

　とりあえず何も考えずにリセットCSSは何か導入すべきです。
　リセットCSSによっては上記の box-sizing も設定してくれます。ありがたい。

参考：[2022年、モダンブラウザに適したCSSリセットのまとめ | コリス](https://coliss.com/articles/build-websites/operation/css/css-reset-for-modern-browser.html)

### viewport を使え

　とりあえず何も考えずに

```html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```

　としておくべきです。

### aspect-ratio を使え

　アスペクト比を固定するための、`padding-top`を使ったハックがありますが、iOS15が`aspect-ratio`に対応したのでそろそろいらなくなってきました。

参考：[aspect-ratio - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/aspect-ratio)

### 折り返しには grid を使え

　フレックスボックスで「3列目で折り返したい」とか苦闘している人がいますが、折り返す列が固定ならそれはグリッドレイアウトを使った方がいいです。
　なお、折り返す列が成り行きであっても、`auto-fit`を使えばグリッドレイアウトの方が楽な場合が多いです。

参考：[これは便利！CSS Gridのauto-fillとauto-fitの使い分けでRWDが捗る – WPJ](https://www.webprofessional.jp/difference-between-auto-fill-and-auto-fit/)

---

# できぬ集

### 絶対配置の子要素サイズに親要素のサイズを合わせる

　できません。

```html
<div class="parent" style="background: #000;">
  <div class="absoluteChild" style="position: absolute;">absoluteChild</div>
</div>
```

　子要素が`position: absolute`である時に、その子要素にあわせてサイズを変化させることは、CSSではできません。

### masonryレイアウト

　できません。

　CSS の仕様としては存在しますが、メジャーブラウザとしてはFirefoxしか対応していません。
　まだしばらくは実装されなさそうな感じですが、JavaScriptのライブラリは複数存在しますので、そちらを使うことになるかと思います。

参考：[組積レイアウト - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout)
参考：[CSS property: `masonry` | Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/mdn-css_properties_masonry)


### 子孫要素を参照するセレクタ　または　後続の要素を参照するセレクタ

　最新のメジャーブラウザで対応されました。
　~~できません。~~
 

　~~CSS の仕様としてはかなり昔から存在しますが、対応しているメジャーブラウザはないです。~~
　~~先読みが必要になるため、実装上の問題が存在するようです。かなりしばらくの間、実装される見込みはないと思った方がよさそうです。~~ 
 
　~~Firefox 以外は対応しました。~~


参考：[:has() CSS relational pseudo-class | Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/css-has)

### :nth-child系疑似クラスで、要素をフィルタした結果のn番目を参照したい

　最新のメジャーブラウザで対応されています。
　~~Safariを除いて、できません。~~ 

　`span:nth-child(1)`は「兄弟要素の中で1番目である」かつ「span要素である」という意味です。
「兄弟要素の中でspan要素であるものの内の1番目である」という指定は、CSSではできないです。

　仕様として`:nth-child(1 of span)`のような書き方はあります~~が、現在のところ対応しているのはSafariのみです。~~
参考：[13.3.1. :nth-child() pseudo-class | Selectors Level 4](https://drafts.csswg.org/selectors/#the-nth-child-pseudo)
参考：[selector list argument of :nth-child and :nth-last-child CSS pseudo-classes | Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/css-nth-child-of)

### 要素内のテキストを参照するセレクタ

　できません。

「ほげほげというテキストを持つ要素」のようなセレクタはないです。
　同様に、要素ではないノードについてのセレクタもないです。
　また、CSSの仕様上発生する匿名要素についても同様です。

---

# こんなときどうする集

### 指定が効かない

　CSS詳細度が原因の可能性。

　↓これがわかりやすいです
　[100年後も崩れないCSS勉強会 · 第1回「詳細度」](http://pepabo.github.io/css/specificity/)

### 指定が効かない

　文法エラーの可能性。
　前の行のセミコロンを忘れている、とか誰でも通る道です。
　
　コードエディタを使った方がいいです。

### 何もしてないのに縮む

　CSSには全てのプロパティに初期値があり、それぞれプロパティによって異なります。
　たとえば、`width`は`auto`、`padding`は`0`、`display`は`inline`です。スタイルシートで何も指定しなかったプロパティは、値がないわけではなくて、初期値を指定しているものと同じです。

### 何もしてないのになんか余白がある

　ブラウザごとに、デフォルトスタイルシートがあります。
　`display`の初期値は`inline`なのに、`div`がブロックで表示されるのは、このデフォルトスタイルシートのおかげです。

　一方で、デフォルトスタイルシートのマージンやパディングなどがレイアウトの邪魔になる場合があるので、「リセットCSS」と呼ばれるライブラリを活用することが多いです。

参考：[2021年、モダンブラウザに適したCSSリセットのまとめ | コリス](https://coliss.com/articles/build-websites/operation/css/css-reset-for-modern-browser.html)

### 何もしてないのになんか余白がある

　親子間のマージン相殺かもしれません。

「相殺」という言葉のイメージとは異なり、子要素のマージンが親要素を突き抜けることがあります。
　`display: flow-root`とすれば大体防げるはずです。

参考：[CSSにおけるマージンの相殺を徹底解説 | コリス](https://coliss.com/articles/build-websites/operation/css/rules-of-margin-collapse.html)

### 何もしてないのになんか余白がある

　HTMLに全角スペースなどがあるかもしれません。`"` `>`などを全角で書いてしまうのもやってしまいがちです。
　コードエディタを使った方がいいです。

### autoを設定したのに自動で広がらない

　たとえば、`width: auto`は多くの場合で`width: 100%`と大体同じ意味を持ちますが、`height: auto`は多くの場合で`height: max-content`と大体同じ意味を持ちます。
　ところが、フレックスアイテムになると`width: auto`は多くの場合で`width: max-content`と大体同じ意味を持つようになります。

　このように、`auto`値は他のプロパティなどによって振る舞いが変わることがありますので、注意が必要です。

### 100%と指定したのに親要素と同じにならない

　パーセンテージ値の基準は親要素とは限らないです。

> **包含ブロック**の幅に対するパーセント値
[width - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/width)

　↑包含ブロックは親要素とは限らないです。

> 包含ブロックの**幅**に対するパーセント値
[margin-top - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/margin-top)

　↑垂直方向のプロパティなのに、水平方向の値を参照します。

> transform-box で定義される参照ボックスの幅からの相対値
[translate() - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/transform-function/translate() )

　↑transform-boxが初期値の場合は、自分自身が基準になります。

> 基本的に何が起こるかというと、背景画像の寸法が対応するコンテナーの寸法から減算され、その結果の値のパーセント値が左端（または上端）からの直接のオフセットとして使用されます。
[background-position - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/background-position#%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E5%80%A4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)

　↑一番わけわからんのはこの background-position や object-position のパーセンテージ指定ですね。calcを使ったりマイナスにしたりすると後で自分で読み返しても何が何だかわからなくなること請け合いです。