レスポンシブデザイン実践ガイド:モバイルファーストで作る現代的なUI
モバイルファーストアプローチでレスポンシブデザインを実装するための実践的なテクニックを解説します。
レスポンシブデザイン実践ガイド
現代の Web サイトに必須のレスポンシブデザインを、モバイルファーストアプローチで実装する方法を学びましょう。
モバイルファーストアプローチ
基本的な考え方
/* モバイルファースト:デフォルトはモバイル向け */
.container {
width: 100%;
padding: 1rem;
margin: 0 auto;
}
/* タブレット向け */
@media (min-width: 768px) {
.container {
max-width: 750px;
padding: 2rem;
}
}
/* デスクトップ向け */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
padding: 3rem;
}
}
ブレークポイント設計
/* カスタムプロパティでブレークポイント管理 */
:root {
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-xxl: 1536px;
}
/* 使用例 */
@media (min-width: 768px) {
/* タブレット以上 */
}
@media (min-width: 1024px) {
/* デスクトップ以上 */
}
フレキシブルレイアウト
Flexbox を活用したレスポンシブカード
.card-container {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
.card {
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
@media (min-width: 768px) {
.card-container {
flex-direction: row;
flex-wrap: wrap;
}
.card {
flex: 1 1 calc(50% - 0.5rem);
}
}
@media (min-width: 1024px) {
.card {
flex: 1 1 calc(33.333% - 0.667rem);
}
}
CSS Grid によるレスポンシブグリッド
.grid-layout {
display: grid;
gap: 1rem;
padding: 1rem;
/* モバイル:1列 */
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.grid-layout {
/* タブレット:2列 */
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.grid-layout {
/* デスクトップ:自動調整 */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
}
/* 複雑なグリッドレイアウト */
.complex-grid {
display: grid;
gap: 1rem;
grid-template-areas:
"header"
"main"
"aside"
"footer";
}
@media (min-width: 1024px) {
.complex-grid {
grid-template-areas:
"header header header"
"main main aside"
"footer footer footer";
grid-template-columns: 1fr 1fr 300px;
}
}
レスポンシブタイポグラフィ
Fluid Typography
/* clamp()を使用した流動的なフォントサイズ */
h1 {
font-size: clamp(1.75rem, 4vw, 3rem);
line-height: 1.2;
margin-bottom: 1rem;
}
h2 {
font-size: clamp(1.5rem, 3vw, 2.5rem);
line-height: 1.3;
}
p {
font-size: clamp(1rem, 2vw, 1.125rem);
line-height: 1.6;
margin-bottom: 1rem;
}
/* カスタムプロパティでタイポグラフィスケール */
:root {
--font-size-xs: clamp(0.75rem, 1.5vw, 0.875rem);
--font-size-sm: clamp(0.875rem, 1.75vw, 1rem);
--font-size-base: clamp(1rem, 2vw, 1.125rem);
--font-size-lg: clamp(1.125rem, 2.5vw, 1.25rem);
--font-size-xl: clamp(1.25rem, 3vw, 1.5rem);
}
レスポンシブな余白とスペーシング
:root {
/* モバイル向けスペーシング */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
}
@media (min-width: 768px) {
:root {
/* タブレット以上でスペーシングを拡大 */
--spacing-md: 1.5rem;
--spacing-lg: 2rem;
--spacing-xl: 3rem;
}
}
@media (min-width: 1024px) {
:root {
/* デスクトップでさらに拡大 */
--spacing-lg: 2.5rem;
--spacing-xl: 4rem;
}
}
/* 使用例 */
.section {
padding: var(--spacing-md) var(--spacing-sm);
margin-bottom: var(--spacing-lg);
}
レスポンシブ画像
Picture 要素を使った画像最適化
<picture>
<source
media="(min-width: 1024px)"
srcset="hero-desktop.webp"
type="image/webp"
/>
<source
media="(min-width: 768px)"
srcset="hero-tablet.webp"
type="image/webp"
/>
<source media="(min-width: 1024px)" srcset="hero-desktop.jpg" />
<source media="(min-width: 768px)" srcset="hero-tablet.jpg" />
<img
src="hero-mobile.jpg"
alt="ヒーロー画像"
loading="lazy"
width="400"
height="300"
/>
</picture>
CSS でのレスポンシブ画像
.responsive-image {
width: 100%;
height: auto;
display: block;
}
/* アスペクト比を保持 */
.aspect-ratio-16-9 {
aspect-ratio: 16 / 9;
object-fit: cover;
}
/* コンテナクエリを使った画像制御 */
.image-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.responsive-image {
border-radius: 12px;
}
}
/* レスポンシブな背景画像 */
.hero-section {
background-image: url("hero-mobile.jpg");
background-size: cover;
background-position: center;
min-height: 50vh;
}
@media (min-width: 768px) {
.hero-section {
background-image: url("hero-tablet.jpg");
min-height: 60vh;
}
}
@media (min-width: 1024px) {
.hero-section {
background-image: url("hero-desktop.jpg");
min-height: 70vh;
}
}
ナビゲーション
モバイル対応ハンバーガーメニュー
<nav class="navbar">
<div class="navbar-brand">
<a href="/">ロゴ</a>
</div>
<button class="navbar-toggle" aria-label="メニューを開く">
<span></span>
<span></span>
<span></span>
</button>
<div class="navbar-menu">
<a href="/">ホーム</a>
<a href="/about">について</a>
<a href="/services">サービス</a>
<a href="/contact">お問い合わせ</a>
</div>
</nav>
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
background: white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.navbar-toggle {
display: flex;
flex-direction: column;
gap: 4px;
background: none;
border: none;
cursor: pointer;
}
.navbar-toggle span {
width: 25px;
height: 3px;
background: #333;
transition: 0.3s;
}
.navbar-menu {
position: fixed;
top: 0;
right: -100%;
width: 80%;
height: 100vh;
background: white;
display: flex;
flex-direction: column;
padding: 2rem;
transition: right 0.3s ease;
z-index: 1000;
}
.navbar-menu.active {
right: 0;
}
.navbar-menu a {
padding: 1rem 0;
text-decoration: none;
color: #333;
border-bottom: 1px solid #eee;
}
/* デスクトップ版 */
@media (min-width: 768px) {
.navbar-toggle {
display: none;
}
.navbar-menu {
position: static;
width: auto;
height: auto;
background: none;
flex-direction: row;
padding: 0;
gap: 2rem;
}
.navbar-menu a {
padding: 0;
border-bottom: none;
}
}
フォームのレスポンシブ化
.form-container {
width: 100%;
max-width: 500px;
margin: 0 auto;
padding: 1rem;
}
.form-group {
margin-bottom: 1rem;
}
.form-input {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.2s;
}
.form-input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
/* タブレット以上で横並び */
@media (min-width: 768px) {
.form-row {
display: flex;
gap: 1rem;
}
.form-row .form-group {
flex: 1;
}
}
/* タッチデバイス対応 */
@media (hover: none) {
.form-input {
font-size: 16px; /* iOSのズーム防止 */
}
}
パフォーマンス最適化
重要な CSS の優先読み込み
<!-- クリティカルCSS -->
<style>
/* Above the fold のスタイルのみ */
.header {
/* ... */
}
.hero {
/* ... */
}
</style>
<!-- 非同期でその他のCSS読み込み -->
<link
rel="preload"
href="styles.css"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript><link rel="stylesheet" href="styles.css" /></noscript>
メディアクエリでの条件読み込み
<!-- 大画面でのみ読み込み -->
<link rel="stylesheet" href="desktop-only.css" media="(min-width: 1024px)" />
<!-- 印刷時のみ -->
<link rel="stylesheet" href="print.css" media="print" />
アクセシビリティ配慮
/* 減速モーション設定への対応 */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* ダークモード対応 */
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #1a1a1a;
--text-color: #ffffff;
--border-color: #333;
}
}
/* 高コントラスト設定への対応 */
@media (prefers-contrast: high) {
.button {
border: 2px solid;
}
}
/* フォーカス表示の改善 */
.focusable:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
テストとデバッグ
レスポンシブデザインのテストポイント
/* デバッグ用のビジュアライゼーション */
.debug-mode * {
outline: 1px solid red;
}
.debug-mode *:nth-child(2n) {
outline-color: blue;
}
/* ブレークポイント表示 */
body::before {
content: "Mobile";
position: fixed;
top: 0;
left: 0;
background: red;
color: white;
padding: 0.5rem;
z-index: 9999;
}
@media (min-width: 768px) {
body::before {
content: "Tablet";
background: blue;
}
}
@media (min-width: 1024px) {
body::before {
content: "Desktop";
background: green;
}
}
まとめ
レスポンシブデザインは現代の Web 開発において必須の技術です。モバイルファーストアプローチを採用し、段階的に機能を拡張することで、すべてのデバイスで最適なユーザー体験を提供できます。
継続的なテストと改善を通じて、真にレスポンシブな Web サイトを構築しましょう。
最後まで読んでいただきありがとうございました!てばさん(@basabasa8770)でした!