L-002 Layout medium

How to create a layered card stack カードスタックレイアウトの作り方

Stacked cards that float on hover with offsets controlled by a custom property. ずらしたカードを重ねてホバー時に浮かせるレイアウト。カスタムプロパティでオフセット量を調整できます。

ライブデモ Live Demo

New

Advanced Analytics

Deep insights into user behavior patterns with real-time tracking and custom dashboards.

Pro

Team Collaboration

Enhanced workflow tools for seamless team communication and project management.

Basic

Essential Features

Core functionality to get started with powerful automation and integrations.

8px ホバーモード Hover Mode

概要・用途・特徴Overview, Usage & Features

何ができるかWhat it does

Stacked cards that float on hover with offsets controlled by a custom property.

ずらしたカードを重ねてホバー時に浮かせるレイアウト。カスタムプロパティでオフセット量を調整できます。

どこで使うかWhere to use

landing page, marketing site, portfolio, product page

NFTコレクション、写真ギャラリープレビュー、タスクグループ、ドキュメントスタック

特徴Key features

Stacked card effect using CSS transform: translateY and z-index. Simulates a physical deck of cards. Hover fans out the stack for preview. Clickable to select/bring to front. Fully CSS-driven visual with minimal JavaScript.

CSS transform:translateYとz-indexによるスタックカードエフェクト。物理的なカードデッキをシミュレート。ホバーでプレビューのためにスタックを扇状に広げる。クリックで選択/前面に表示。最小限のJavaScriptによる完全CSS駆動のビジュアル。

調整可能パラメータ Adjustable Parameters

Parameter Default Description
--stack-offset8pxvertical offset distance between layers
--stack-scale0.95scale ratio for background cards
--stack-spread16pxhorizontal spread distance used in spread mode
stack modeliftswitch between lift and spread hover behavior

実装コード Implementation Code

// react/L-002.jsx
import "./L-002.css";

const cards = [
  { badge: "New", title: "Analytics", desc: "Deep insights..." },
  { badge: "Pro", title: "Collaboration", desc: "Team tools..." },
  { badge: "Basic", title: "Essentials", desc: "Core features..." },
];

export default function LayeredCardStack({ offset = 8 }) {
  return (
    <div className="card-stack" style={{ ["--stack-offset"]: `${offset}px` }}>
      {cards.map((card) => (
        <div key={card.title} className="stack-card">
          <span className="card-badge">{card.badge}</span>
          <h3>{card.title}</h3>
          <p>{card.desc}</p>
        </div>
      ))}
    </div>
  );
}
/* react/L-002.css */
.card-stack {
  position: relative;
  max-width: 400px;
  padding-top: calc(var(--stack-offset) * 2);
}

.stack-card {
  position: relative;
  background: linear-gradient(135deg, #1a1f3a, #2a3256);
  border-radius: 20px;
  padding: 24px;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.stack-card:nth-child(2) {
  transform: scale(0.98) translateY(calc(var(--stack-offset) * -1));
  margin-top: calc(var(--stack-offset) * -1);
}

.stack-card:nth-child(3) {
  transform: scale(0.96) translateY(calc(var(--stack-offset) * -2));
  margin-top: calc(var(--stack-offset) * -1);
  opacity: 0.8;
}

.stack-card:hover {
  transform: scale(1.02) translateY(-8px);
  box-shadow: 0 20px 40px rgba(92, 106, 196, 0.3);
  z-index: 10;
}
import { useState } from "react";
import "./L-002.css";

const items = [
  { title: "Research", body: "Collect customer signals." },
  { title: "Design", body: "Craft flows and prototypes." },
  { title: "Launch", body: "Ship incremental releases." },
];

export default function LayeredCardStack() {
  const [gap, setGap] = useState(18);

  return (
    <div className="card-stack" style={{ "--stack-gap": `${gap}px` }}>
      {items.map((item, index) => (
        <article key={item.title} style={{ zIndex: index + 1 }}>
          <h4>{item.title}</h4>
          <p>{item.body}</p>
        </article>
      ))}
      <input
        className="card-stack__slider"
        type="range"
        min="8"
        max="28"
        value={gap}
        onChange={(event) => setGap(Number(event.target.value))}
      />
    </div>
  );
}
:root {
  --stack-gap: 18px;
}

.card-stack {
  position: relative;
  width: min(360px, 100%);
  height: 260px;
  margin: 0 auto;
}

.card-stack article {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  padding: 24px;
  background: linear-gradient(150deg, #111632, #1c2450);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: #f7f8ff;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card-stack article:nth-child(1) {
  transform: translate(calc(var(--stack-gap) * -1), var(--stack-gap));
}

.card-stack article:nth-child(2) {
  transform: translate(calc(var(--stack-gap) * -0.3), calc(var(--stack-gap) * 0.2));
}

.card-stack article:nth-child(3) {
  transform: translate(calc(var(--stack-gap) * 0.5), calc(var(--stack-gap) * -0.6));
  background: linear-gradient(150deg, #5c6ac4, #22d3ee);
}

.card-stack article:hover {
  transform: translate(0, -10px);
  box-shadow: 0 30px 60px rgba(5, 7, 18, 0.6);
}

.card-stack__slider {
  position: absolute;
  bottom: -48px;
  left: 0;
  width: 100%;
}

仕組みとカスタマイズHow It Works & Customization

仕組みHow it works

Cards are absolutely positioned within a relative container. Each card gets a progressively increasing translateY (or rotate) offset and decreasing z-index to create the stacking illusion. On :hover of the container, CSS or JavaScript fans the cards out by updating their transforms to distinct positions, revealing all cards in the stack.

カードはrelativeコンテナ内に絶対配置。各カードはスタックイリュージョンを作るために徐々に増加するtranslateY(またはrotate)オフセットと減少するz-indexを持ちます。コンテナの:hoverで、CSSまたはJavaScriptがカードのトランスフォームを異なる位置に更新し、スタック内のすべてのカードを明示するよう扇状に広げます。

カスタマイズ方法Customization

Replace translateY with rotate for a fan-out spread instead of a vertical stack. Add a perspective transform on the container for a 3D deck effect. Implement click-to-bring-front by updating z-index on click.

translateYをrotateに置き換えて縦積みでなく扇状の広がりに。コンテナにperspectiveトランスフォームを追加して3Dデッキエフェクトに。クリック時にz-indexを更新するクリックで前面表示を実装。

注意点Caveats

Overlapping cards can create confusing tab order. Use inert or tabindex="-1" on non-top cards to prevent keyboard users from focusing hidden cards. Announce the active card to screen readers via aria-live when it changes.

重なったカードは混乱したタブ順序を作る可能性があります。キーボードユーザーが非表示カードにフォーカスしないよう、トップでないカードにinertまたはtabindex="-1"を使用してください。変更時にaria-liveでアクティブカードをスクリーンリーダーにアナウンスしてください。

よくある質問 Frequently Asked Questions

How to customize the layered card stack? Layered Card Stackをカスタマイズするには?

Modify the CSS custom properties and class styles defined in the code section. Key adjustable values include colors, sizes, durations, and spacing. See the Adjustable Parameters section for specific variables.

コードセクションで定義されているCSSカスタムプロパティとクラススタイルを変更してください。色、サイズ、時間、間隔が主な調整可能値です。具体的な変数は調整可能パラメータセクションを参照してください。

How to use the layered card stack in React? ReactでLayered Card Stackを使うには?

Import the provided React component and its CSS file. The component accepts props for customization. Check the React code section for the full implementation and available props.

提供されているReactコンポーネントとCSSファイルをインポートしてください。コンポーネントのpropsでカスタマイズできます。完全な実装と利用可能なpropsはReactコードセクションを参照してください。

What are the performance implications of layered card stack? Layered Card Stackのパフォーマンスへの影響は?

This implementation uses CSS transforms and opacity for animations, which are GPU-accelerated. It's lightweight and doesn't cause layout thrashing. Consider using prefers-reduced-motion for accessibility.

この実装はCSSのtransformとopacityを使用しており、GPUアクセラレーションされます。軽量でレイアウトスラッシングを引き起こしません。アクセシビリティのためにprefers-reduced-motionの使用を検討してください。

AIへの指示テンプレート AI Prompt Template

以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.