前回(HTMLファイルを表示する)で templates/index.html を表示できるようにしました。今回はそのHTMLからCSSとJavaScriptを読み込んで、見た目と動きをつけます。
ポイント:static ディレクトリと url_for
Flaskでは、CSS・JavaScript・画像などの静的ファイルを static/ ディレクトリに置きます。HTMLからは次のように url_for を使って参照します。
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<script src="{{ url_for('static', filename='script.js') }}"></script>
{{ ... }} はテンプレートエンジン(Jinja2)の記法で、url_for('static', filename='style.css') は実際には /static/style.css というパスに展開されます。パスを直接 /static/... と書かず url_for を使うのは、アプリの配置場所が変わってもリンクが壊れないようにするためです。
ディレクトリ構成
flask/
├── compose.yaml
├── Dockerfile
├── requirements.txt
├── app.py
├── templates/
│ └── index.html
└── static/ ← 追加
├── style.css ← 追加
└── script.js ← 追加
static/ も templates/ と同じく Flask の規約のディレクトリ名です。
コード
templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ゾンビハンティングクラブ</title>
<!-- url_for で static/style.css を読み込む -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<h1>ゾンビでもわかるFlask入門</h1>
<p>これは templates/index.html を表示しています。</p>
<p id="message">(JavaScript 実行前)</p>
<!-- url_for で static/script.js を読み込む -->
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>
static/style.css
色は #1a1a1a のような16進数コードでも書けますが、初心者のうちは black や red といった名前付きカラー(CSSに約140色用意されている)の方がひと目で意味がわかります。各行にもコメントを付けておきます。
/* ページ全体のスタイル */
body {
font-family: sans-serif;
background-color: black; /* 背景は黒 */
color: white; /* 文字は白 */
text-align: center; /* 中央寄せ */
padding-top: 50px; /* 上に余白 */
}
/* CSSが効いているとひと目でわかるように見出しを赤くする */
h1 {
color: red; /* 見出しは赤 */
}
/* JavaScriptで書き換わるメッセージ部分 */
#message {
color: gold; /* メッセージは金色(黄色) */
font-size: 1.2em; /* 文字を少し大きく */
}
static/script.js
「ページが表示されたら文字を書き換える」だけのコードですが、初心者でも追えるよう1行ずつコメントを付けています。
// ===========================================================
// このファイルは「ページが表示されたら文字を書き換える」JavaScriptです
// ===========================================================
// addEventListener =「○○が起きたら、この処理をして」と予約する命令
// "DOMContentLoaded" = HTMLの読み込みが終わったタイミング、という意味
// → つまり「HTMLの準備ができたら、中の処理を実行してね」という予約
document.addEventListener("DOMContentLoaded", function () {
// HTMLの中から id="message" の要素を1つ探してきて、el という箱に入れる
// (index.html の <p id="message"> がこれにあたる)
// const = あとで入れ替えない値につける宣言(うっかり書き換えを防げる)
const el = document.getElementById("message");
// 見つけた要素の「中の文字」を書き換える
// textContent = その要素が表示している文字そのもの
el.textContent = "JavaScript が読み込まれました!";
});
app.py は前回から変更ありません(render_template("index.html") を返すだけ)。
実行と確認
Docker環境はホットリロードが効くので、ファイルを保存するだけで反映されます。
docker compose up
url_for がきちんとパスに展開されているか、静的ファイルが配信されているかを確認します。
$ curl -s http://localhost:5000/ | grep -E "stylesheet|script src"
<link rel="stylesheet" href="/static/style.css">
<script src="/static/script.js"></script>
$ curl -s -o /dev/null -w "%{http_code} %{content_type}\n" http://localhost:5000/static/style.css
200 text/css; charset=utf-8
ブラウザで http://localhost:5000 を開くと、
- CSSが効いて黒い背景+赤い見出しになる
- JavaScriptが動いて「(JavaScript 実行前)」が「JavaScript が読み込まれました!」に書き換わる
ことが確認できます。
実行画面
実際にブラウザで開くと、次のように表示されます。黒い背景に赤い見出し、そしてJavaScriptによって書き換わった金色のメッセージが確認できます。
まとめ
- 静的ファイル(CSS/JS/画像)は
static/ディレクトリに置く - HTMLからは
url_for('static', filename='...')で参照する(パス直書きしない) -
static/も Flask 規約のディレクトリ名 - 次回はPythonの値をHTMLに埋め込む(Jinja2のテンプレート変数)予定
