【CSS】ホバーするとキラキラ光って見えるカードを作る

## はじめに
みなさんは、どんなトレーディングカードゲームをやったことがありますか？

僕が触れたことがあるトレーディングカードゲームは、**遊戯王**、**デュエマ**、**ポケカ**くらいですが、他にも、1993年からある**マジック:ザ・ギャザリング**や最近の**ワンピース** などなどいろいろなトレーディングカードゲームが存在します。

それらのほとんどのトレーディングカードゲームには、カードにレアリティと呼ばれる希少度の段階があるため、カードゲームで対戦するだけでなく、コレクションされたり、高額になったりと奥が深いです。

今回は、そんなカードゲームのレアリティを表現をCSSとJavaScriptを使って、ホバーするとキラキラ光って見えるカードを作っていこうと思います。

## 完成形
完成形は、↓こんな感じです。
<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="JjZZMve" data-user="sp_degu" 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/sp_degu/pen/JjZZMve">
  Light Card</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

hoverしたところにハイライトが当たったり、マウスの位置に合わせて、グラデーションが移動したりすることで、キラキラ光って見えるように表現しています。

また、CSSのプロパティの観点では、`repeating-radial-gradient`・`linear-gradient`を`mix-blend-mode`を使って、いい感じに画像を加工していて、キラキラ光って見えるように表現しています。

詳しい作り方は、これから解説していきます。

## 作り方

### 1. 構成を理解する
まずは、今回作成するキラキラ光って見えるような表現の構成解説していきます。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/d2fb4624-953b-11c0-283b-1bf99776f13f.png)

キラキラ光って見えるような表現は、↑このように「**画像層**」「**パターン層**」「**カラー層**」「**ハイライト層**」の4層で作成しています。これらの層で、`mix-blend-mode` を使ってそれっぽくしています。

- **画像層**
    - 画像層は、キラキラ光らせたい画像を置きます。
- **パターン層**
    - パターン層は、光らせる模様を置きます。 SVG等の画像でも可能です。
- **カラー層**
    - カラー層は、光らせるグラデーションを置きます。 複雑なグラデーションだとそれっぽくさが増します。
- **ハイライト層**：
    - ハイライト層は、ホバーした時のハイライトを作る層です。


### 2. HTMLを作成する
1の構成になるように、HTMLの構造を以下のように作成していきます。

```sample.html
<div class="card-wrapper">
  <img class="card" src="../../image.jpeg" />
  <div class="card pattern"></div>
  <div class="card color"></div>
  <div class="card highlight"></div>
</div>
```

`<img>` に `::before`　`::after`　`:hover` を駆使しても、いい感じに作ることができますが、
わかりやすさ重視で `<div>` で分けて作成しています。

また、`:hover` している位置を取得して輝きの表現をするため、
位置取得するための `<div class="card-wrapper">` でラップします。

### 3. 各層を重ねて、形を整える
次に**画像層**・**パターン層**・**カラー層**・**ハイライト層**をCSS Gridと `position: absolute;` を使って重ねて、形を整えて行きます。

```sample.css
/*形を整える*/
.card {
  aspect-ratio: 3 / 4;
  border-radius: 4.5% / 3.5%;
  box-shadow: 0px 4px 8px rgba(0, 0, 0, .2);
  height: 100%;
  position: absolute;
  width: 100%;
}

.card-wrapper {
  aspect-ratio: 3 / 4;
  display: grid;
  height: calc(100% - 32px);
  max-width: 100%;
  place-items: center;
  position: absolute;
}

/*真ん中に持ってきている*/
body {
  background-color: #212529;
  display: grid;
  height: calc(100vh - 32px);
  margin: 0;
  padding: 16px;
  place-items: center;
  position: relative;
  width: calc(100% - 32px);
}
```
　
### 4. パターン層とカラー層のCSSを作成する
次に**パターン層**・**カラー層**のCSSを作成します。
#### パターン層
```sample.css
.pattern {
  background: repeating-radial-gradient(circle at -150% -25%, #fff, #777 3px, #fff 3px);
  background-position: 50% 50%;
  background-size: 120% 120%;
  mix-blend-mode: color-dodge;
  opacity: 0.3;
}
```
パターン層は、`repeating-radial-gradient` を使って、白黒のパターンを作成します。
また、`:hover` で `background-position` で移動させるため、 `background-size` を120%にしています。

`mix-blend-mode` ・ `opacity` で、画像を加工すると、以下のように画像が加工されます。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/c7bb8353-5d51-e7f6-6af2-a4e938f77c52.png)

#### カラー層
```sample.css
.color {
  background: linear-gradient(115deg, transparent 20%, #40A4BF 30%, transparent 48% 52%, #404FBF 70%, transparent);
  background-position: 50% 50%;
  background-size: 200% 200%;
  mix-blend-mode: overlay;
}
```
カラー層は、`linear-gradient` を使って、グラデーションを作成します。
また、`:hover` で `background-position` で移動させるため、 `background-size` を200%にしています。

`mix-blend-mode`で、画像を加工すると、以下のように画像が加工されます。
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/23b8b28b-191f-c195-9b86-1fa762a9723a.png)

### 5. マウスの位置に応じた、アニメーションを作成する
#### カード内のマウスの位置を取得する
```sample.js
console.clear()

const CARD = document.querySelector('.card-wrapper')

const UPDATE = ({ x, y }) => {
  const BOUNDS = CARD.getBoundingClientRect()
  const posX = x - BOUNDS.x
  const posY = y - BOUNDS.y
  const ratioX = posX / BOUNDS.width
  const ratioY = posY / BOUNDS.height
  CARD.style.setProperty('--ratio-x', ratioX)
  CARD.style.setProperty('--ratio-y', ratioY)
}

document.body.addEventListener('pointermove', UPDATE)
```
`addEventListener` の `'pointermove'` で、マウスポインターの位置を取得します。

また、マウスポインターがカード内のどの位置にあるのかをいい感じに計算しした値を
cssの変数(`--ratio-x`・`--ratio-y`)で使えるように、`.card-wrapper`のstyle属性に定義して、います。

以下の画像のように計算しています。
![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/763243e6-543f-fb7a-a549-fd9f83ea57c7.png)


#### カード内の要素がマウスの位置に応じて動くようにする
```sample.css
.card-wrapper:hover > .pattern {
  background-position: calc(50% + (var(--ratio-x) * -50%)) calc(50% + (var(--ratio-y) * -50%));
}

.card-wrapper:hover > .color {
  background-position: calc(50% + (var(--ratio-x) * -50%)) calc(50% + (var(--ratio-y) * -50%));
}

.card-wrapper:hover > .highlight {
  background: radial-gradient(circle at calc(var(--ratio-x) * 100%) calc(var(--ratio-y) * 100%), hsl(0 0% 100% / 0.2), transparent 50%);
  background-repeat: no-repeat;
}
```

`.pattern` と `.color`は、マウスポインターの位置に応じて、`background-position`の位置を変更しています。

`.highlight`は、`radial-gradient` の中心点をマウスポインターの位置にしてマウスに追従する形にしています。


### 完成
このようにhoverしたところにハイライトが当たったり、マウスの位置に合わせて、グラデーションが移動したりすることで、キラキラ光って見えるように表現しています。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="JjZZMve" data-user="sp_degu" 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/sp_degu/pen/JjZZMve">
  Light Card</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


## まとめ
今回は、トレーディングカードゲームのレアリティを表現のようなホバーするとキラキラ光って見えるカードを
CSSとJavaScriptを使って作りました。

キラキラ光って見えるカードの構成イメージがわかるようにシンプルになるように意識して作りましたが、ここからパターン層のパターンをSVG等の画像にして複雑なものにしたり、カラー層のグラデーションを複雑でたくさんの色を使うことで、トレーディングカードゲームのレアリティを表現にもっとも近づくと思います。

この表現がトレーディングカードゲームのカードのweb通販のサイトや、クレジットカードの比較アフィリエイトサイトとかで、使われると見るだけで楽しいものになるのかなとかと感じました。


↓この記事のカードを立体的にアニメーションを追加するとなおクオリティが高くなります。

https://qiita.com/degudegu2510/items/a0ad925aaf09181a5390

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510