## 仕様
><img src="../../image/2025-09-13-03-21-57.png" width="300">
## 実装
[page.tsx](https://github.com/kmishima16/react-project-school/blob/main/app/lesson1/page.tsx)
> <video controls src="https://i.gyazo.com/df4801835b941cedcf591e99b9b464d6.mp4" title="実装" width="300"></video>
TODO
- 実装した
- 3d transform,親のcardと子要素が共通のものを使っているので、子要素単位でコンポーネントを分割できないけどよい?
- reactのuseStateでactiveにクラスが切り替わるような管理しているけど、疑似クラスで表現できないか?
- レスポンシブ対応ができていない
- CSS変数を親子関係のコンポーネントで共有させることは可能?CSS変数はglobal.cssで定義するだけにとどめておくべき?
## マークアップ
- card
- svg
- h3
- p
- toggleボタン
- startボタン
### CSS実装のメモ
- card
- box-shadowは上下左右方向に影を伸ばす
- `display: flex; flex-direction: column; align-items: center;`
- svgContainer
- `display: flex; justify-content: center; align-items: center;`
- h3
- `text-align: left; align-self: flex-start;`
- toggleButtons
- `display: flex; justify-content: center; gap: 1px;`
- startButton
## 余談1: 3dインタラクションにすることで、z-indexなどの重なり順を制御するスタックコンテキストが生まれる
[[スタックコンテキスト]]の処理によって、クリックイベントによる疑似クラスが正しく動作しない場合もあるらしい。
描画順序とスタックコンテキスト
>3D transformを適用すると、その要素は新しいスタックコンテキストを生成します。このスタックコンテキストは、3次元空間での描画順序を決定するために使用されます。子要素はこの新しい3次元空間に配置されますが、マウスのクリックイベントを処理する際には、ブラウザは2次元のビューポート(画面)上での座標を考慮します。
問題のメカニズム
>子要素が3D transformによって手前に移動したり、回転したりすると、画面上での位置は変化しますが、親要素のスタックコンテキストの中では3次元的な配置が優先されます。このため、クリックイベントが実際に子要素に到達する前に、親要素の3D空間の計算が優先されてしまい、:active 擬似クラスが正しく発火しない、または遅延して発火するといった問題が発生します。
[スタックコンテキストとz-indexについて qiita](https://qiita.com/hoto17296/items/42e62989193504d512c7)
[DeesSearch](https://gemini.google.com/app/0f3136466acd5f74?utm_source=app_launcher&utm_medium=owned&utm_campaign=base_all)
- CSS Modulesのクラス名の付与の仕組み上、ブラウザ上で疑似クラスのレンダリングは問題なくできる
- [[LVHA順序]]:
- :link — :visited — :hover — :activeの順でスタイルを定義することで、各状態のスタイルが意図通りに適用されるようになります
- 複雑な条件分岐によるスタイルの変化は、[[clsx]]などのユーティリティライブラリの導入を検討する
- どんな時にReactのstateでスタイルの管理を行うか
- propsで親が子に状態を渡すとき(ex: 商品をホバーすると、別の場所にあるアイテムがハイライトされる)
- JavaScriptのイベントハンドラと連動した複雑な動作
- css modulesにはcomposesというキーワードがあり、クラスのスタイルを継承できる仕組みがある
- ゼロランタイムCSS-in-JSの台頭
- [[Vanilla Extract]]のような,TypeScriptでスタイルを書きながら、パフォーマンスを最大化できるものも出ている
## 余談2:3Dインタラクションじゃなくて、強調ホバーエフェクトの作り方
`transform: scale()`を使って、ホバー時にそのカードを大きく見せるテクニックがあるらしい #CSSテク
>CSS の **`:hover`** 疑似クラスを使えば、カードコンポーネントにカーソルを当てたときに強調するホバーエフェクトを実現できます。最も一般的で簡単な方法は、`box-shadow` や `transform` プロパティを変更することです。
### 1\. `box-shadow` を使って影を付ける
カーソルを当てたときに、要素に影を付けて浮き上がったように見せます。
```css
.card {
/* 通常時のスタイル */
transition: box-shadow 0.3s ease; /* ホバー時の変化を滑らかにする */
}
.card:hover {
/* ホバー時のスタイル */
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); /* 影を付けて強調 */
}
```
**`transition`** を設定することで、ホバーしたときに影が急に現れるのではなく、ゆっくりと滑らかに変化します。
### 2\. `transform: scale()` を使って少し拡大する
要素全体を少しだけ拡大し、強調するホバーエフェクトです。
```css
.card {
/* 通常時のスタイル */
transition: transform 0.3s ease; /* ホバー時の変化を滑らかにする */
}
.card:hover {
/* ホバー時のスタイル */
transform: scale(1.05); /* 1.05倍に拡大 */
}
```
この方法も、**`transition`** を使うことで、拡大がスムーズに行われます。
### 3\. `transform: translateY()` と `box-shadow` を組み合わせる
カードが少し上に移動しながら、影も大きくなるエフェクトです。より立体的な効果を出せます。
```css
.card {
/* 通常時のスタイル */
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
/* ホバー時のスタイル */
transform: translateY(-5px); /* 上に5px移動 */
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); /* 影を大きくして強調 */
}
```
これらを組み合わせることで、より洗練されたホバーエフェクトを作ることができます。重要なのは、**`:hover`** 疑似クラスと、変化を滑らかにするための **`transition`** プロパティをセットで使うことです。