【CSS】トランジションで色々なボタンを作ってみた

#はじめに
今までBootstrapを使っていたのですが、自分の気に入るデザインが少なかったので、
Bootstrapに頼らずとも自分で出来るように学習しようとCSSに手をつけることに。

HTMLとCSSは少し触ったことがある程度だったのですが、
これを機にしっかり学ぼうということで、まずはトランジションについて学習しました。

記事では、コードと個人的なポイント？を記載しています。
では、早速さまざまなボタンを作っていこうと思います！
（用語とか間違っているかもしれません。すみません・・・。）

##色が変わるボタン
完成は次のようなイメージ
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/1479951b-bf35-3947-4b94-a0e9d3d282d9.gif)
まずは、HTMLファイル

```html:index.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css"> 
</head>

<body>
    <div id="container">
        <button class="btn">Button</button>
    </div>
</body>

</html> 
```
buttonタグにbtnクラスを付与しています。

次に、CSSファイル

```css:style.css
.btn {
  background-color: white;
  border: 1px solid black;
  font-weight: 600;
  width: 150px;
  height: 50px;
  margin: 100px 0;
  cursor: pointer;
  transition: all 0.5s;
}

.btn:hover {
  background-color: black;
  color: white;
}
```
ポイントは、`transition: all 0.5s;`でしょうか。
これを記述すると、btnクラスに関連したトランジションにかかる時間が0.5秒になります。


##背景色がスライドするボタン
完成形は次のようなイメージ
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/e3de1d24-0b03-97b7-8d64-1912a9d48981.gif)
まずは、HTMLファイル

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="container">
        <button class="btn slide-bg">Button</button>
    </div>
</body>
</html>
```
buttonタグには、btnクラスとslide-bgクラスを付与しています。

btnクラスに全て記述すると、他のbuttonタグでもbtnクラスを付与したボタンは、
背景がスライドしてしまうことになります。

なので、**ボタンデザイン**の記述と**背景スライド**の記述を分けました。


次に、CSSファイル

```css:style.css
#container {
  text-align: center;
}

.btn {
  background-color: white;
  color: black;
  font-weight: 600px;
  border: 1px solid black;
  width: 150px;
  height: 50px;
  margin: 100px 0;
  cursor: pointer;
}

.btn.slide-bg {
  position: relative;
  overflow: hidden;
  z-index: 1;
}

.btn.slide-bg::before {
  content: "";
  background-color: black;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  transform: translateX(-100%);
  transition: transform 0.5s;
}

.btn.slide-bg:hover {
  color: white;
}

.btn.slide-bg:hover::before {
  transform: none;
}
```
btnクラスは一つ前と同じです。

`.btn.slide-bg::before {}`の箇所で、ボタンタグの前に擬似要素を作っています。
擬似要素で、ボタンと同じサイズの背景色が黒を作成しています。

そいつを、`transform: translateX(-100%);`で、
ボタンと同じ横幅分、左方向（マイナス方向）に移動しています。

`overflow: hidden;`を消すとこんな感じです。
![スクリーンショット 2021-08-13 19.30.07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/9bbe6072-ace8-62c5-3c5d-ff307cf46583.jpeg)

これを、マウスホバー時に右に持ってくるだけです。

もともと左にずらしていただけなので、
`transform: none;`で元に戻せばOKです。

`z-index`を指定しないと、上手くボタンの文字が表示されないので弄ってます。

##蓋を閉じるような3Dアニメーションボタン
完成形は次のようなイメージ
![ezgif.com-gif-maker (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/79ecd054-7a96-b913-e064-d2dd54f69449.gif)

まずは、HTMLファイル

```html:index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div id="container">
        <button class="btn cover-3d"><span>Button</span></button>
    </div>
</body>

</html>
```
3Dアニメーションを反映させるための、
`cover-3d`クラスを付与しています。

buttonタグ内で、Buttonをspanタグで囲んでいるのにはわけがあるので、
後ほど説明します。

次に、CSSファイル

```css:style.css
#container {
  text-align: center;
}

.btn {
  background-color: white;
  color: black;
  border: 1px solid black;
  width: 150px;
  height: 50px;
  cursor: pointer;
  margin: 100px auto;
  font-weight: 700;
}

.btn.cover-3d {
  position: relative;
  transform-style: preserve-3d;
  perspective: 300px;
}

.btn.cover-3d span {
  display: inline-block;
  transform: translateZ(20px);
}

.btn.cover-3d::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: black;
  opacity: 0;
  transform: rotateX(90deg);
  transform-origin: top center;
  transition: all 1s;
}

.btn.cover-3d:hover {
  color: white;
}

.btn.cover-3d:hover::before {
  opacity: 1;
  transform: none;
}
```

一つ前のボタンと同じで、擬似要素であるbeforeを使用し、
beforeに対して、ボタンと同じサイズの黒色の四角形を作成しています。

これを上から閉じるように表示するわけですが、
3D風にそれを表現するのに必須な記述が以下になります。

```css
.btn.cover-3d {
  position: relative;
  transform-style: preserve-3d;   
  perspective: 300px;
}
```
`transform-style`で3Dにします宣言を行い、
`perspective`でどの程度の奥行きにするか指定します。

perspectiveの値を変更してみるとどのように変わるのかわかるので、
気になる方は50pxとかに値を変更してみてください。

次に擬似要素の記述について。
一部省略しております。

```css
.btn.cover-3d::before {
  --- 省略 ---
  opacity: 0;
  transform: rotateX(90deg);
  transform-origin: top center;
  transition: all 1s;
}
```

初期状態では`opacity`を0にして透明にしております。

その後、`transform: rotateX(90deg);`でX軸方向で90度回転させ、
`transform-origin: top center;`で変形させる要素の中心点の位置を指定します。

opacityを1にすると次のような状態です。
![スクリーンショット 2021-08-13 23.08.27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/3cca08a3-383c-dd9a-6f8e-f62588628826.jpeg)

rotateX(90deg)で90度傾けたのになんか見えるじゃん！と思ってしまいますが、
これは、`perspective: 300px;`で奥行きがついているのでそう見えるだけです。

`perspective: 300px;`を消すと次のようになります。
直角なので、ボーダーのトップと重なって見えません。
![スクリーンショット 2021-08-13 23.10.27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/9d454f3d-2da2-0dcd-1be2-cfc5c7bffd1b.jpeg)

次にホバー時の記述について。

```css
.btn.cover-3d:hover {
  color: white;
}

.btn.cover-3d:hover::before {
  opacity: 1;
  transform: none;
}
```
btnクラスとcover-3dクラスが付与されている要素のテキストの色を白色に、
その擬似要素のopacityを1にし、transformをnoneにしています。

これにより、黒い四角形は表示されてボタンに覆い被さる形で移動します。

次は、なんだかんだ大事な記述について。
bottanタグ内でspanを利用した理由です。

```css
.btn.cover-3d span {
  display: inline-block;
  transform: translateZ(20px);
}
```
このspanタグを使用しないでz-indexを使い実装すると、
蓋が閉じきるまでボタン内のテキストが表示されません。

なぜかというとz-indexは二次元でのみ有効なので、
三次元のトランジションが終了してから反映されます。

閉じている途中で完成形のようにButtonを表示させるためには必要な記述になります。

`transform: translateZ(20px);`で、
蓋が閉じている途中で擬似要素よりも前に出るようにしています。

なお、transformは、inline要素には反映することができないので、
`display: inline-block;`でinline-block要素にしています。

##ブロックが回るような3Dアニメーション
完成形は次のようなイメージ
![ezgif.com-gif-maker (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797483/2bef9636-f00e-b4ba-7b26-970170f6587d.gif)

まずは、HTMLファイル

```html:index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <div id="container">
    <a class="btn cubic"><span class="hovering">Now, Hovering</span><span class="default">Button</span></a>
  </div>
</body>

</html>
```
今回はbuttonタグではなくaタグの中にspanタグを2つ入れて実装します。
aタグでもcssをうまく利用すればボタンのようにすることができます。


次に、CSSファイル

```css:style.css
#container {
  text-align: center;
}

.btn {
  position: relative;
  display: inline-block;
  transform-style: preserve-3d;
  perspective: 300px;
  width: 150px;
  height: 50px;
  cursor: pointer;
  margin: 100px auto;
}

.btn.cubic span {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  line-height: 48px;
  transition: all 1s;
  border: 1px solid black;
  transform-origin: center center -25px;
}

.btn.cubic .hovering {
  background-color: black;
  color: white;
  transform: rotateX(90deg);
}

.btn.cubic .default {
  background-color: white;
  color: black;
  transform: rotateX(0);
}

.btn.cubic:hover .hovering {
  transform: rotateX(0);
}

.btn.cubic:hover .default {
  transform: rotateX(-90deg);
}
```

一つ前のものと記述内容が似ているものは、説明を省きます。

まずはspanタグの記述内容から

```css
.btn.cubic span {
  --- 省略 ---
  transition: all 1s;
  transform-origin: center center -25px;
}
```

`transform-origin: center center -25px;`についてですが、
一つ前でも記述した通り変形させる要素の中心点の位置を指定します。

transform-originは、X軸, Y軸, Z軸の順で記載していきます。

そのため今回は、`center(X軸), center(Y軸), -25px(Z軸)`です。
ちなみにデフォルトは全てcenterになります。

なぜZ軸が-25pxなのかというと、今回のボタンの縦幅が50pxなので、
デフォルトのcenterから-25px分動かす必要があるからです。

ちなみにZ軸のマイナスは奥側です。

では、なぜ-25px動かさないといけないかという話ですが、
流石に文字だけだと説明が難しいので実際に記述してみてください！
-25pxの値をいじっていると、なるほど！となるはずです。(笑)

#さいごに

以上が一通りトランジションで作ることができるボタンになります！

最後の最後で説明は放棄してしまいましたが、
ほんとに言葉だけだと難しいです・・・。

数学みたいに3つのベクトルを書いて考えるとわかりやすいかもしれません！

ちなみに、transfromには、まだまだ色々なプロパティがあるので、
それについてもいつか記事にできたらと思います。

scaleやtranslate、skewなどがあるので、
みなさんも是非使ってください。