【ハマりポイント解説】CSSでアイコン付きボタンを作る

# はじめに
Web制作においてボタンを実装する際にアイコンつきのボタンを実装するケースが多いかと思います。
加えて、最近はTailwindやUIテンプレートを使用することもあり、なかなか素のCSSを書く機会が減ってきました。
そんな中、久しぶりにCSSを書く機会があり、個人的にホバー時の挙動やアイコンの位置調整で少し躓いたので改めて作り方をざっくりまとめます。

:::note
この記事ではCSSを使ったアイコン付きボタンの作り方を学べます
:::

# 今回作るボタン（完成形）
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="eYbjpmx" data-user="hisa-takeuchi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/hisa-takeuchi/pen/eYbjpmx">
  【ハマりポイント解説】CSSでアイコン付きボタンを作る【完成形】</a> by hisa-takeuchi (<a href="https://codepen.io/hisa-takeuchi">@hisa-takeuchi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

よく見る詳細画面へ遷移するボタンを作っていきます。
ところどころ、ハマりポイントがあるので一つずつ紹介していきます。

# ①ホバーしたときにボタンの高さがほんの少しずれる
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYyLGMy" data-user="hisa-takeuchi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/hisa-takeuchi/pen/zYyLGMy">
  【ハマりポイント解説】CSSでアイコン付きボタンを作る【完成形】</a> by hisa-takeuchi (<a href="https://codepen.io/hisa-takeuchi">@hisa-takeuchi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 原因
ホバーをした際にボーダーが表示されるため、ボーダーの高さ分要素の高さが増えてしまうためです。
これはCSSのボックスモデルから来ているもので、ボーダーの幅は要素自体の高さに含まれるためこのような事象が発生します。
[参考：今更聞けない！エンジニアのための CSS の基礎講座 〜ボックスモデル編〜](https://nulab.com/ja/blog/nulab/css-basics-for-engineer-boxmodel/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527256/f17ae30a-7ded-4618-1dc2-8b0a079af01a.png)

## 解決方法
通常時の要素自体に背景色と同じ色のボーダーをつけてあげることで、ホバーをしたときも要素の高さを維持することができます。

```scss
.btn {
    padding: 15px 20px 15px 0px;
    width: 300px;
    color: #fff;
    font-size: 20px;
    background-color: #0099FF;
    border: 1px solid #0099FF; // ①背景色と同じ色のボーダーを追加
 /** 略 **/
```

# ②画面サイズが狭まるとアイコンとテキストが被ってしまう
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwqBvKj" data-user="hisa-takeuchi" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/hisa-takeuchi/pen/VwqBvKj">
  【ハマりポイント解説】CSSでアイコン付きボタンを作る【ポイント②】</a> by hisa-takeuchi (<a href="https://codepen.io/hisa-takeuchi">@hisa-takeuchi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

画面サイズを狭めると分かる通り、テキストとアイコンが被ってしまいます。
これだとモバイル端末で見たときにテキストが読みづらくなってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527256/2b169c4b-bba3-3668-b45b-d4e412fc9b6e.png)

## 解決方法
before要素はアイコンの水平位置を要素の中央から起点に配置させます。
つまり、`calc`を使って要素の水平位置の中央を指定（50%）し、そこからアイコンを配置したい分だけ位置を指定すれば良いわけです。
左に動かしたければ、`calc(50% + 動かしたい数値)` としてください。
```scss
&::before {
      position: absolute;
      content: "\f105";
      font-family: "Font Awesome 6 Free";
      font-weight: 900;
      top: 50%;
      // right: 40%; // 要素の右から配置すると画面サイズが狭まったときにテキストに被る
      right: calc(50% - 70px); //②中央を起点に位置指定する
      transform: translatey(-50%);
    }
```

# 最後に
素直にCSSを書いていくだけだと、思わぬ落とし穴にハマってしまうことがあります。
特にボタンに関してはCSSを理解していないとスタイルが崩れてしまったり、思ったように表示されなかったりと意外と実装難易度は高めだと思います。

昨今はモダンなCSSフレームワークやUIテンプレートを使用する機会が増え、CSSの理解が足りなくてもレイアウトをいい感じに実装できる時代にはなっていますが、初心に帰ってHTMLとCSSのみでコーディングすることで、様々な気づきがありました。

この記事が誰かの役に立つことを願っております。