ブログサイトのレイアウトを改善する際、Dev.toのような3カラム構成は非常に効果的な選択肢の一つです。この記事では、Next.jsとTailwind CSSを用いてDev.toライクな3カラムレイアウトを実装する方法について、実践的な知見を共有します。
はじめに
技術ブログを運営していると、以下のような課題に直面することが多いのではないでしょうか:
- 見出しや関連情報へのジャンプが分かりにくい
- デスクトップ画面での余白が効果的に活用できていない
- タグ一覧や執筆者情報などの追加情報を表示するスペースが不足している
- レスポンシブ対応が不完全で、モバイル表示時に使いづらい
これらの課題を解決するため、Dev.toで採用されているような3カラムレイアウトの実装方法について解説します。
前提条件
この記事で説明する実装には、以下の技術スタックを使用します:
- Next.js(App Router)
- TypeScript
- Tailwind CSS
- React 18以上
Dev.toスタイルの3カラムレイアウトとは
Dev.toスタイルの3カラムレイアウトは、以下のような構成を特徴としています:
- 左サイドバー(240px)
- サイト全体のナビゲーション
- シリーズ記事リンク
- タグ一覧
- 著者情報
- メインコンテンツ(可変幅)
- 記事本文
- 広いスペースでの快適な読書体験
- 右サイドバー(240px)
- シェアボタン
- 目次
- 関連記事
- モバイル時はスライドアウトメニュー化
この構成により、技術系ブログで多くの読者が慣れ親しんだUIを提供しながら、ナビゲーション性とスペース活用を向上させることができます。
実装のポイント
1. 基本的なレイアウト構造
まず、3カラムレイアウトの基本構造を実装します。Tailwind CSSのユーティリティクラスを活用することで、簡潔なコードでレスポンシブ対応を実現できます。
// components/layouts/BlogLayout.tsx
import { ReactNode } from 'react'
import LeftSidebar from './LeftSidebar'
import RightSidebar from './RightSidebar'
type Props = {
children: ReactNode
}
export default function BlogLayout({ children }: Props) {
return (
<div className="relative min-h-screen lg:flex">
{/* 左サイドバー */}
<aside className="fixed inset-y-0 left-0 hidden w-60 overflow-y-auto border-r border-gray-200 lg:block">
<LeftSidebar />
</aside>
{/* メインコンテンツ */}
<main className="mx-auto w-full max-w-3xl px-4 py-8 lg:ml-60 xl:px-0">
{children}
</main>
{/* 右サイドバー */}
<aside className="fixed inset-y-0 right-0 hidden w-60 overflow-y-auto border-l border-gray-200 xl:block">
<RightSidebar />
</aside>
</div>
)
}
ここでのポイントは以下の通りです:
-
lg:flex
を使用して、大画面時のみフレックスボックスレイアウトを適用 - サイドバーは
w-60
(240px)で固定幅を設定 - メインコンテンツは
max-w-3xl
で最大幅を制限 - 左サイドバーは
lg:block
で、右サイドバーはxl:block
でブレークポイントを分けて表示
2. モバイル対応の実装
モバイル対応では、サイドバーをドロワーメニューとして実装します。これにより、限られた画面スペースを効率的に活用できます。
// components/layouts/MobileSidebar.tsx
import { useState } from 'react'
export default function MobileSidebar() {
const [isOpen, setIsOpen] = useState(false)
return (
<>
{/* ハンバーガーメニューボタン */}
<button
onClick={() => setIsOpen(true)}
className="fixed left-4 top-4 z-50 block lg:hidden"
aria-label="メニューを開く"
aria-expanded={isOpen}
aria-controls="mobile-menu"
>
<svg className="h-6 w-6" /* ... */ />
</button>
{/* オーバーレイ */}
{isOpen && (
<div
className="fixed inset-0 z-40 bg-black bg-opacity-50 lg:hidden"
onClick={() => setIsOpen(false)}
/>
)}
{/* ドロワーメニュー */}
<div
id="mobile-menu"
className={`fixed inset-y-0 left-0 z-50 w-60 transform overflow-y-auto bg-white transition duration-300 ease-in-out lg:hidden ${
isOpen ? 'translate-x-0' : '-translate-x-full'
}`}
>
<LeftSidebar />
</div>
</>
)
}
実装のポイント:
-
useState
でドロワーの開閉状態を管理 -
transform
とtranslate
でスライドアニメーションを実現 - 背景のオーバーレイで操作を制限
- アクセシビリティに配慮したARIA属性の設定
3. シェアボタンの実装
モバイルとデスクトップで異なるシェア機能を提供するため、Web Share APIを活用します。
// components/ShareButton.tsx
'use client'
import { useEffect, useState } from 'react'
export default function ShareButton({ url, title }: { url: string; title: string }) {
const [canShare, setCanShare] = useState(false)
useEffect(() => {
setCanShare(!!navigator.share)
}, [])
const handleShare = async () => {
try {
if (navigator.share) {
await navigator.share({
title,
url,
})
} else {
// フォールバック:URLをクリップボードにコピー
await navigator.clipboard.writeText(url)
alert('URLをコピーしました')
}
} catch (error) {
console.error('シェアに失敗しました:', error)
}
}
return (
<button
onClick={handleShare}
className="inline-flex items-center rounded-md bg-blue-600 px-4 py-2 text-white hover:bg-blue-700"
>
<svg className="mr-2 h-5 w-5" /* ... */ />
{canShare ? 'シェア' : 'URLをコピー'}
</button>
)
}
実装のポイント:
-
use client
ディレクティブでクライアントコンポーネントとして宣言 -
navigator.share
の存在チェックでWeb Share APIの対応を判定 - フォールバックとしてクリップボードコピー機能を実装
実装時の注意点
1. ハイドレーションエラーへの対策
Next.jsでSSRを使用する場合、ブラウザ固有のAPIを直接参照するとハイドレーションエラーが発生する可能性があります。これを防ぐため:
- クライアントサイド機能は
use client
ディレクティブを使用して分離 -
useEffect
内でブラウザAPIの参照を行う - SSR時とCSR時で表示が異なる部分は適切にローディング状態を表示
2. アクセシビリティへの配慮
3カラムレイアウトを実装する際は、以下のアクセシビリティ対応が重要です:
- 適切なARIA属性の設定(
aria-label
、aria-expanded
、aria-controls
) - キーボード操作のサポート
- スクリーンリーダー対応の階層構造
- 十分なコントラスト比の確保
3. パフォーマンスの最適化
レイアウトのパフォーマンスを最適化するためのポイント:
- サーバーコンポーネントとクライアントコンポーネントの適切な分離
- 画像の最適化(
next/image
の活用) - 不要なリレンダリングの防止
- Tailwind CSSのパージによる最適化
コード公開
この記事で紹介した実装のサンプルコードは、以下のGitHubリポジトリで公開しています:
実装時の参考にしていただければ幸いです。
参考資料
この記事は以下の記事を参考に、Qiita向けに再構成したものです:
まとめ
Dev.toスタイルの3カラムレイアウトは、技術ブログのUI/UX改善に非常に効果的です。主なメリットは:
- ナビゲーション性の向上
- 画面スペースの効率的な活用
- モバイルフレンドリーな対応
- 拡張性の高い設計
実装時は、レスポンシブデザイン、ハイドレーションエラー、アクセシビリティなど、考慮すべき要素が多くありますが、本記事で紹介した方法を参考に、段階的に改善を進めることをお勧めします。
また、このレイアウト構造は将来的な機能追加(シリーズ記事の目次連動やブックマーク機能など)にも対応しやすい設計となっています。
Next.jsとTailwind CSSを使用した実装例を通じて、読者の皆さんがより良い技術ブログの UI/UX を実現する一助となれば幸いです。