【技術書まとめ】作って学ぶ　HTML＆CSSモダンコーディング

現在のCSSを整理するために本書を手に取った。11冊目。
CSSの全体整理のための本。とりあえずこの本でCSS実装系はいったん終わり。


- 作成したデモサイト
    - https://cerulean-chebakia-bdaf42.netlify.app/index.html
        - モバイルフレンドリーテスト
            - https://search.google.com/test/mobile-friendly/result?id=xvc1AwB8BNX5VSxzjFRLug
        - PageSpeed Insights
            - https://pagespeed.web.dev/analysis/https-cerulean-chebakia-bdaf42-netlify-app-index-html/tbp2uuasfu?hl=ja&form_factor=mobile
        - HTML文法チェック
            - https://validator.w3.org/nu/?showoutline=yes&doc=https%3A%2F%2Fcerulean-chebakia-bdaf42.netlify.app%2Findex.html

# まとめ
## レイアウトのバリエーション

- 両端配置
    - Flexbox `justify-content: space-between`, `margin-right: auto`
    - Grid `grid-auto-flow: column; grid-template-columns: 1fr auto`
- 縦横中央配置
    - Grid `justify-items: center; align-content: center`
        - アイテムが1つだけなら `place-items: center`
    - Flexbox `flex-direction: column; justify-content: center; align-items: center`
- タイル状配置
    - Grid
        - 列の数が固定
            - `grid-template-columns: repeat(3, 1fr); gap: 32px 25px;`
                - アイテム配置を指定する `posts-container > :nth-child(5)`
        - 列の数が変わる
            - `grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))`
    - Flexbox `flex-wrap: wrap`, `.container > * { width: 33.333% }`
        - gapで余白調整 `gap: 32px 25px`, `width: calc(33.33% - (25px * 2 / 3))`
        - justify-contentで余白調整 `row-gap: 32px`, `width: 32%`
        - paddingで余白調整 `width: 33.33%`, `padding: 0 12.5px 32px`, `box-sizing: border-box`, `.container { margin: 0 -12.5px -32px }`
- 自在に配置を変更
    - Grid
        - テンプレート `grid-template-columns: auto auto`, `grid-column: 1 / 4`
        - エリア `grid-template-areas: "site" ". sns"`, `grid-area: site`
    - Flexbox `position: absolute; top: 0; right: 0; height: 100%;`
- 中身に合わせたサイズで横並び配置
    - Flexbox `display: flex; flex-wrap: wrap; gap: 20px;`
    - Grid `display: grid; grid-template-columns: repeat(auto-fit, minmax(6em, auto)); gap: 20px`
- カード型UI配置
    - Grid `grid-template-columns: repeat(auto-fit, minmax(0, 1fr))`
    - Flexbox `flex-direction: column`, `.container > * { flex: 1; }`
- カードの中身を上下揃えて配置
    - Flexbox `flex-direction: column`, `margin-top: auto`
    - Grid `grid-template-rows: auto 1fr auto auto`
- 画像とテキストを横並びに配置
    - Flexbox `flex-direction: column`, `.text { flex: 1 }; .img { flex: 2 };`
    - Grid `grid-template-columns: 1fr 2fr`
- 画像にテキストを重ねる
    - 背景画像 `.hero { height: 650px; background-image: url(img/hero.jpg); background-position: center; background-size: cover }`
    - Grid `grid-template-rows: 650px`, `.hero > * { grid-area: 1 / 1 }`, `.hero > img { width: 100%; height: 100%; object-fit: cover }`
- オーバーレイで表示する
    - `position: fixed; inset: 0; z-index: 100;`
- ヘッダーを上部に固定する
    - `position: sticky; top: 0; z-index: 10;`
- 記事本文の余白
    - `margin: 1.8em 0`
    - Grid `display: grid; gap: 1.8em`, `figure { margin: 20px 0; }`
- 横幅と左右の余白
    - width `width: min(92%, 1166px); margin: auto;` or `width: 92%; max-width: 1166px; margin: auto;`
    - padding `max-width: 1166px; margin: auto; padding-left: 4%; padding-right: 4%;`
    - Grid `grid-template-columns: 1fr min(92%, 1166px) 1fr`, `.grid > * { grid-column: 2; }`


## 各種設定

- 画面幅に合わせてフォントサイズを変える
    - `font-size: clamp(48px, 5vw, 68px)`
- レスポンシブイメージ
    - `srcset/sizes`
- 画像によるレイアウトシフトを防ぐ
    - `<img>`の`width/height`

# ヘッダー

## 両端に配置するレイアウト
- ヘッダーのようなシンプルな横並びコンテンツは`Flexbox`で両端に配置する
    - 3つ以上の要素の場合
        - flexboxでロゴに`margin-right: auto`を指定して枠を広げる
        - CSS Gridでロゴに`grid-template-columns: 1fr`を割り当てる

### Flexboxとgapでのシンプルな横並び
```css
.footer-sns {
    display: flex;
    gap: 24px;
}
```

## 横幅と左右の余白を調整する方法
### `min`関数`margin: auto`で横幅と左右の余白を指定する

```css
/* このクラス名を使って他のパーツでも同じ余白を指定する */
.w-container {
    width: min(92%, 1166px);
    margin: auto;
}
```

- Gridで余白を調整すると

```css
/* 2列目の横幅を指定して調整する */
.grid {
  display: grid;
  grid-template-columns: 1fr min(92%, 1166px) 1fr;
}
.grid > * {
  grid-column: 2;
}

/* 左右の列で調整する　*/
.grid {
  display: grid;
  grid-template-columns:
    minmax(4%, 1fr)
    minmax(auto, 1166px)
    minmax(4%, 1fr);
}
.grid > * {
  grid-column: 2
}
```


### imgの下に余計な余白が入るのを防ぐ（imgのスタイルをリセットする）

- imgタグは標準ではインラインブロックボックスになっているため

```css
img {
    display: block;
     /* オリジナルサイズ以上に拡大されるのを防ぎながら、親要素の横幅に合わせる */
    max-width: 100%;
    /* 横幅に対してオリジナルの縦横比を維持した高さにする */
    height: auto;
}
```

## ヘッダーを画面上部に固定するレイアウト
### `position: sticky`でヘッダーを固定する

```css
.header {
  position: sticky;
  top: 0;
  z-index: 10;
}
```


# ヒーロー
## 縦横中央に配置するレイアウト

- FlexboxとCSS Gridどちらでも対応できる
    - 今後複雑なデザインになっても対応しやすいのはCSS Grid


## 画面幅に合わせてfont-sizeを48pxから68pxに変化させる

```css
.hero h1 {
  font-size: clamp(48px, 5vw, 68px); /* 画面幅960pxで48px、1360pxで68px */
  min-height: 0vw; /* Safariで機能させるため */
}
```

## シンプルなボタンのサンプル

```css
a {
  color: inherit;
  text-decoration: none;
}

a:hover {
  filter: brightness(90%) contrast(120%);
}

a.btn {
  display: block;
  width: 260px;
  padding: 10px;
  box-sizing: border-box;
  border-radius: 4px;
  background-color: #e8b368;
  color: #fff;
  font-size: 18px;
  text-align: center;
  text-shadow: 0 0 6px #00000052;
}
```


## 縦横中央に配置するレイアウト

### CSS Gridで設定する
```css
.hero-container {
  display: grid;
  justify-items: center;
  align-content: center;
  height: 100%;
}

/* 縦横中央に配置するアイテムが1つだけの場合 */
.hero-container {
  display: grid;
  place-items: center; /* justify-items, align-itemsの値をまとめて指定する */
  height: 100%;
}
```

### Flexboxで設定する

```css
.hero-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%;
}
```


## 画像にテキストを重ねるレイアウト

### 背景画像で表示する
```css
.hero {
  height: 650px;
  background-image: url(img/hero.jpg);
  background-position: center;
  background-size: cover;
}
```

### `<img>`で表示する
```css
.hero {
  display: grid;
  grid-template-rows: 650px;
}

.hero > * {
  /* 「grid-row1; grid-column: 1;」をまとめて指定する */
  grid-area: 1 / 1;
}

.hero > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
```


# 画像とテキスト

## 横並びにするレイアウト

- 配置を逆転させるときはFlexboxの方がわかりやすくなる

### Flexboxのrow-reverseを使用する
```css
/* 連続して並べた場合に上要素のpaddingで間隔を調整する */
.imgtext + .imgtext {
  padding-top: 0;
}

.imgtext-container {
  display: flex;
  flex-direction: column;
}

@media (min-width: 768px) {
  .imgtext-container {
    flex-direction: row;
    align-items: center;
    gap: clamp(45px, 6vw, 80px); /* 余白を可変にする */
  }

  /* imagetext-containerに、reverseが指定されたときだけ配置を逆にする */
  .imgtext-container.reverse {
    flex-direction: row-reverse;
  }

  .imgtext-container > .text {
    flex: 1;
    min-width: 17em; /* テキスト折り返しで崩れるので最小幅を指定する */
  }
  .imgtext-container > .img {
    flex: 2;
  }
}
```

### CSS Gridを使用する

```css
.imgtext-container {
  display: grid;
  gap: clamp(45px, 6vw, 80px);
}

.imgtext-container.reverse > .text {
  order: 2;
}

.imgtext-container.reverse > .img {
  order: 1;
}

@media (min-width: 768px) {
  .imgtext-container {
    grid-template-columns: 1fr 2fr;
    align-items: center;
  }

  .imgtext-container.reverse {
    grid-template-columns: 2fr 1fr;
  }
}
```



## 可変サイズフォントの下線の余白をemで指定して対応する

```css
.heading-decoration {
  font-size: clamp(30px, 3vw, 40px);
  min-height: 0vw; /* Safari用　*/
}

.heading-decoration::after {
  display: block;
  content: "";
  width: 160px;
  height: 9px;
  border-top: solid 1px #b72661;
  margin-top: 0.6em;
}
```

## 見出しフォントをパーツ外側に配置する

```css
.heading {
  position: absolute;
  /* パーツの上の余白から外側に出すサイズ（0.6em）をマイナス指定する */
  top: calc((var(--v-space) + 0.6em) * -1);
}
```

## Chrome, Safariで:hoverを反映させるため、`<a>`にdisplay: blockを指定する

```css
.post a {
  display: block;
}
```

## article画像を3:2の縦横比に揃える

```css
.post img {
    aspect-ratio: 3 / 2;
    object-fit: cover;
    width: 100%; /* aspect-ratioの設定を反映させるために必要 */
}
```



## タイル状に並べるレイアウト
### CSS Gridでタイル状にする

```css
.posts-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px 25px;
}

@media (min-width: 768px) {
  .posts-container {
    grid-template-columns: repeat(3, 1fr);
  }
}
```

### 特定のアイテムの配置をグリッドで指定する（5つめだけ大きく配置する）

```css
.posts-container > :nth-child(5) {
    grid-column: 1 / span 2;
    grid-row: 1 / span 2;
}

.posts-container > :nth-child(5) img {
  aspect-ratio: 3 / 2.5;
}
```


### `@media`を使用せず、コンテナの横幅に合わせてタイル状に並べるレイアウト

#### CSS Gridで並べる

- 「特定のブレークポイントで2列と3列を切り替える」ような制御は難しくなる

```css
.posts-container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 32px 25px;
}
```

#### Flexboxで並べる

```css
.posts-container {
    display: flex;
    flex-wrap: wrap;
    gap: 32px 25px;
}

.posts-container > * {
    flex-grow: 1;
    width: 200px;
}
```

### Flexboxで設定する

- gapで調整する
    - gapを入れた分だけ横幅を短くする
- justify-contentで調整する（アイテム数を5件などに変えると崩れる）
- アイテムの横幅値余白を含めて調整する
    - paddingを入れて、border-boxを指定する

```css: gapで調整する
.posts-container {
  display: flex;
  flex-wrap: wrap;
  gap: 32px 25px;
}

.posts-container > * {
  /* 横幅50%から、25pxのギャップを1つ分を2分割したサイズを引く */
  width: calc(50% - (25px * 1 / 2)); 
}

@media (min-width: 768px) {
  .posts-container > * {
    width: calc(33.33% - (25px * 2 / 3));
  }
}
```



# フッター
## Gridでアイコンを正方形の中に表示する
```css
.footer-sns a {
    display: grid;
    place-items: center; /* 縦横中央に配置する（要素が1つだけの場合） */
    width: 36px;
    aspect-ratio: 1 / 1;
    background-color: #cccccc;
    color: #ffffff;
    clip-path: circle(50%);
}
```


# 記事
## 本文の構成要素の感覚をブラウザ標準の設定に戻す（特定クラスの特定要素を:whereで指定する）

```css
.entry-container :where(h1, h2, h3, h4, h5, h6, p, figure, ul) {
  margin-top: revert;
  margin-bottom: revert;
  padding: revert;
  list-style: revert;
}
```

## 記事本文のレイアウト
### marginの重ね合わせと、:first-child, :last-childで指定する
```css
.entry-container p {
  margin: 1.8em 0;
}

.entry-container > :first-child {
  margin-top: 0;
}

.entry-container > :last-child {
  margin-bottom: 0;
}
```

### CSS Grid/Flexboxで設定する
```css
/* Grid */
.entry-container {
    display: grid;
    gap: 1.8em;
}

/* Flexbox */
.entry-container {
    display: flex;
    flex-direction: column;
    gap: 1.8em;
}
```

## 複数の適用先をまとめて指定する

- 詳細度の違い
    - `:is()`
    - `:where()`




# プラン

## ボタンをwidth: autoにして左右いっぱいに広げる
```css
.plan .btn {
    width: auto;
}
```

## カード内のCTAボタンを下に揃えて表示を統一する
### Flexboxで設定する
```css
.plan .price {
  margin-top: auto; /* 余剰スペースが割り当てられる */
  ...
}
```

### CSS Gridで設定する
```css
.plan {
  display: grid;
  grid-template-rows: auto 1fr auto auto; /* 2列目に余剰スペースを割り当てる */
}
```

## カード型UIのレイアウト
### CSS Gridで設定する
```css
.plans-container {
  display: grid;
  gap: 27px;
}

@media (min-width: 768px) {
  .plans-container {
    /* 並べるカードの数を固定する */
    grid-template-columns: repeat(3, 1fr);

    /* カードの数を変えても対応できるようにする */
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));

    /* 複数行でレイアウトする場合 */
    grid-template-columns: repeat(2, 1fr);
  }
}
```

### Flexboxで設定する
```css
.plans-container {
    display: flex;
    flex-direction: column;
    gap: 27px;
}

@media (min-width: 768px){
    .plans-container {
        flex-direction: row;
    }
    
    .plans-container > * {
        flex: 1;

        /* 複数行でレイアウトする場合 */
        width: calc(50% - (27px * 1 / 2));
        box-sizing: border-box;
    }
}
```

# ナビゲーション
## position: fixedでオーバーレイ表示する

```css
@media (max-width: 767px) {
  .nav {
    position: fixed;
    inset: 0; /* 上下左右から内側に0の距離に揃える */
    z-index: 100;
    background-color: #4e483ae6;
  }

  .nav ul {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100%;
    gap: 40px;
    color: #ffffff;
  }
}
```

## ボタンクリックでメニューを表示する
### `position: fixed, inset: 0`で設定する
```html
<button
  class="navbtn"
  onclick="document.querySelector('html').classList.toggle('open')"
>
  <i class="fas fa-bars"></i>
  <span class="sr-only">MENU</span>
</button>
```
```css
@media (max-width: 767px) {
  .nav {
    position: fixed;
    inset: 0 -100% 0 100%; /* 右画面外に配置する */
    z-index: 100;
    background-color: #4e483ae6;

    /* top, left, width, heightで設定する場合 */
    top: 0;
    left: 100%;
    width: 100%;
    height: 100%;
    z-index: 100

    transition: transform 0.3s;
  }

  .open .nav {
    transform: translate(-100%, 0); /* navの横幅分だけ左移動させる */
  }

  /* 不要なスクロール発生を防ぐ */
  .open body {
    position: fixed;
    overflow: hidden;
  }

  .nav ul {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100%;
    gap: 40px;
    color: #ffffff;
  }
}
```