Skip to main content
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

1

Create the CSS file

Create flaskr/static/style.css:
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;
}
2

View the styled application

Go to http://127.0.0.1:5000/auth/login and the page should now have styling applied.

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 */
}

Form Styling

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:
  1. Hard refresh - Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
  2. Disable cache - Open browser DevTools and enable “Disable cache”
  3. 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.

Build docs developers (and LLMs) love