The authentication views and templates work, but they look very plain. Some CSS can be added to add style to the HTML layout. The style won’t change, so it’s a static file rather than a template.
Static Files in Flask
Flask automatically adds a static view that takes a path relative to the flaskr/static directory and serves it. The base.html template already has a link to the style.css file:
{{ url_for('static', filename='style.css') }}
Besides CSS, other types of static files might be:
- JavaScript functions
- Logo images
- Font files
- Any other files that don’t change
They are all placed under the flaskr/static directory and referenced with url_for('static', filename='...').
Add CSS Styling
Create the CSS file
Create flaskr/static/style.css:html {
font-family: sans-serif;
background: #eee;
padding: 1rem;
}
body {
max-width: 960px;
margin: 0 auto;
background: white;
}
h1, h2, h3, h4, h5, h6 {
font-family: serif;
color: #377ba8;
margin: 1rem 0;
}
a {
color: #377ba8;
}
hr {
border: none;
border-top: 1px solid lightgray;
}
nav {
background: lightgray;
display: flex;
align-items: center;
padding: 0 0.5rem;
}
nav h1 {
flex: auto;
margin: 0;
}
nav h1 a {
text-decoration: none;
padding: 0.25rem 0.5rem;
}
nav ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
nav ul li a, nav ul li span, header .action {
display: block;
padding: 0.5rem;
}
.content {
padding: 0 1rem 1rem;
}
.content > header {
border-bottom: 1px solid lightgray;
display: flex;
align-items: flex-end;
}
.content > header h1 {
flex: auto;
margin: 1rem 0 0.25rem 0;
}
.flash {
margin: 1em 0;
padding: 1em;
background: #cae6f6;
border: 1px solid #377ba8;
}
.post > header {
display: flex;
align-items: flex-end;
font-size: 0.85em;
}
.post > header > div:first-of-type {
flex: auto;
}
.post > header h1 {
font-size: 1.5em;
margin-bottom: 0;
}
.post .about {
color: slategray;
font-style: italic;
}
.post .body {
white-space: pre-line;
}
.content:last-child {
margin-bottom: 0;
}
.content form {
margin: 1em 0;
display: flex;
flex-direction: column;
}
.content label {
font-weight: bold;
margin-bottom: 0.5em;
}
.content input, .content textarea {
margin-bottom: 1em;
}
.content textarea {
min-height: 12em;
resize: vertical;
}
input.danger {
color: #cc2f2e;
}
input[type=submit] {
align-self: start;
min-width: 10em;
}
View the styled application
CSS Tips
If you change a static file, refresh the browser page. If the change doesn’t show up, try clearing your browser’s cache.
Flexbox for Layout
The CSS uses Flexbox for responsive layouts:
nav {
display: flex;
align-items: center;
}
nav h1 {
flex: auto; /* Takes up remaining space */
}
Forms use flexbox with column direction for vertical layout:
.content form {
display: flex;
flex-direction: column;
}
input[type=submit] {
align-self: start; /* Don't stretch to full width */
min-width: 10em;
}
Flash Message Styling
Flash messages get distinct styling to stand out:
.flash {
margin: 1em 0;
padding: 1em;
background: #cae6f6;
border: 1px solid #377ba8;
}
Static File Organization
For larger applications, you might organize static files into subdirectories:
static/
├── css/
│ ├── style.css
│ └── theme.css
├── js/
│ └── main.js
└── images/
└── logo.png
Reference them with:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}">
Browser Caching
Browsers cache static files for performance. During development, you can:
- Hard refresh - Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
- Disable cache - Open browser DevTools and enable “Disable cache”
- Use cache busting - Add version query parameters:
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}?v=1.0">
For production, Flask extensions like Flask-Assets can handle cache busting automatically by adding content hashes to filenames.