- Djangoでグローバルメニューを作りたい!
- CSSファイルってどこに配置したら良いの?
このような疑問にお答えします。
テンプレートHTMLを作り込もうとした場合に、最初に作るのがグローバルメニューという場合は多いのではないでしょうか。
ただバックエンドばかりいじっていると、HTMLやCSSなどの書き方に迷ってしまう方も多いはず。
本記事ではフロントエンドをこれから勉強しようとしている方に向けて、実装方法を解説します。
ファイルの配置場所と初期設定
まずは静的ファイルの配置場所と、静的ファイルを扱うための初期設定を行います。
ファイルの配置場所
今回作成するHTMLファイルとCSSファイルは、以下の場所に格納してください。
.
├── static/
│   └── css/
│       └── style.css  # プロジェクト全体で使用するCSS
└── templates
    └── base.html      # グローバルメニューを書く静的ファイルの初期設定
settings.pyに以下を追記します。
STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATIC_ROOT = BASE_DIR / "staticfiles"ファイルの設置場所と初期設定については、別記事で詳しく解説しました。
» 参考:【Django】静的ファイル(staticfiles)の配置・設定方法

フロントエンド側の実装ガイド
ごく簡単な例でお伝えしていきますので、一つずつ確実に進めていきましょう。
HTML
まずは、base.htmlの以下の部分にグローバルメニューを追加します。
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Blog{% endblock %}</title>
</head>
<body>
    <nav>
        <!-- ここにグローバルメニューを追加 -->
    </nav>
    <div>
        {% block content %}{% endblock %}
    </div>
</body>
</html>グローバルメニューはリストタグで組むことが多いので、今回もそれに倣っています。
<nav class="nav">
    <ul class="nav__list">
        <li class="nav__item">
            <a href="{% url 'blog:home' %}" class="nav__link">Home</a>
        </li>
        {% if user.is_authenticated %}
            <li class="nav__item">
                <a href="{% url 'blog:post_create' %}" class="nav__link">Create New Post</a>
            </li>
            <li class="nav__item">
                <form id="logout-form" action="{% url 'accounts:account_logout' %}" method="post">
                    {% csrf_token %}
                    <button type="submit">Logout</button>
                </form>
            </li>
        {% else %}
            <li class="nav__item">
                <a href="{% url 'accounts:account_login' %}" class="nav__link">Login</a>
            </li>
            <li class="nav__item">
                <a href="{% url 'accounts:account_signup' %}" class="nav__link">SignUp</a>
            </li>
        {% endif %}
    </ul>
</nav>この後スタイルを当てるため、各要素にはクラス名を付与しました。
ユーザーがログイン中ならログアウトボタンを、ログアウト中ならログインボタンとサインアップボタンを表示させています。
なお、ログイン・ログアウトなどの認証はdjango-allauthで組んだものを使っています。
認証の実装方法を知りたい方は、別記事もご覧ください。
» 参考:【django-allauth】accountsアプリでユーザー認証機能を集約する方法

これでHTML部分は完成です。

見た目は単なるリストのようになっているので、次のステップでグローバルメニューっぽくスタイルを当てていきます。
CSS
グローバルメニューはサイト全体に共通の内容なので、STATICFILES_DIRで定義した場所にCSSファイルを配置しましょう。
今回はのちのち静的ファイルの管理がしやすいよう、cssディレクトリを切って配置しました。
プロジェクトルート/
├── static/
│   └── css/
│       ├── reset.css
│       └── global-menu.cssreset.css
リセットスタイルを定義するのがreset.cssです。
Webブラウザはデフォルトでマージンやパディング、フォントサイズなどのスタイルを当ててしまうため、これをリセットするCSSを当てる必要があります。
今回はよく使われる簡単なリセットスタイルを当てます。
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}すべてのHTML要素(*)に対して、マージンとパディングをゼロにします。
また、ボックスのサイズはパディングやボーダーを含む値で計算するようにbox-sizingをborder-boxにしました。これをしないと、要素のサイズが思いがけず大きくなってしまうことがあります。
global-menu.css
先ほどのHTMLで指定したクラスに対して、スタイルを当てていきます。
.nav {
    background-color: #333;
    padding: 10px;
}
.nav__list{
    list-style-type: none;
    margin: 0;
    padding: 0;
    display: flex;
    margin-right: 20px;
}
.nav__item {
    margin-right: 20px;
}
.nav__link {
    color: white;
}
.nav__item button{
    background: none;
    border: none;
    text-decoration: underline;
    color:white;
    font-size: inherit;
    padding: 0 ;
    cursor: pointer;
}HTMLからCSSを読み込ませる
linkタグでreset.cssとglobal-menu.cssを読み込ませます。
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Blog{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/reset.css' %}">
    <link rel="stylesheet" href="{% static 'css/global-menu.css' %}">
</head>
<body>
    <nav>
        <!-- ここにグローバルメニューを追加 -->
    </nav>
    <div>
        {% block content %}{% endblock %}
    </div>
</body>
</html>ブラウザで表示を確認してみましょう。

このようにグローバルメニューっぽく表示できました。
一手間加えてグローバルメニューを改善する
ここからは保守性アップなど、プラスαの実装方法をご紹介します。
グローバルメニュー部分をテンプレート化する
base.html にグローバルメニューをベタ書きすると、かなりの分量になります。
これでは読みにくく保守がしづらいです。
そこで、ナビゲーションバー部分をテンプレートとして分離する方法をご紹介します。
まずはtemplates/include/global-menu.htmlを作って、グローバルメニュー部分だけを記述しましょう。
<nav class="nav">
</nav>
<ul class="nav__list">
    <li class="nav__item">
        <a href="{% url 'blog:home' %}" class="nav__link">Home</a>
    </li>
    {% if user.is_authenticated %}
        <li class="nav__item">
            <a href="{% url 'blog:post_create' %}" class="nav__link">Create New Post</a>
        </li>
        <li class="nav__item">
            <form id="logout-form"
                  action="{% url 'accounts:account_logout' %}"
                  method="post">
                {% csrf_token %}
                <button type="submit">Logout</button>
            </form>
        </li>
    {% else %}
        <li class="nav__item">
            <a href="{% url 'accounts:account_login' %}" class="nav__link">Login</a>
        </li>
        <li class="nav__item">
            <a href="{% url 'accounts:account_signup' %}" class="nav__link">SignUp</a>
        </li>
    {% endif %}
</ul>
</nav>これを base.html から読み込みます。
テンプレートファイルの中で他のテンプレートファイルを呼び出すには、テンプレートタグの {% include %} を使います。
{% load static %}
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="description"
              content="This is a blog where I share my thoughts on technology, programming, and more.">
        <meta name="keywords" content="blog">
        <link rel="stylesheet" href="{% static 'css/reset.css' %}">
        <link rel="stylesheet" href="{% static 'css/global-menu.css' %}">
        <title>
            {% block title %}
                My Site
            {% endblock title %}
        </title>
    </head>
    <body>
        <header>
            {% include "includes/global_menu.html" %}
        </header>
        <main>
            {% block content %}
            {% endblock content %}
        </main>
        <footer>
            <!-- フッター要素 -->
        </footer>
    </body>
</html>ちなみに include という名前は、他のテンプレートから呼び出されることを意味しています。
つまり、「再利用可能なパーツ」を格納するフォルダです。
何度も同じコードを書かない「DRY 原則(Don’t Repeat Yourself)」の観点からも、ぜひ実践したい実装方法になります。
 karo
karoコードの見通しも改善されます!











コメント