ReactでCSSグリッドを使ったレスポンシブなカードレイアウトの作り方

CSSグリッドは、Webデザインにおける強力なレイアウトシステムで、特に複雑なレイアウトやレスポンシブデザインを簡単に実現することができます。本記事では、このCSSグリッドをReactアプリケーションに取り入れ、レスポンシブなカードレイアウトを構築する方法について解説します。特に、画面サイズに応じてカードの配置を自動的に調整する仕組みや、動的データの表示方法を中心に説明し、応用例としてフィルタリングやソート機能の追加も紹介します。React初心者にも理解しやすい形で、CSSグリッドの基礎から実践までを丁寧に説明していきます。

目次

CSSグリッドの基本概念


CSSグリッドは、2次元のレイアウトを効率的に構築するためのCSSプロパティ群です。これにより、行と列を用いた柔軟なデザインが可能になります。

CSSグリッドの特徴


CSSグリッドは、以下のような特徴を持っています:

  • 行と列の明確な定義:行(rows)と列(columns)を簡単に設定でき、レイアウトの可視性が高まります。
  • レスポンシブデザインの強力なサポート:メディアクエリと組み合わせることで、画面サイズに応じた調整が容易です。
  • アイテムの配置制御:グリッド内のアイテムを任意の位置に配置できるため、複雑なデザインを実現できます。

CSSグリッドの基本構文


以下はCSSグリッドの基本的な設定例です:
“`css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3列の等間隔グリッド / gap: 20px; / アイテム間のスペース */
}

.item {
background-color: lightblue;
padding: 20px;
}

<h3>グリッドのユニット</h3>  
CSSグリッドでは、以下のようなユニットを使用します:  
- **fr(フラクション)**:利用可能な空間を分割するための単位。  
- **px(ピクセル)や%(パーセント)**:固定サイズや相対サイズを指定するための単位。  

CSSグリッドの基本概念を理解することで、複雑なレイアウトでも効率よくデザインすることができます。この基礎を元に、Reactアプリケーションでの実践的な実装に進んでいきましょう。
<h2>ReactとCSSグリッドの連携方法</h2>  

<h3>ReactでCSSグリッドを使用する準備</h3>  
ReactでCSSグリッドを使うには、通常のCSSファイルを作成してReactコンポーネントに適用する方法が一般的です。また、CSS-in-JSのライブラリ(例:styled-components)を使用することも可能です。以下に基本的な流れを示します:  

<h4>手順1: CSSファイルを作成</h4>  
CSSファイルにグリッドのスタイルを記述します。  

css
/* styles.css / .container { display: grid; grid-template-columns: repeat(3, 1fr); / 3列のグリッド */
gap: 20px;
}

.item {
background-color: lightblue;
padding: 20px;
}

<h4>手順2: ReactコンポーネントにCSSを適用</h4>  
CSSファイルをインポートして適用します。  

jsx
import React from ‘react’;
import ‘./styles.css’;

const GridComponent = () => {
return (

Card 1

Card 2

Card 3
);
};

export default GridComponent;

<h3>CSS-in-JSでのCSSグリッドの適用</h3>  
CSS-in-JSを使う場合、以下のように書きます。  

jsx
/** @jsxImportSource @emotion/react */
import { css } from ‘@emotion/react’;

const containerStyle = css display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; ;

const itemStyle = css background-color: lightblue; padding: 20px; ;

const GridComponent = () => {
return (

Card 1

Card 2

Card 3
);
};

export default GridComponent;

<h3>ReactとCSSグリッドの連携の利点</h3>  
- **コンポーネント単位の分離**:スタイルと構造を分離しつつ、再利用可能なUIパーツを作成できます。  
- **動的レンダリング**:Reactの動的データバインディングを利用して、グリッド内のアイテムを動的に追加・変更できます。  

この連携方法により、Reactの再利用性とCSSグリッドの強力なレイアウト機能を最大限活用できます。次はレスポンシブデザインの実現方法に進みます。  
<h2>CSSグリッドによるレスポンシブデザインの仕組み</h2>  

<h3>レスポンシブデザインとは</h3>  
レスポンシブデザインは、デバイスの画面サイズや解像度に応じてレイアウトを調整する設計手法です。CSSグリッドは、メディアクエリと組み合わせることで簡単にレスポンシブなレイアウトを実現できます。  

<h3>CSSグリッドのレスポンシブ設定</h3>  
CSSグリッドでは、`grid-template-columns`プロパティをメディアクエリ内で変更することで、画面サイズに応じたレイアウトを設定します。以下はその基本的な例です:  

css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* デフォルトは3列 */
gap: 20px;
}

@media (max-width: 768px) {
.container {
grid-template-columns: repeat(2, 1fr); /* タブレットでは2列 */
}
}

@media (max-width: 480px) {
.container {
grid-template-columns: 1fr; /* スマートフォンでは1列 */
}
}

<h3>Reactでの適用例</h3>  
以下のReactコンポーネントでは、画面サイズに応じてカードの数が自動調整されます:  

jsx
import React from ‘react’;
import ‘./styles.css’;

const ResponsiveGrid = () => {
const cards = Array.from({ length: 9 }, (_, index) => Card ${index + 1});

return (

{cards.map((card, index) => (

{card}

))}

);
};

export default ResponsiveGrid;

<h3>CSSグリッドのauto-fitとauto-fill</h3>  
さらに、CSSグリッドの`auto-fit`や`auto-fill`を使用すると、より柔軟なレスポンシブレイアウトが可能です。以下の例では、カードが画面サイズに応じて自動的に配置されます:  

css
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}

<h3>利点と応用</h3>  
- **メンテナンス性の向上**:コードがシンプルで、異なるデバイス対応が容易。  
- **動的データにも適応**:Reactでの動的なカード追加にも対応可能。  
- **ユーザー体験の向上**:どのデバイスでも最適なレイアウトを提供可能。  

次に、この仕組みを活用して具体的なカードレイアウトの設計と実装方法を見ていきます。  
<h2>カードレイアウトの設計とコーディング</h2>  

<h3>カードレイアウトの設計</h3>  
カードレイアウトは、情報を視覚的に整理しやすいUIデザインの一種です。以下の要素を含めることで、使いやすく美しいデザインを実現できます:  
- **視覚的な分離**:カードごとに明確な境界を設けることで情報を区別。  
- **レスポンシブ対応**:画面サイズに応じて柔軟に配置を変更。  
- **情報の要約**:カード内にタイトル、画像、説明、アクションボタンなどを適切に配置。  

<h3>カードのHTML構造</h3>  
以下は基本的なカードレイアウトのHTML構造です:  

jsx

Card Image

Card Title

This is a description of the card content.Learn More

<h3>カードレイアウトのCSS</h3>  
以下はカードを美しくレイアウトするCSS例です:  

css
.card {
background: #fff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
display: flex;
flex-direction: column;
}

.card-image {
width: 100%;
height: 150px;
object-fit: cover;
}

.card-content {
padding: 16px;
}

.card-title {
font-size: 1.25rem;
margin: 0 0 8px;
}

.card-description {
font-size: 1rem;
color: #666;
margin: 0 0 16px;
}

.card-button {
background: #007bff;
color: #fff;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
text-align: center;
}

.card-button:hover {
background: #0056b3;
}

<h3>Reactでのカードリストの実装</h3>  
カードを複数表示する場合、Reactでのループ処理を活用します:  

jsx
import React from ‘react’;
import ‘./styles.css’;

const Card = ({ title, description, image }) => (

{title}

{title}

{description}Learn More


);

const CardList = () => {
const cards = [
{ title: ‘Card 1’, description: ‘Description for card 1’, image: ‘https://via.placeholder.com/150’ },
{ title: ‘Card 2’, description: ‘Description for card 2’, image: ‘https://via.placeholder.com/150’ },
{ title: ‘Card 3’, description: ‘Description for card 3’, image: ‘https://via.placeholder.com/150’ },
];

return (

{cards.map((card, index) => ( ))}
);
};

export default CardList;

<h3>完成したカードレイアウト</h3>  
このコードにより、動的に生成されるカードがCSSグリッドを活用して整然と配置されます。次は、Reactコンポーネントでの動的データ表示について掘り下げます。  
<h2>Reactコンポーネントでの動的データ表示</h2>  

<h3>動的データ表示の概要</h3>  
Reactでは、動的なデータを扱うことで、ユーザー入力やAPIから取得した情報を柔軟に表示できます。カードレイアウトに動的データを組み込むことで、リストやギャラリーのようなコンテンツをリアルタイムに更新可能です。  

<h3>動的データの取得と処理</h3>  
動的データは以下のようにしてReactコンポーネントで扱います:  
- **静的データ**:ローカルに定義した配列などを使用。  
- **APIからのデータ取得**:`fetch`や`axios`を使用して外部からデータを取得。  

以下はAPIから取得したデータを動的に表示する例です:  

<h3>静的データを用いた例</h3>  

jsx
import React from ‘react’;

const StaticCardList = () => {
const cards = [
{ id: 1, title: ‘Card 1’, description: ‘Description for card 1’ },
{ id: 2, title: ‘Card 2’, description: ‘Description for card 2’ },
{ id: 3, title: ‘Card 3’, description: ‘Description for card 3’ },
];

return (

{cards.map((card) => (

{card.title}

{card.description}

))}

);
};

export default StaticCardList;

<h3>APIから動的にデータを取得</h3>  

jsx
import React, { useState, useEffect } from ‘react’;

const DynamicCardList = () => {
const [cards, setCards] = useState([]);

useEffect(() => {
// APIからデータを取得
fetch(‘https://jsonplaceholder.typicode.com/posts?_limit=3’)
.then((response) => response.json())
.then((data) => {
const formattedData = data.map((item) => ({
id: item.id,
title: item.title,
description: item.body,
}));
setCards(formattedData);
});
}, []);

return (

{cards.map((card) => (

{card.title}

{card.description}

))}

);
};

export default DynamicCardList;

<h3>動的データの表示を最適化</h3>  
- **ローディング状態の管理**:データ取得中にローディングスピナーを表示します。  
- **エラー処理**:データ取得失敗時のメッセージ表示を追加します。  

以下はローディングとエラー処理を組み込んだ例です:  

jsx
import React, { useState, useEffect } from ‘react’;

const DynamicCardListWithLoading = () => {
const [cards, setCards] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
fetch(‘https://jsonplaceholder.typicode.com/posts?_limit=3’)
.then((response) => {
if (!response.ok) {
throw new Error(‘Failed to fetch data’);
}
return response.json();
})
.then((data) => {
const formattedData = data.map((item) => ({
id: item.id,
title: item.title,
description: item.body,
}));
setCards(formattedData);
setLoading(false);
})
.catch((err) => {
setError(err.message);
setLoading(false);
});
}, []);

if (loading) return

Loading…;
if (error) return

Error: {error};

return (

{cards.map((card) => (

{card.title}

{card.description}

))}

);
};

export default DynamicCardListWithLoading;

<h3>動的データ表示の利点</h3>  
- **リアルタイム更新**:API連携により、最新のデータを即時反映。  
- **拡張性**:データ量に応じてレイアウトが自動調整可能。  
- **ユーザーエクスペリエンスの向上**:適切なローディングやエラー処理で快適な操作感を提供。  

次は、メディアクエリを使ったレスポンシブ設定の実践について解説します。  
<h2>メディアクエリを使ったレスポンシブ設定の実践</h2>  

<h3>メディアクエリの基本</h3>  
メディアクエリは、デバイスの画面サイズや解像度に応じて異なるCSSスタイルを適用するための機能です。これにより、レスポンシブデザインを実現できます。以下はメディアクエリの基本構文です:  

css
@media (max-width: 768px) {
/* 768px以下の画面サイズに適用するスタイル */
}

@media (min-width: 769px) and (max-width: 1024px) {
/* 769pxから1024pxまでの画面サイズに適用するスタイル */
}

<h3>Reactでのメディアクエリの活用</h3>  
Reactコンポーネントでメディアクエリを適用する場合、CSSファイルに記述したメディアクエリをそのまま使用できます。また、CSS-in-JSライブラリを使うことで、JavaScript内でメディアクエリを定義することも可能です。  

<h4>基本例: CSSファイルでメディアクエリを使用</h4>  
以下はカードレイアウトのレスポンシブ設定例です:  

css
/* styles.css */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}

@media (max-width: 768px) {
.container {
grid-template-columns: repeat(2, 1fr);
}
}

@media (max-width: 480px) {
.container {
grid-template-columns: 1fr;
}
}

これをReactコンポーネントにインポートして使用します:  

jsx
import React from ‘react’;
import ‘./styles.css’;

const ResponsiveGrid = () => {
const cards = Array.from({ length: 9 }, (_, index) => Card ${index + 1});

return (

{cards.map((card, index) => (

{card}

))}

);
};

export default ResponsiveGrid;

<h4>応用例: CSS-in-JSを使ったメディアクエリ</h4>  
CSS-in-JSを使う場合、`@emotion/react`や`styled-components`を利用します。以下は`@emotion/react`を使った例です:  

jsx
/** @jsxImportSource @emotion/react */
import { css } from ‘@emotion/react’;

const containerStyle = css`
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;

@media (max-width: 768px) {
grid-template-columns: repeat(2, 1fr);
}

@media (max-width: 480px) {
grid-template-columns: 1fr;
}
`;

const ResponsiveGrid = () => {
const cards = Array.from({ length: 9 }, (_, index) => Card ${index + 1});

return (

{cards.map((card, index) => (

{card}

))}

);
};

export default ResponsiveGrid;

<h3>メディアクエリのメリット</h3>  
- **デバイスごとの最適化**:画面サイズに応じた柔軟なレイアウト調整。  
- **再利用性の向上**:1つのCSS定義で複数の画面サイズに対応。  
- **簡潔なコーディング**:グリッドレイアウトとの併用で効率的なレスポンシブデザイン。  

<h3>ベストプラクティス</h3>  
- **モバイルファースト**:最初に小さい画面サイズのスタイルを定義し、大きいサイズに対応。  
- **適切なブレークポイントの選択**:デバイスの利用状況に合わせてブレークポイントを設定。  

次は、具体的な商品リストを例に、レスポンシブなカードレイアウトの実装方法を詳しく解説します。  
<h2>実装例: レスポンシブな商品リスト</h2>  

<h3>概要</h3>  
このセクションでは、ReactとCSSグリッドを活用してレスポンシブな商品リストを実装します。商品カードには、画像、タイトル、価格、説明、および購入ボタンを含めます。これにより、さまざまな画面サイズで見やすいレイアウトを作成します。  

<h3>商品データの準備</h3>  
まず、商品データを用意します。以下は例です:  

jsx
const products = [
{
id: 1,
title: ‘Product 1’,
price: ‘$10.00’,
description: ‘This is an amazing product.’,
image: ‘https://via.placeholder.com/150’
},
{
id: 2,
title: ‘Product 2’,
price: ‘$20.00’,
description: ‘Another incredible item.’,
image: ‘https://via.placeholder.com/150’
},
{
id: 3,
title: ‘Product 3’,
price: ‘$30.00’,
description: ‘You will love this one.’,
image: ‘https://via.placeholder.com/150’
}
];

<h3>商品カードコンポーネント</h3>  
商品データを表示するカードコンポーネントを作成します:  

jsx
import React from ‘react’;

const ProductCard = ({ title, price, description, image }) => {
return (

{title}

{title}

{price}

{description}Buy Now
);
};

export default ProductCard;

<h3>商品リストコンポーネント</h3>  
カードコンポーネントを使って商品リストを表示します:  

jsx
import React from ‘react’;
import ProductCard from ‘./ProductCard’;
import ‘./styles.css’;

const ProductList = () => {
const products = [
{ id: 1, title: ‘Product 1’, price: ‘$10.00’, description: ‘This is an amazing product.’, image: ‘https://via.placeholder.com/150’ },
{ id: 2, title: ‘Product 2’, price: ‘$20.00’, description: ‘Another incredible item.’, image: ‘https://via.placeholder.com/150’ },
{ id: 3, title: ‘Product 3’, price: ‘$30.00’, description: ‘You will love this one.’, image: ‘https://via.placeholder.com/150’ }
];

return (

{products.map((product) => ( ))}
);
};

export default ProductList;

<h3>レスポンシブ対応のCSS</h3>  
以下のCSSでレスポンシブなグリッドレイアウトを実現します:  

css
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}

.card {
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
display: flex;
flex-direction: column;
}

.card-image {
width: 100%;
height: 150px;
object-fit: cover;
}

.card-content {
padding: 16px;
}

.card-title {
font-size: 1.25rem;
margin: 0 0 8px;
}

.card-price {
font-size: 1.1rem;
color: #28a745;
margin: 0 0 8px;
}

.card-description {
font-size: 1rem;
color: #666;
margin: 0 0 16px;
}

.card-button {
background: #007bff;
color: #fff;
border: none;
padding: 10px 16px;
border-radius: 4px;
cursor: pointer;
text-align: center;
}

.card-button:hover {
background: #0056b3;
}

@media (max-width: 768px) {
.container {
grid-template-columns: repeat(2, 1fr);
}
}

@media (max-width: 480px) {
.container {
grid-template-columns: 1fr;
}
}

<h3>実装の利点</h3>  
- **画面サイズ対応**:デバイスに応じて列数を調整。  
- **シンプルで直感的な設計**:CSSグリッドとReactの組み合わせでコードが簡潔。  
- **ユーザー体験の向上**:見やすく整った商品リストを提供可能。  

次は、このカードレイアウトにフィルタリングやソート機能を追加する方法について解説します。  
<h2>応用例: フィルタリングやソート機能の追加</h2>  

<h3>概要</h3>  
商品リストにフィルタリングやソート機能を追加することで、ユーザーが目的の商品を簡単に見つけられるようにします。このセクションでは、Reactの状態管理と動的レンダリングを利用してこれらの機能を実装します。  

<h3>フィルタリング機能の実装</h3>  
フィルタリングでは、商品カテゴリーや価格帯などの条件に基づいてリストを絞り込みます。  

<h4>カテゴリフィルタの例</h4>  
まず、商品データにカテゴリを追加します:  

jsx
const products = [
{ id: 1, title: ‘Product 1’, price: ‘$10.00’, category: ‘Electronics’, description: ‘Amazing product.’, image: ‘https://via.placeholder.com/150’ },
{ id: 2, title: ‘Product 2’, price: ‘$20.00’, category: ‘Books’, description: ‘Incredible item.’, image: ‘https://via.placeholder.com/150’ },
{ id: 3, title: ‘Product 3’, price: ‘$30.00’, category: ‘Electronics’, description: ‘You will love this.’, image: ‘https://via.placeholder.com/150’ }
];

次に、フィルタリング用のコンポーネントを作成します:  

jsx
import React, { useState } from ‘react’;
import ProductCard from ‘./ProductCard’;

const ProductListWithFilter = () => {
const [category, setCategory] = useState(‘All’);

const handleFilterChange = (event) => {
setCategory(event.target.value);
};

const filteredProducts = category === ‘All’
? products
: products.filter((product) => product.category === category);

return (
Filter by category: All Electronics Books

  <div className="container">  
    {filteredProducts.map((product) => (  
      <ProductCard key={product.id} {...product} />  
    ))}  
  </div>  
</div>  

);
};

export default ProductListWithFilter;

<h3>ソート機能の実装</h3>  
ソート機能では、価格やタイトルなどの条件で商品リストを並べ替えます。  

<h4>価格でのソート例</h4>  
商品データの価格を数値として扱えるように調整します:  

jsx
const products = [
{ id: 1, title: ‘Product 1’, price: 10.0, category: ‘Electronics’, description: ‘Amazing product.’, image: ‘https://via.placeholder.com/150’ },
{ id: 2, title: ‘Product 2’, price: 20.0, category: ‘Books’, description: ‘Incredible item.’, image: ‘https://via.placeholder.com/150’ },
{ id: 3, title: ‘Product 3’, price: 30.0, category: ‘Electronics’, description: ‘You will love this.’, image: ‘https://via.placeholder.com/150’ }
];

ソート機能を追加します:  

jsx
import React, { useState } from ‘react’;
import ProductCard from ‘./ProductCard’;

const ProductListWithSort = () => {
const [sortOrder, setSortOrder] = useState(‘asc’);

const handleSortChange = (event) => {
setSortOrder(event.target.value);
};

const sortedProducts = […products].sort((a, b) => {
if (sortOrder === ‘asc’) return a.price – b.price;
return b.price – a.price;
});

return (
Sort by price: Ascending Descending

  <div className="container">  
    {sortedProducts.map((product) => (  
      <ProductCard key={product.id} {...product} />  
    ))}  
  </div>  
</div>  

);
};

export default ProductListWithSort;

<h3>フィルタリングとソートの統合</h3>  
フィルタリングとソートを組み合わせることで、柔軟な検索機能を提供できます:  

jsx
const filteredAndSortedProducts = […products]
.filter((product) => (category === ‘All’ ? true : product.category === category))
.sort((a, b) => (sortOrder === ‘asc’ ? a.price – b.price : b.price – a.price));
“`

これをリストコンポーネントで利用すれば、強力な商品検索システムが完成します。

利点

  • ユーザーエクスペリエンス向上:簡単に目的の商品を探せる。
  • 再利用性:他のプロジェクトにも応用可能。
  • 拡張性:さらなる条件や機能を簡単に追加できる。

次は、これまでの実装内容をまとめます。

まとめ


本記事では、ReactとCSSグリッドを用いたレスポンシブなカードレイアウトの実装方法について解説しました。基本的なCSSグリッドの使い方から、Reactコンポーネントとの連携、さらに動的データの表示やレスポンシブ対応の設定を学びました。応用例として、フィルタリングやソート機能の追加も行い、実際のアプリケーションで役立つスキルを習得しました。これにより、効率的で柔軟なレイアウト設計が可能になります。ぜひ、学んだ知識を活用し、ユーザーにとって魅力的なWebアプリケーションを構築してください。

コメント

コメントする

目次