ホバー
CSSだけで作る、ホバーで広がるインタラクティブカードギャラリー
2026/04/06
2026/4/2
複数のコンテンツを一覧表示するとき、ただ並べるだけでは視線誘導が弱くなりがちです。このカードギャラリーは、マウスホバーに応じてカードが滑らかに拡張し、注目コンテンツを自然に強調できるUIです。JavaScriptを使わずCSSのみで実装できるため、軽量で導入しやすく、ポートフォリオや特集一覧、LPのビジュアルセクションにも適しています。
Preview プレビュー
Code コード
<div class="cards">
<div class="card">
<a href="#">
<img src="https://picsum.photos/id/1015/800/600" alt="画像 1" />
<div class="card-title">カード 1</div>
<p class="card-desc">カード 1に関する説明文がここに入ります。</p>
</a>
</div>
<div class="card">
<a href="#">
<img src="https://picsum.photos/id/1022/800/600" alt="画像 2" />
<div class="card-title">カード 2</div>
<p class="card-desc">カード 2に関する説明文がここに入ります。</p>
</a>
</div>
<div class="card">
<a href="#">
<img src="https://picsum.photos/id/1035/800/600" alt="画像 3" />
<div class="card-title">カード 3</div>
<p class="card-desc">カード 3に関する説明文がここに入ります。</p>
</a>
</div>
<div class="card">
<a href="#">
<img src="https://picsum.photos/id/1045/800/600" alt="画像 4" />
<div class="card-title">カード 4</div>
<p class="card-desc">カード 4に関する説明文がここに入ります。</p>
</a>
</div>
<div class="card">
<a href="#">
<img src="https://picsum.photos/id/1055/800/600" alt="画像 5" />
<div class="card-title">カード 5</div>
<p class="card-desc">カード 5に関する説明文がここに入ります。</p>
</a>
</div>
</div>
body {
margin: 0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #f0f2f5;
font-family: "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
color: #333;
}
.cards {
display: flex;
flex-wrap: nowrap;
width: min(1200px, 95vw);
height: 400px;
overflow: hidden;
border-radius: 1rem;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
background: #fff;
}
.card {
flex: 1 1 0;
min-width: 0;
height: 100%;
cursor: pointer;
transition: flex 0.5s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
position: relative;
}
.card:hover {
flex: 5;
}
.card a {
display: block;
width: 100%;
height: 100%;
text-decoration: none;
color: inherit;
}
.card img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.5s ease, filter 0.5s ease;
filter: grayscale(100%);
}
.card:hover img {
transform: scale(1.1);
filter: grayscale(0%);
}
.card::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent 60%);
opacity: 0;
transition: opacity 0.3s ease;
z-index: 1;
}
.card:hover::after {
opacity: 1;
}
.card-title {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 10px 20px;
border-radius: 4px;
font-size: 1.2rem;
font-weight: bold;
transition: all 0.3s ease;
z-index: 2;
white-space: nowrap;
}
.card:hover .card-title {
top: 40%;
background: #fff;
color: #000;
}
.card-desc {
position: absolute;
z-index: 3;
left: 0;
right: 0;
bottom: 0;
margin: 0;
transform: translateY(100%);
transition: transform 0.3s ease;
padding: 1.5rem;
color: #fff;
font-size: 1rem;
text-align: center;
white-space: normal;
}
.card:hover .card-desc {
transform: translateY(0);
}
@media (max-width: 768px) {
.cards {
flex-direction: column;
height: 700px;
width: 90vw;
}
.card {
flex: 1 1 0;
min-height: 0;
width: 100%;
}
.card:hover {
flex: 3;
}
.card-title {
font-size: 1rem;
}
.card-desc {
padding: 1rem;
font-size: 0.9rem;
}
}
Explanation 詳しい説明
基本構造
カード全体は .cards コンテナの中に複数の .card 要素を横並びで配置するシンプルな構造です。
Flexbox を利用してカード幅を自動分配し、各カード内部にリンク・画像・タイトル・説明文を配置しています。
.card は flex: 1 を基準サイズとして並び、ホバー時のみ flex の値を変更することで横方向に拡張される仕組みになっています。
仕様
このUIの最大の特徴は、JavaScriptを使わず flex の伸縮アニメーションだけでインタラクションを実現している点です。
ホバー時の主な挙動は以下です。
・カードの flex 値が増加し横幅が拡張される
・画像が拡大(scale)する
・グレースケールが解除されカラー表示になる
・グラデーションオーバーレイが表示される
・タイトル位置と配色が変化する
・下部から説明文がスライド表示される
これらを transition のみで同期させることで、自然なアニメーション体験を作っています。
カスタムできるポイント
カードの広がり方は .card:hover { flex: 5; } の数値を変更することで調整できます。数値を大きくすると強調度が増し、小さくすると控えめな動きになります。
アニメーション速度は transition: flex 0.5s cubic-bezier(...) を変更することで調整可能です。イージングを変更すると印象も大きく変わります。
画像演出は以下を変更することで簡単にカスタマイズできます。
・ズーム量 → transform: scale()
・モノクロ度 → filter: grayscale()
・暗転の強さ → ::after のグラデーション透明度
・タイトルデザイン → .card-title の背景色や位置
カード枚数は .card を追加するだけで自動的にレイアウトへ反映されます。
注意点
Flexboxの特性上、カード数が極端に多い場合は初期幅が狭くなりすぎるため、表示枚数は4〜6枚程度が最も見やすくなります。
ホバー操作を前提としているため、スマートフォンでは同じ体験にならない点に注意が必要です。本コードではメディアクエリを使用し、モバイル時は縦並びレイアウトへ切り替え、常時説明文を表示する設計になっています。
また、画像は object-fit: cover を使用しているため、重要な被写体が中央付近に配置された画像を使用すると見切れを防げます。
パフォーマンス面ではCSSのみで動作するため軽量ですが、大きな画像を多数使用する場合は画像サイズ最適化を行うことで表示速度を維持できます。