【HTML＆CSS】初心者が躓きがちなスタイリングについて解説してみた

## はじめに
はじめまして！
[DMM WEBCAMP Advent Calendar](https://qiita.com/advent-calendar/2023/infratop) 🎄 7 日目を担当することになりました、@k_uki512と申します！

Webアプリケーション開発において、HTML＆CSSを使用したフロントエンド開発は避けて通れません！ですが、実際にCSSを書いてみると自分の思ったようなスタイリングができないことも多いと思います。

そこで今回は、<b>初心者が躓きがちなスタイルの事例とその解決策をいくつか紹介していきたいと思います！🙌</b>

## 対象者
- CSS（SCSS）によるスタイリングに苦手意識がある方
- ホームページ制作,LP制作（web制作） にも興味がある方
- 基本的な HTML&CSS を学習後、更にステップアップしたい方
  - 簡単なFlexBoxのスタイリングについて知っていると更に良い（横並び、中央揃え程度でOK）

:::note info
本記事では、Bootstrap や Tailwind CSS などのCSSフレームワークは使わない場合を想定しています。フレームワークを使用している場合、予期せぬスタイルが適用されてしまう場合もありますのでご注意ください。
:::

## 事例1： 文字や要素が中央寄せにならない
まずは復習も兼ねて、要素の中央寄せについて見ていきます。
要素を中央寄せにする場合、<b>適用するタグが何要素であるのかを見ることが大切です。
代表的な要素としては以下のようなものが挙げられます。

### ブロック要素
- 各文章やコンテンツをまとめる役割、<b>高さや幅、余白</b>を指定できます。
   - （例：divタグ, pタグ, ulタグ等）
    
### インライン要素
- ブロック要素の中身という扱いになります。ブロック要素とは対照的に<b>高さや、幅、余白の指定はできません。</b>
   - （例：aタグ, spanタグ, iタグ等）

  例えば、以下の要素について考えてみます。
  ```
  <!-- index.html -->
  <body>
    <div class="container">
        <div class="box"></div>
        <span class="text">サンプル</div>
    </div>
  </body>
  ```
  ```
  /* style.css */
  .container{
    width: 100%;
    height: 100%;
   }
  .box{
    width: 200px;
    height: 200px;
    background-color: blue;
   }
   .text{
    font-size: 32px;
    color:red;
   }
  ```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/77113698-b992-afae-12ac-370c980214f4.png)

今回はdivタグとspanタグの２つの要素を中央寄せにしていきます。

### divタグ（ブロック要素）の場合
まずdivタグですが、divタグは<b>ブロック要素</b>に該当する要素です。ブロック要素を中央寄せにする場合は<b> margin:0 auto; </b>を記述します。

```
  .box{
    width: 200px;
    height: 200px;
    background-color: blue;
    margin: 0 auto; /* 追加 */
   }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/1cff379f-ec71-25d0-1baa-9152167f9eb5.png)
中央寄せになりましたね！
ここまでは知ってるよ！という方もいらっしゃると思うので、なぜ margin:0 auto;を指定することで中央寄せになるかについても解説します。

margin:0 auto;の２つの値はそれぞれ<b>上下 左右</b>の指定をしています。分解すると以下のようになります。
```
.hoge{
    margin-top:0;
    margin-bottom:0;
    margin-left:auto;
    margin-right:auto;
}
```

今回重要なのは、autoを適用している left と right の記述です。
```
.hoge{
    margin-left:auto;
    margin-right:auto;
}
```
margin-left 及び margin-rightに auto を適用することで、<b>指定した方向に限界まで余白を付けてくれます。</b>先程のboxクラスに対してmargin-leftのみを適用してみましょう。
```
.box{
    width: 200px;
    height: 200px;
    background-color: blue;
    margin-left: auto;
}
```
すると、boxクラスのdivタグは以下のように動きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/cf2e0e6f-f24c-c43b-776c-7b360609974e.png)

右寄せになりました！
つまり、leftとrightそれぞれにautoを適用することで、それぞれの動きが真ん中でぶつかり合い、中央寄せになるということです。

特に <b>margin-left: auto; </b>の記述は<b>右寄せのスタイリングをする際に使える</b>ため、ぜひ頭の片隅に入れておいてください！

### spanタグ（インライン要素）の場合
次にspanタグの中央寄せをしてみます。spanタグは<b>インライン要素</b>に該当します。
インライン要素の中央寄せをする場合、<b>親要素に対しtext-align:center;</b> を適用します。

```
container{
    width: 100%;
    height: 100%;
    text-align:center; /* 追加 */
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/9edc4d35-f220-e097-4197-444fec40b4ad.png)

中央寄せになりましたね！ここで重要なのは<b>中央寄せしたい要素の親要素に適用することです。</b>spanタグ自身にtext-alignを適用しても中央寄せにならないため注意してください。

※ displayを使用して、spanタグをブロック要素に変更する方法もありますが、今回は省略します。

### 発展：ブロック要素に margin:0 auto; を適用しても中央寄せにならない場合
たまに、ブロック要素に対して margin:0 auto; を適用しても中央寄せにならない場合があります。以下のソースコードを見てみます。
```
<!-- index.html -->
<body>
    <div class="container">
        <div class="inner">
            <div class="box"></div>
        </div>
    </div>
</body>
```
```
.container{
    width: 100%;
    height: 100%;
}
.inner{
    width: 200px;
}
.box{
    width: 200px;
    height: 200px;
    background-color: green;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/eda12fcc-c2d9-6dd8-ca1b-64306d6fde7c.png)

上記の場合、boxクラスに対して margin:0 auto; を適用しても中央寄せはされず、微動だにしません。なぜでしょうか？
これは、<b>親要素（innerクラス）の幅と子要素（boxクラス）の幅（width）が同じであることが原因</b>です。

marginを用いた中央寄せは<b>親要素の幅が基準になる</b>ため、親要素の幅が狭すぎる場合、想定した中央寄せにならない場合があるので注意しましょう。
今回の場合、親要素と子要素（box）の幅が同じ200pxであることから、動かなかったのですね。

今回のケースで中央寄せしたい場合、<b>親要素であるinnerクラスに対してmargin:0 auto; を適用するか、innerクラスに対し、 width:100%; などを適用することで幅をしっかり確保してから中央寄せしましょう。</b>

今回の問題は、<b>HTMLの入れ子構造が複雑になるにつれ発生しやすいです。</b>
（私もしょっちゅう遭遇します💦）

親要素の幅や構造をしっかり把握することが大切です👍

## 事例2：画像の上に文字を配置する
次に、以下のような事例を見ていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/baf534ea-031e-ef6e-12aa-cf93ffa51886.png)

コーポレートサイトや、Webアプリケーションのトップページ等で見かける<b>背景画像の上に画像を配置するスタイリング</b>です！

今回のケースは、画像の上に文字を重ねる必要があり、前述したmarginやtext-alignでは対応できないことがほとんどです。そのため、<b>position</b>プロパティを使用し対応します。

## positionの解説
まず、positonプロパティについて解説します。positionプロパティに指定できる値の代表例としては以下のようなものがあります。
- <b>relative</b>：<b>現在の位置を基準</b>に相対的な位置を決める
- <b>absolute</b>：<b>親要素の位置を基準</b>に絶対的な位置を決める
- fixed： 画面の決まった位置に要素を配置する。

これだけを聞いても「？」となると思いますのでもう少し詳しく解説します。

### positon: relative;
まず、<b>relative</b>についてですが、<b>初めに配置されていた位置からどれだけ移動させるか</b>という指定になります。

例として、以下の柴犬の画像を動かしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/715266f0-d695-0c91-e5a8-91489239eac9.png)

```
<!-- index.html -->
<body>
    <div class="container">
        <div class="box box1"></div>
        <div class="box box2"></div>
        <img class="shiba" src="./img/shiba.jpg" alt="柴犬">
        <div class="box box3"></div>
        <div class="box box4"></div>
    </div>
</body>
```

``` 
/* style.css */
body{
    margin: 0;
}
p{
    margin: 0;
    padding: 0;
}

.box{
    width: 100%;
    height: 50px;
}
.box1{
    background-color: green;
}
.box2{
    background-color: blue;
}
.box3{
    background-color: orange;
}
.box4{
    background-color: pink;
}

.shiba{
    width: 200px;
    height: auto;
    vertical-align: top;
}
```

shibaクラスに対してposition:relative を指定し、下と右にそれぞれ50pxずつ動かしてみます。
```
.shiba{
    /* 追加 */
    position: relative;
    top:50px;
    left:50px;
    
    ...以下省略...
}
```
その結果、このように動きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/968f4f24-ec2d-2235-2665-aba5fb68f444.png)

このように、<b>初期に配置された位置を基準にどれだけ動くかを決定する</b>のがrelativeです。

### position: absolute;
先程の柴犬の画像に対し、position: absolute;を指定し relative と同様の動きを指定します。

```
.shiba{
    /* 追加 */
    position: absolute;
    top:50px;
    left:50px;
    
    ...以下省略...
}
```

結果以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/eab3f12b-8312-c694-dd45-5b5306100f6e.png)

先程とは違い、画像の左上の位置が青色のラインに変化しているのが分かります。
position: absolute; を指定した場合、<b>親要素の左上の地点を基準に位置を決定する</b>ため、初期地点は緑色のラインの左上となり、そこから下右に50pxずつ移動したということになります。

:::note info
<b>親要素に position: relative;</b>を指定した場合、<b>absoluteの基準点がrelativeをつけた親要素の左上に変化する</b>特性があります。

absoluteを使用する場合は、親要素に relative を適用することが一般的です。
:::

少し脱線しましたが、再度今回の事例について見ていきます。
## 再度事例を見てみる。

positionの解説を行ったところで、再度今回の事例について見ていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/baf534ea-031e-ef6e-12aa-cf93ffa51886.png)

上記画像のソースコードは以下のような構成になっています。

```
<!-- index.html -->
<body>
    <div class="container">
        <div class="inner">
        <p class="mv-text">
            新しいソリューション
            <br>
            xxx株式会社
        </p>
        </div>
    </div>
</body>
```
```
/* style.css */
p{
    margin: 0;
    padding: 0;
}

.inner{
    position: relative;
    background: url(./img/background.jpg) no-repeat center center /cover;
    height: 600px;
}

.mv-text{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-size: 50px;
    font-weight: bold;
    text-align: center;
    font-family: 'Times New Roman', serif;
}
```

その中でも、文字を重ねる挙動を担っている記述は以下の通りです。
```
.inner{
    position: relative;
}

.mv-text{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
```
背景画像の上に文字を重ねる場合、<b>背景画像をしている innerクラス に対し、position: relative; を指定し、移動させる mv-textクラスに対し、position: absolute; を適用します。

そうすることで、<b>テキストの初期地点が背景画像の左上になります。</b>
そして、topとleftそれぞれに50%を指定することでテキストを真ん中に移動させます。

しかし、topとleftのみ指定した場合テキストが全体的に右側に寄ってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/687051b8-c0cb-b415-4700-f6ddc00050a5.png)

これは、<b>要素の左上の地点を位置の基準としている</b>ため、テキストの左上が画像の中心に来ている状態です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/d51e91e6-444f-f045-006e-ea1268336552.png)

そのため、transformプロパティを使用し、widthと高さをそれぞれ50%（半分）ずつ後ろに戻してあげます。
    
```
transform: translate(-50%, -50%);
```
そうすることで、文字を中心に移動させることが可能になります！！

### おまけ
position の位置を指定する top, bottom, left, rightは <b>insetプロパティ</b>を使用すると、まとめて指定できます。
適用順は「top, right, bottom, left」の順番です。（topから時計回り）
```
inset: 50% 0 0 50%; /* top, right, bottom, left */
```

## 事例3：FlexBoxで縦並び時に中央寄せができない
最後は少し発展的な事例について紹介します。

要素の中央寄せの方法の一つとして<b>FlexBox</b>を使用する方法があります。
使用するためには、適用した要素に対して、<b>display: flex; を記述します。

例として、以下の4枚の画像をFlexBoxで動かしていきたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/4cf06af0-48f8-88be-87c5-3a67bd79131b.png)

```
<!-- index.html -->
<div class="flex-container">
    <div class="box">
        <img class="content" src="./img/dog1.jpg" alt="">
    </div>
    
    <div class="box">
        <img class="content" src="./img/dog2.jpg" alt="">
    </div>

    <div class="box">
        <img class="content" src="./img/dog3.jpg" alt="">
    </div>

    <div class="box">
        <img class="content" src="./img/dog4.jpg" alt="">
    </div>
</div>
```
各画像が格納されたboxクラスの親要素である、flex-containerクラスに対しdisplay:flex; を適用します。
また、各要素の間にスペースが欲しいので、gapプロパティも同時につけます。
```
/* style.css */
.flex-container{
    display: flex;
    gap: 10px;
    height: 500px;
}
```
そうすることで、各要素が横並びになって表示されます。

:::note info
gap は、flexアイテム等の行・列間の余白を指定できるプロパティです。
marginやpaddingと違い、行初め・終わりに余白がつかないため、効率的なスタイリングが可能になります。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/99659d71-f706-dbf7-ef08-5cc60508ef1f.png)

更にこの状態で中央寄せにしたい場合、flexを適用している要素に  justify-content: center; を適用します。
```
/* style.css*/
.flex-container{
    display: flex;
    justify-content: center;　/*追加*/
    gap: 10px;
    height: 500px;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/7425eef1-67cc-3476-3e43-53e049b7767c.png)
また、上下にも中央寄せしたい場合は、justify-content に加え、align-items:center; を追加します。
```
/* style.css*/
.flex-container{
    display: flex;
    justify-content: center;　
    align-items: center;  /*追加*/
    gap: 10px;
    height: 500px;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/db84e8e0-f63e-3666-56eb-b9393ab3e235.png)
### 今回の問題
ここから、問題のケースについて説明します。
今回の問題は、<b>縦並び</b>になっている flexアイテムを中央寄せする場合です。

flexアイテムを縦並びにする際には、flex-direction: column;を追加します。
```
/* style.css*/
.flex-container{
    display: flex;
    flex-direction: column; /*追加*/
    gap: 10px;
    height: 500px;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/b6c56084-f507-7ed8-71c4-1ab0f670247b.png)

縦並びに戻りましたね！

ただ、この状態で中央寄せしようと justify-content: center; を適用しても中央寄せされることはありません。

```
.flex-container{
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-direction: column;
    height: 500px;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/30af1148-bf93-5c14-6886-631eb05882ac.png)

この原因について見ていきます。

### この問題の原因
今回、中央寄せにならない原因は<b>flex-direction: column;</b>の仕様によるものです。
まずは、flex-direction: column; を適用していない場合について見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/47eadf7e-a361-a85f-3104-69249b60a502.png)

このように、アイテムは横並びになり、<b>主軸が横向きに刺さっている</b>感覚です。
この真ん中に刺さっている主軸を基準に中央寄せなどの移動を行っていきます。

一方、flex-direction: column;を適用した場合はflexアイテムの主軸は以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/93a78ab9-4cc8-3544-775d-9ac4af0b903c.png)

このように、<b>flexアイテムの主軸が90度回転しているのです！</b>
つまり、justify-content と align-items の役割をまとめると以下のようになります。

- justify-content：主軸に対して<b>平行方向の位置を指定する。
- align-items：主軸に対して<b>交差方向（垂直）の位置を指定する。</b>

今回の中央寄せにならない問題は、<b>justify-content を横向きの位置を決定するものと覚えていると起こる問題でした。

flex-diretion:column を指定している際は、主軸が90度回転するため、<b>主軸に対して垂直方向の位置を決定する align-itemsを使うと中央寄せにすることができます！

```
.flex-container{
    height: 500px;
    display: flex;
    gap: 10px;
    align-items: center; /* 修正 */
    flex-direction: column;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341225/febf1f4a-cad7-fbc4-ce28-183f4d2d3e22.png)

無事中央寄せができました！！🎉🎉
このように、flex-direction を使用する際には、挙動が変わることがありますので、是非覚えておきましょう！

## さいごに
ここまで、初心者が躓きそうなスタイリングについてまとめてきました！
HTML＆CSSといったマークアップ言語は、簡単そうに見えて、実は奥が深い言語です。
また、webアプリケーション開発は、バックエンドの勉強が中心になりがちで、HTMLやCSSの勉強は後回しになりがちです。

ですが、ユーザーに利用してもらうためには、美しく、使いやすいUIを作成することが大切です！これを機に是非マークアップ言語の勉強も進めてみてください！😊


ここまでお読みいただきありがとうございました！
その他のアドベントカレンダーにも目を通してみてくださると大変うれしいです！🙏