Using CSS with Flask Templates
What You'll Learn
- What CSS is and why it's used
- How Flask templates (HTML files) work
- How to connect a CSS file to a Flask template
- How to organize a simple Flask project with static files (CSS, images)
- Optional: How to reuse a shared layout using a base template
What You Need
- Python 3.8+ installed
- A code editor (VS Code, Thonny, or similar)
- A web browser (Chrome, Edge, Firefox, etc.)
- Internet not required after installing Flask
Install Flask (once)
- Open your terminal or command prompt and run:
pip install flask
1) Quick Intro: HTML, CSS, and Flask Templates
- HTML is the structure of a web page (headings, paragraphs, images).
- CSS is the style (colors, fonts, spacing, layout).
- Flask is a Python web framework. It can render HTML templates and serve static files (like CSS and images).
- Flask templates use a system called Jinja. Anything inside
{{ ... }}or{% ... %}is processed by Flask before the page is sent to your browser.
2) Project Folder Setup
Create a new folder for your project, for example: flask_css_demo
Inside it, create this structure:
flask_css_demo/
app.py
templates/
index.html
static/
css/
style.css
images/
(optional images go here)- The folder names
templatesandstaticare special names Flask looks for by default. - CSS files must go inside the
staticfolder (commonlystatic/css/).
3) Step 1: Start a Simple Flask App (app.py)
Create app.py with this code:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template("index.html", title="Welcome to PyVerse")
if __name__ == "__main__":
app.run(debug=True)What this does:
- Creates a Flask app.
- When someone visits the homepage ("/"), Flask loads
index.htmlfrom the templates folder. - We pass a variable
titleinto the template (it will show up in the browser tab).
4) Step 2: Create the HTML Template (templates/index.html)
Create templates/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<!-- Link the CSS file the Flask way -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="site-header">
<h1>PyVerse: Using CSS with Flask Templates</h1>
<p class="tagline">Make your pages colorful and cool!</p>
</header>
<main class="container">
<section class="card">
<h2>Hello, Flask + CSS!</h2>
<p>This page is styled using our external CSS file.</p>
<button class="primary-btn">Click Me</button>
</section>
<section class="card">
<h2>Why CSS?</h2>
<ul>
<li>Change colors, fonts, and sizes</li>
<li>Control spacing and layout</li>
<li>Make pages look professional</li>
</ul>
</section>
<section class="card">
<h2>Optional Image</h2>
<p>Place an image in static/images and link to it like this:</p>
<img src="{{ url_for('static', filename='images/example.png') }}" alt="Example image" class="preview">
<p>(If you don't have an image yet, that's okay!)</p>
</section>
</main>
<footer class="site-footer">
<p>Made with Flask and CSS • PyVerse</p>
</footer>
</body>
</html>Important:
- The line with
url_for('static', filename='css/style.css')is how Flask finds your CSS file. {{ title }}is a template variable that comes fromapp.py.
5) Step 3: Add Styles (static/css/style.css)
Create static/css/style.css:
/* Base styles */
:root {
--primary: #4f46e5; /* Indigo */
--primary-dark: #3730a3;
--bg: #f5f7fb;
--text: #1f2937; /* Dark gray */
--card: #ffffff;
--accent: #10b981; /* Green */
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
}
/* Header */
.site-header {
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
color: white;
padding: 24px;
text-align: center;
}
.site-header h1 {
margin: 0 0 8px 0;
font-size: 28px;
}
.tagline {
margin: 0;
opacity: 0.9;
}
/* Layout */
.container {
max-width: 900px;
margin: 24px auto;
padding: 0 16px;
}
/* Cards */
.card {
background: var(--card);
border-radius: 12px;
padding: 16px 20px;
margin: 16px 0;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
}
.card h2 {
margin-top: 0;
}
/* Button */
.primary-btn {
background: var(--accent);
color: white;
border: none;
padding: 10px 16px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
}
.primary-btn:hover {
background: #0ea371;
}
/* Image */
.preview {
max-width: 100%;
border-radius: 8px;
margin-top: 8px;
}
/* Footer */
.site-footer {
text-align: center;
padding: 16px;
color: #6b7280;
}6) Step 4: Run Your App
- In the terminal, go to your project folder (the one with
app.py). - Run:
python app.py - Open your browser and go to:
http://127.0.0.1:5000 - You should see your styled page. If not, check the Troubleshooting section below.
7) How Flask Finds Your CSS
- Flask automatically serves files from the
staticfolder. - In HTML, instead of writing a hardcoded path like
/static/css/style.css, use:{{ url_for('static', filename='css/style.css') }} url_forbuilds the correct URL even if your app moves to another folder or server. It prevents broken links.
8) Add an Image (Optional)
- Put an image file into
static/images(for example,example.png). - In your HTML template, use:
<img src="{{ url_for('static', filename='images/example.png') }}" alt="Example image"> - Make sure the filename matches exactly (including uppercase/lowercase).
9) Bonus (Optional): Use a Base Template Once for CSS
If you have many pages, you don't want to repeat the <head> and CSS link every time. Use a base.html and extend it.
templates/base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}PyVerse App{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="site-header">
<h1>PyVerse Demo</h1>
<p class="tagline">Shared header from base template</p>
</header>
<main class="container">
{% block content %}{% endblock %}
</main>
<footer class="site-footer">
<p>Footer from base template</p>
</footer>
</body>
</html>templates/home.html:
{% extends "base.html" %}
{% block title %}Home • PyVerse{% endblock %}
{% block content %}
<section class="card">
<h2>Home Page</h2>
<p>This page extends base.html and reuses styles automatically.</p>
</section>
{% endblock %}Update app.py to use home.html:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template("home.html")
if __name__ == "__main__":
app.run(debug=True)10) Mini-Project: Profile Card Page
Goal: Make a simple, styled "My Profile" page using Flask + CSS.
Create templates/profile.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Profile</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="site-header">
<h1>My Profile</h1>
</header>
<main class="container">
<section class="card" style="max-width: 480px; margin: 24px auto; text-align: center;">
<img src="{{ url_for('static', filename='images/example.png') }}" alt="Profile" class="preview" style="width: 160px; border-radius: 50%;">
<h2>{{ name }}</h2>
<p>Grade: {{ grade }}</p>
<p>Favorite Hobby: {{ hobby }}</p>
<button class="primary-btn">Say Hi</button>
</section>
</main>
</body>
</html>Update app.py to pass data:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template("index.html", title="Welcome to PyVerse")
@app.route("/profile")
def profile():
return render_template(
"profile.html",
name="Alex",
grade=9,
hobby="Photography"
)
if __name__ == "__main__":
app.run(debug=True)- Visit
http://127.0.0.1:5000/profileto see your styled profile. - Customize name, grade, hobby, and colors in
style.css.
11) Troubleshooting
- My CSS isn't loading (page looks plain):
- Is your CSS file in
static/css/style.css? - Did you link it with
{{ url_for('static', filename='css/style.css') }}? - Did you restart the Flask server after creating files?
- Try a hard refresh in your browser (Ctrl+F5 or Cmd+Shift+R).
- Is your CSS file in
- I get a TemplateNotFound error:
- Make sure the template file is inside the
templatesfolder. - Check the filename in
render_template("index.html")matches exactly.
- Make sure the template file is inside the
- The image isn't showing:
- Is the image inside
static/images? - Is the filename correct (including .png, .jpg)?
- Check the path in
url_for:images/your_file.png
- Is the image inside
- I get a 404 on /static/...:
- Confirm the folder is named
static(notstaticsorStatic). - Confirm the file exists and the path in
url_foris correct.
- Confirm the folder is named
- Unicode or weird characters in the browser:
- Ensure your HTML includes
<meta charset="utf-8">in the head.
- Ensure your HTML includes
12) Practice Tasks
- Change the site's accent color in
style.css(try a different color for--accent). - Add another card section with a list of your three favorite snacks.
- Add a new route
/aboutthat shows a simple page reusing the same CSS. - Optional: Create
base.htmland make bothindex.htmlandprofile.htmlextend it.
13) Quick Review
- Flask looks for HTML templates in
templatesand for CSS/images instatic. - Use
url_for('static', filename='path/to/file')to link CSS and images. - Keep CSS in a separate file to keep your HTML clean and reusable.
- Optional template inheritance helps you avoid repeating the same HTML on every page.
Wrap-Up
You did it! You connected CSS to Flask templates and styled a real page. Keep experimenting with colors, spacing, and layouts to make your pages uniquely yours. 🎨