Dev.toスタイルのブログ記事レイアウトを導入してみた

エンジニアリングブログのUI/UXを改善するため、Dev.toスタイルの3カラムレイアウトを導入しました。その背景、実装アプローチ、得られた知見を紹介します。

はじめに

エンジニアリング系のブログを運営していると、「読みやすく・探しやすい」レイアウトはとても重要だと感じます。今回、私たちはDev.toの記事ページに似た3カラムレイアウトを採用し、ブログのUI/UXを大きくリニューアルしました。本記事では、その背景・実装・学びなどを共有します。

背景と課題

私たちのブログサイトには、いくつかの課題を抱えていました。大量の記事を投稿していると、見出しや関連情報へのジャンプができる仕組みが欲しくなります。従来は記事本文の下部に小さなリンクしかなく、ユーザーが迷いやすい状態でした。

デスクトップやタブレットで見ると、画面の左右が大きく余っているのが勿体ないという声がありました。横長ディスプレイを活かすレイアウトが必要です。また、タグ一覧、執筆者情報、関連記事などの追加情報を表示するスペースがなく、コンテンツ紹介の機会を逃していました。

レスポンシブ対応はしていたものの、サイドバーが煩雑だったり、ナビゲーションメニューと記事本文がバッティングしてしまうなど課題が散見されました。こうした課題を解消すべく、「Dev.toライクな3カラム構成」に着目しました。

Dev.toスタイルの3カラムレイアウトとは

左サイドバー(240px)にはサイト全体のナビゲーションや、シリーズ記事、タグ一覧、著者情報などを表示します。メインコンテンツ(可変幅)では記事の本文を主役にし、広いスペースで快適に読めるようにします。右サイドバー(240px)にはシェアボタンや目次、関連記事などを表示する領域を設け、デスクトップ以上で表示し、モバイル時はスライドアウトで呼び出せるようにします。

これにより「技術系ブログで多くの人が見慣れているUI」を踏襲しながら、ナビゲーション性とスペース活用を向上させることを狙いました。

実装アプローチ

1. レイアウト構造

Tailwind CSSのユーティリティクラスを活用することで、簡潔なコードでレスポンシブ対応を実装しました。3カラムレイアウトの基本構造は以下のコードで実現しています。

BlogLayout.tsx
1export default function BlogLayout({ children }: { children: React.ReactNode }) {
2  return (
3    <div className="container mx-auto">
4      <div className="grid
5        lg:grid-cols-[minmax(0,1fr)_240px]
6        xl:grid-cols-[240px_minmax(0,1fr)_240px]
7        gap-4">
8        <LeftSidebar />
9        <main className="min-w-0">{children}</main>
10        <RightSidebar />
11      </div>
12    </div>
13  );
14}

主要なコンポーネントは以下のように分割し、それぞれの役割を明確にしました。BlogLayout.tsxは3カラムレイアウトのベースとなり、LeftSidebar.tsxではシリーズナビやタグ、関連記事などの補助情報を、RightSidebar.tsxでは目次やシェアボタンを配置します。ShareButton.tsxではブラウザのWeb Share APIやTwitter/Xシェアなどを集約しています。

2. モバイル対応

モバイル対応では、単一のDOM要素をブレークポイントで出し分ける方式を採用しました。小画面ではサイドバーをfixed + transformにして「ドロワー」化し、画面幅が大きくなるとstickyで常時表示に切り替えます。モバイルでサイドバーを開いた際は、背面を薄暗くしてユーザーの操作をそちらに集中させる設計としています。

Sidebar.tsx
1export function Sidebar({ isOpen, onClose }: SidebarProps) {
2  return (
3    <>
4      {/* オーバーレイ */}
5      <div
6        className={`fixed inset-0 bg-black/50 transition-opacity lg:hidden
7          ${isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
8        onClick={onClose}
9      />
10      {/* サイドバー */}
11      <aside
12        className={`fixed top-0 bottom-0 w-[240px] bg-white overflow-y-auto
13          transform transition-transform lg:sticky lg:transform-none
14          ${isOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'}`}
15      >
16        {/* サイドバーコンテンツ */}
17      </aside>
18    </>
19  );
20}

3. シェアボタンの実装

モバイル端末(iOS Safari, Android Chromeなど)ではWeb Share APIを利用してOSネイティブの共有機能を提供します。非対応ブラウザではURLコピーやX(旧Twitter)のIntent Linkを使用することで、「シェアしたい!」のに何も起こらないという状況を防ぐ多段的な仕組みを用意しました。

ShareButton.tsx
1'use client';
2
3export function ShareButton({ url, title }: ShareProps) {
4  const handleShare = async () => {
5    if (navigator.share) {
6      try {
7        await navigator.share({
8          title,
9          url
10        });
11      } catch (error) {
12        if (error instanceof Error && error.name !== 'AbortError') {
13          console.error('Error sharing:', error);
14        }
15      }
16    } else {
17      // フォールバック: クリップボードにURLをコピー
18      await navigator.clipboard.writeText(url);
19    }
20  };
21
22  return (
23    <button
24      onClick={handleShare}
25      className="flex items-center gap-2 px-4 py-2 rounded-md bg-blue-500 text-white hover:bg-blue-600"
26    >
27      <ShareIcon className="w-5 h-5" />
28      Share
29    </button>
30  );
31}

課題と学び

1. 開発工数の増加

3カラムレイアウトへの移行には、既存コンテンツの配置替えやCSSリファクタリングが必要でした。ただ長期的に見れば、この段階でレイアウトを再設計したことで、追加機能の実装がスムーズになるというメリットが大きいです。

2. ハイドレーションエラーへの対策

Next.jsのSSR環境でnavigator.shareやwindowオブジェクトを直接使うと、サーバー側とクライアント側で描画結果が異なりハイドレーションエラーになりがちです。解決策として、'use client'を付与したコンポーネントでuseEffectを使って動的に機能を切り替える方法を取りました。

3. アクセシビリティの考慮

サイドバーの開閉ボタンにはaria-label、aria-expanded、aria-controlsを適切に設定しました。スクリーンリーダー利用者がわかりやすいように、表示テキストや階層構造を明確にしました。

実装から得られた教訓

グリッドレイアウトは、ブレークポイントごとにカラム数を増やすことで、意図した配置を崩さずに実現できました。モバイル時は1カラム → タブレットでは2カラム → デスクトップでは3カラムへの移行もスムーズに実装できています。

サイドバーを「モバイル用DOM」「デスクトップ用DOM」に分割すると、重複表示や制御の煩雑化が起こりがちです。単一要素をCSSクラスで変形させる方法がベストプラクティスであることを学びました。

Web Share APIやモーダル操作など、ブラウザ固有の機能だけを'use client'で囲むことで、パフォーマンスを最適化できました。ベースレイアウトはサーバーコンポーネントでも作れるため、パフォーマンスと拡張性を両立しやすい構成となりました。

まとめ

Dev.toスタイルの3カラムレイアウトは、技術ブログと非常に相性が良いと感じました。ナビゲーション性を高めるだけでなく、広いディスプレイを最大限活用できるため、読者が記事に没頭しやすい環境を作れます。実装段階では、レスポンシブデザインやハイドレーションエラー対策、アクセシビリティなど考慮すべき要素が多いですが、結果として「読みやすさ」と「拡張性」を兼ね備えたレイアウトへ一歩前進できました。

もし今後、シリーズ記事の目次連動やブックマーク・フォロー機能を追加していく場合も、今回の設計を土台にすれば、コンポーネントの差し替えやサイドバー拡張が容易です。ブログレイアウトが旧来の1カラムor2カラムで、読者が迷子になりやすいと悩んでいる方は、ぜひDev.to風3カラムを検討してみてください。きっと新しい読者体験を提供できるはずです。

参考

この記事の実装にあたり、以下の資料を参考にしました。

Bootstrap 5 Sidebar Examples - レスポンシブなサイドバーの実装パターン集 • 10 blog layout best practices for 2024 - 最新のブログレイアウトトレンド • Weblog Usability: The Top Ten Design Mistakes - ブログデザインの典型的な問題と解決策

これらの情報やベストプラクティスを踏まえ、私たちのブログでも「スキャンしやすさ」や「モバイルファースト」を意識したデザインにアップデートできました。すでに読者からは「記事をスムーズに行き来できる」「モバイルで見やすくなった」と好評の声をいただいています。今後さらに改良を重ねながら、新機能や目次機能(Phase 4)を実装して、より使いやすい技術ブログを目指していきたいと思います。