1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

日本語縦書き小説を読めるWebアプリをHugoで作ってみた話

Posted at

はじめに

こんにちは。個人開発者として、Hugoを使用した多言語対応の小説読書プラットフォーム「NovelCat」を作成しました。この記事では、実際に開発した当事者として、CSSのwriting-mode: vertical-rlを活用した日本語縦書き表示機能と、包括的な読書設定システムの実装について詳しく紹介したいと思います。

実際のサイトはこちら: https://novelcat.pages.dev/

記事を読みながら、ぜひ実際の動作をご確認ください。縦書きモードや読書設定機能を体験していただけます。

開発状況について: 現在GitHubでのオープンソース化に向けた準備を進めており、コードの整理とドキュメント化を行っています。サイト自体も継続的に改善を重ねており、より使いやすい読書体験の提供を目指しています。GitHubリポジトリが公開され次第、本記事も更新してソースコードへのリンクを追加する予定です。

免責事項: この記事は開発者本人による実装記録であり、技術的な詳細や実装方法について個人的な観点から説明しています。環境や要件によって最適な実装方法は異なる場合があります。

開発の背景

日本語の小説を読む際、縦書きで読みたいという需要は根強く存在します。しかし、多くのWebサイトでは横書き表示が主流で、縦書きの小説読書体験を提供するサイトは限られています。そこで、Hugoという静的サイトジェネレーターを使用して、縦書き読書機能と多様な読書設定を持つ小説プラットフォームを構築することにしました。

また、日本語と英語の両方のユーザーに対応するため、多言語機能も同時に実装しました。これにより、日本人読者は縦書きで、英語圏の読者は横書きで、それぞれ快適に小説を楽しめるプラットフォームを目指しました。

技術スタック

今回使用した主要な技術は以下の通りです:

  • Hugo: 静的サイトジェネレーター
  • CSS: writing-mode: vertical-rl、Flexbox
  • JavaScript: localStorage、DOM操作
  • HTML: セマンティックマークアップ

HugoはGo言語で書かれた高速な静的サイトジェネレーターで、多言語サイトの構築に優れた機能を提供します。また、テンプレートシステムが強力で、動的なコンテンツ生成が容易に行えることから選択しました。

実装した機能

縦書き読書モード

最も重要な機能である縦書き表示は、CSSのwriting-modeプロパティを使用して実装しました:

.vertical-mode article {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    height: 80vh;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 1rem;
    width: calc(100vw - 2rem);
    max-width: none;
    box-sizing: border-box;
}

writing-mode: vertical-rlにより、文字が右から左へ、上から下へと配置されます。text-orientation: mixedは、英数字や記号を適切に表示するために使用しています。高さは80vhに設定し、横スクロールで読み進められるようにしました。

JavaScript側では、ボタンクリックによる表示モードの切り替えを実装:

function toggleVerticalMode() {
    const body = document.body;
    const button = document.querySelector('.reading-mode-toggle');
    const isJapanese = document.documentElement.lang === 'jp';
    
    if (body.classList.contains('vertical-mode')) {
        body.classList.remove('vertical-mode');
        button.textContent = isJapanese ? '縦書き' : 'Vertical';
        localStorage.setItem('readingMode', 'horizontal');
    } else {
        body.classList.add('vertical-mode');
        button.textContent = isJapanese ? '横書き' : 'Horizontal';
        localStorage.setItem('readingMode', 'vertical');
    }
}

ユーザーの言語設定に応じてボタンテキストを動的に変更し、選択された表示モードをlocalStorageに保存して次回アクセス時に復元する機能も組み込みました。

実際の縦書きモードはNovelCatでご体験いただけます。

横書きモード

縦書きモード

包括的な読書設定システム

単純な縦書き表示だけでなく、読書体験を向上させるための様々な設定機能を実装しました。設定パネルはインライン形式で記事の上部に配置し、折りたたみ可能にすることで画面領域を効率的に使用できるようにしています。

実際の設定パネルはNovelCatでお試しください。「読書設定」をクリックして展開できます。

読書設定パネル

実装した設定項目:

背景色テーマ: 白、セピア、ダークの3種類から選択可能。目の疲労軽減や読書環境に応じたカスタマイズができます。

フォントサイズ: 70%から150%の範囲で10%刻みの調整が可能。視認性に応じた細かな調整ができます。

行間設定: 1.0から3.0の範囲で0.2刻みの調整。文章の読みやすさを個人の好みに合わせて調整できます。

段落間隔: 0.0emから3.0emの範囲で調整可能。文章の区切りを明確にしたい場合に有効です。

全画面モード: ヘッダーやサイドバーを非表示にして読書に集中できる環境を提供します。

設定の永続化

すべての設定項目はlocalStorageを使用して保存され、ページを再読み込みしても前回の設定が自動的に復元されます:

// 設定の保存例
localStorage.setItem('backgroundColor', color);
localStorage.setItem('fontSize', currentFontSize);
localStorage.setItem('lineHeight', currentLineHeight);

// ページ読み込み時の復元
document.addEventListener('DOMContentLoaded', function() {
    const savedBgColor = localStorage.getItem('backgroundColor') || 'white';
    changeBackground(savedBgColor);
    
    const savedFontSize = localStorage.getItem('fontSize');
    if (savedFontSize) {
        currentFontSize = parseInt(savedFontSize);
        document.body.style.fontSize = `${currentFontSize}%`;
    }
});

エクスポート・インポート機能

設定のバックアップや他のデバイスでの共有を可能にするため、JSON形式での設定エクスポート・インポート機能も実装しました:

window.exportSettings = function() {
    const settings = {
        readingMode: localStorage.getItem('readingMode') || 'horizontal',
        backgroundColor: localStorage.getItem('backgroundColor') || 'white',
        fontSize: parseInt(localStorage.getItem('fontSize')) || 100,
        // その他の設定項目...
        exportDate: new Date().toISOString()
    };
    
    const blob = new Blob([JSON.stringify(settings, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `novelcat-settings-${new Date().toISOString().split('T')[0]}.json`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
};

章ナビゲーションシステム

小説の連載形式に対応するため、自動的な章間ナビゲーション機能を実装しました。ファイル名のパターン(例:「kyokansha-ch1」「kyokansha-ch2」)を解析し、同一シリーズの章を自動的に検出します。

章ナビゲーション機能はこちらの連載小説でご確認いただけます。

章ナビゲーション

Hugoのテンプレート機能を活用した実装:

{{ if .File }}
{{ $currentFileName := .File.BaseFileName }}
{{ $chapterMatch := findRE "^(.+)-ch(\\d+)$" $currentFileName }}
{{ if $chapterMatch }}
    {{ $seriesName := index (split (index $chapterMatch 0) "-ch") 0 }}
    
    <!-- シリーズ内の全章を取得 -->
    {{ $seriesPages := slice }}
    {{ range where .Site.Pages "Type" "posts" }}
        {{ if and .File (eq .Language.Lang $.Language.Lang) (hasPrefix .File.BaseFileName (printf "%s-ch" $seriesName)) }}
            {{ $seriesPages = $seriesPages | append . }}
        {{ end }}
    {{ end }}
    {{ $seriesPages = sort $seriesPages "File.BaseFileName" }}
    
    <!-- 前後の章リンクを生成 -->
    <!-- 章一覧の表示 -->
{{ end }}
{{ end }}

この実装により、作者が新しい章を追加するだけで、自動的に章間のナビゲーションが生成されます。読者は章一覧の表示・非表示を切り替えることもでき、この設定もlocalStorageに保存されます。

多言語対応

日本語と英語の両方のユーザーに対応するため、Hugoの多言語機能を活用して完全に対応した読書設定UIを実装しました。

英語版はNovelCat Englishからアクセスできます。すべての読書設定が英語で表示されます。

英語版

Hugoテンプレートでの条件分岐による多言語対応:

{{ if eq .Language.Lang "jp" }}
<h3>読書設定</h3>
<button class="settings-collapse-btn">設定を閉じる ▲</button>
{{ else }}
<h3>Reading Settings</h3>
<button class="settings-collapse-btn">Close Settings ▲</button>
{{ end }}

JavaScriptでも言語に応じた動的テキスト変更を実装:

const isJapanese = document.documentElement.lang === 'jp';
const confirmMessage = isJapanese ? 
    'すべての設定をデフォルトに戻しますか?' : 
    'Reset all settings to default?';

モバイル対応

縦書きモードでのモバイル表示において、画面からのはみ出しを防ぐため、レスポンシブデザインを実装しました:

.vertical-mode article {
    width: calc(100vw - 2rem);
    box-sizing: border-box;
}

@media (max-width: 768px) {
    .vertical-mode article {
        padding: 0.5rem;
        width: calc(100vw - 1rem);
    }
}

開発過程での課題と解決策

課題1: 縦書きモードでのレイアウト崩れ

初期実装では、縦書きモードを適用する要素の選択が不適切で、テキストが細い縦線のように表示される問題が発生しました。これはwriting-modeを適用する対象要素が間違っていたことが原因でした。

解決策: 適用対象を#full-contentからarticle要素に変更し、適切な高さとスクロール設定を行うことで解決しました。

課題2: 設定変更の適用範囲

行間や段落間隔の調整が、特定のID以下の段落にのみ適用され、記事全体に反映されない問題がありました。

解決策: CSSセレクターを#full-content pからarticle pに変更し、記事全体の段落に設定が適用されるようにしました。

課題3: モバイルでの表示崩れ

縦書きモードで画面からはみ出る問題が発生していました。

解決策: calc(100vw - 2rem)box-sizing: border-boxを使用して、パディングを含めた正確な幅計算を行いました。

課題4: 多言語での動的テキスト

JavaScript内でのテキスト変更時に、言語に応じたテキストの切り替えが必要でした。

解決策: document.documentElement.langを使用して現在の言語を判定し、条件分岐でテキストを動的に変更する関数を実装しました。

パフォーマンスと最適化

軽量な実装

外部ライブラリを使用せず、ピュアなCSS、JavaScript、HTMLのみで実装することで、ページの読み込み速度を最適化しました。全ての機能がクライアントサイドで動作するため、サーバーへの追加リクエストは発生しません。

設定の効率的な管理

localStorageを使用した設定管理により、サーバーサイドでのセッション管理やデータベースが不要になり、シンプルな構成を維持できました。

静的サイトの利点

Hugoによる静的サイト生成により、高速な表示速度とサーバー負荷の軽減を実現しています。CDNとの相性も良く、グローバルな配信にも適しています。

今後の展開

現在実装している機能をベースに、以下のような機能拡張を検討しています:

読書進捗の保存: 各章での読書位置を記録し、次回アクセス時に続きから読めるような機能の追加を予定しています。

追加のテーマ: セピア、ダーク以外にも、夜間読書向けのテーマや、目に優しいカラー設定の追加を検討しています。

ソーシャル機能: 読者コメントやレビュー機能、お気に入り作品の管理機能なども将来的には追加したいと考えています。

アクセシビリティの向上: スクリーンリーダー対応や、視覚障害者向けの読み上げ機能の実装も重要な課題として認識しています。

まとめ

今回の開発を通じて、CSSのwriting-modeプロパティを活用した縦書き表示の実装から、包括的な読書設定システムの構築まで、幅広い技術要素を組み合わせた小説読書プラットフォーム「NovelCat」を作成することができました。特に、多言語対応と設定の永続化により、日本語圏と英語圏の読者双方にとって使いやすいプラットフォームになったと考えています。

開発者として実際に実装した立場から、writing-mode: vertical-rlは日本語のWeb表示において非常に有効な技術であり、適切なレスポンシブデザインと組み合わせることで、モダンなブラウザでも美しい縦書き表示を実現できることを確認できました。

ぜひ実際にお試しください: https://novelcat.pages.dev/

この記事が同様の機能を実装したい開発者の参考になれば幸いです。また、実際のサイトの動作を確認していただくことで、より具体的な使用感を理解していただけると思います。縦書きモードや各種読書設定をぜひご体験ください。

技術的な詳細や実装コードについて質問がある場合は、コメントでお気軽にお声かけください。開発者として、可能な限りサポートさせていただきます。

技術仕様

  • Hugo version: 0.147.9
  • 対応ブラウザ: Chrome, Firefox, Safari, Edge (writing-mode対応ブラウザ)
  • レスポンシブ対応: デスクトップ、タブレット、モバイル
  • 言語: 日本語、英語

関連リンク

今すぐ体験: https://novelcat.pages.dev/posts/trump-reincarnation-ch1/ で縦書きモードや読書設定をお試しください。

開発者注記: この記事は実際の開発経験に基づいて作成されており、実装の詳細やトラブルシューティングについては開発者本人の知見を基にしています。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?