🎨 Modulo 4: File Statici
Rendi i tuoi templates bellissimi con CSS, JavaScript e immagini
4 di 8
45 minuti
Intermedio
🎯 Cos’è una Cartella Static?
Finora i nostri siti sono stati brutti e senza stile. La cartella static è il posto dove Flask cerca automaticamente file come:
CSS
Fogli di stile per design
JavaScript
Interattività e dinamismo
Immagini
Foto, icone, logo
Font
Caratteri personalizzati
💡 Perché “Static”?
Si chiamano “statici” perché non cambiano in base alle richieste degli utenti. Un file CSS è sempre lo stesso per tutti gli utenti. A differenza delle pagine HTML (template) che Flask “riempie” con dati diversi per ogni utente.
📁 Struttura della Cartella Static
Come per templates, Flask cerca automaticamente una cartella chiamata static.
flask-progetto/ │ ├── app.py ← File Python principale │ ├── templates/ ← Template HTML │ ├── base.html │ └── home.html │ ├── static/ ← 🆕 CARTELLA STATICA │ ├── css/ │ │ └── style.css │ ├── js/ │ │ └── script.js │ ├── images/ │ │ ├── logo.png │ │ └── background.jpg │ └── fonts/ │ └── custom-font.woff │ └── venv/ ← Ambiente virtuale
In PyCharm/VS Code:
- Clic destro sulla cartella del progetto
- New → Directory
- Digita:
static - Premi Invio
Dentro static/ crea:
css/→ per i file CSSjs/→ per i file JavaScriptimages/→ per le immaginifonts/→ per i font personalizzati
💡 Nota: Questa organizzazione non è obbligatoria, ma è una best practice che rende il progetto più ordinato e professionale.
🎨 CSS: Stili Professionali
Vediamo come collegare un file CSS al nostro template Flask.
Nella cartella static/css/:
- Clic destro su
static/css/ - New → File
- Digita:
style.css
/* Reset di base */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f8fafc;
}
/* Header */
header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 0;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
nav {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
nav a {
color: white;
text-decoration: none;
margin: 0 15px;
font-weight: 500;
transition: color 0.3s;
}
nav a:hover {
color: #c4b5fd;
}
/* Contenuto principale */
main {
max-width: 1200px;
margin: 40px auto;
padding: 0 20px;
}
/* Footer */
footer {
background: #1e293b;
color: white;
text-align: center;
padding: 20px;
margin-top: 40px;
}
Modifica il file templates/base.html:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Sito Flask{% endblock %}</title>
<!-- 🆕 COLLEGA IL CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
🔍 La Funzione url_for()
{{ url_for('static', filename='css/style.css') }} è MAGICA! Flask la converte automaticamente in:
<link rel="stylesheet" href="/static/css/style.css">
Perché usare url_for() invece di scrivere il percorso manualmente?
- Portabilità: Funziona anche se cambi la struttura delle cartelle
- Sicurezza: Gestisce automaticamente i caratteri speciali
- Best Practice: È il modo “Flask-way” di collegare file statici
🖼️ Immagini in Flask
Aggiungere immagini ai tuoi templates è semplice con la cartella static.
Metti le tue immagini nella cartella static/images/. Per esempio:
logo.png→ Logo del sitohero.jpg→ Immagine di copertinaprofile.jpg→ Foto profilo
{% extends "base.html" %}
{% block content %}
<div class="hero">
<!-- 🖼️ Immagine di sfondo -->
<img src="{{ url_for('static', filename='images/hero.jpg') }}"
alt="Immagine di copertina"
class="hero-image">
<h1>Benvenuto nel nostro sito</h1>
</div>
<div class="content">
<h2>Il nostro team</h2>
<div class="team-member">
<!-- 🖼️ Immagine profilo -->
<img src="{{ url_for('static', filename='images/mario.jpg') }}"
alt="Mario Rossi"
class="profile-pic">
<h3>Mario Rossi</h3>
<p>Sviluppatore Senior</p>
</div>
<div class="logo-section">
<!-- 🖼️ Logo -->
<img src="{{ url_for('static', filename='images/logo.png') }}"
alt="Logo Azienda"
class="logo">
</div>
</div>
{% endblock %}
/* Stili per immagini */
.hero {
position: relative;
text-align: center;
color: white;
margin-bottom: 40px;
}
.hero-image {
width: 100%;
max-height: 400px;
object-fit: cover;
border-radius: 10px;
}
.profile-pic {
width: 150px;
height: 150px;
border-radius: 50%;
border: 4px solid #667eea;
margin: 0 auto 15px;
display: block;
}
.logo {
width: 200px;
height: auto;
margin: 20px auto;
display: block;
}
/* Team */
.team-member {
text-align: center;
padding: 20px;
background: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
margin: 20px;
}
⚡ JavaScript: Interattività
Aggiungiamo funzionalità dinamiche al nostro sito con JavaScript.
Nella cartella static/js/:
- Clic destro su
static/js/ - New → File
- Digita:
script.js
console.log('JavaScript caricato con successo!');
// Esempio: Alert al caricamento della pagina
document.addEventListener('DOMContentLoaded', function() {
console.log('Pagina completamente caricata');
});
// Funzione per mostrare/nascondere contenuto
function toggleContent(elementId) {
const element = document.getElementById(elementId);
if (element.style.display === 'none') {
element.style.display = 'block';
} else {
element.style.display = 'none';
}
}
// Gestione click sul menu mobile (responsive)
const menuToggle = document.querySelector('.menu-toggle');
const navMenu = document.querySelector('nav ul');
if (menuToggle) {
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('show');
});
}
// Aggiungi classe "active" ai link del menu
const currentPage = window.location.pathname;
const navLinks = document.querySelectorAll('nav a');
navLinks.forEach(link => {
if (link.getAttribute('href') === currentPage) {
link.classList.add('active');
}
});
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Sito Flask{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<!-- 🆕 Aggiungi qui per CSS specifici per pagina -->
{% block styles %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
<!-- 🆕 COLLEGA JAVASCRIPT -->
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
<!-- 🆕 Blocco per JS specifici per pagina -->
{% block scripts %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block styles %}
<!-- CSS specifico per la pagina contatti -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/contatti.css') }}">
{% endblock %}
{% block content %}
<h1>Contattaci</h1>
<button onclick="toggleContent('info-nascoste')">
Mostra informazioni nascoste
</button>
<div id="info-nascoste" style="display: none;">
<p>Queste informazioni erano nascoste!</p>
</div>
{% endblock %}
{% block scripts %}
<!-- JavaScript specifico per la pagina contatti -->
<script src="{{ url_for('static', filename='js/contatti.js') }}"></script>
{% endblock %}
🔤 Font Personalizzati
Aggiungi caratteri personalizzati al tuo sito per un design unico.
Nella cartella static/fonts/ metti i tuoi file font:
montserrat.woff2montserrat.woffmontserrat.ttf
💡 Suggerimento: Scarica font gratuiti da Google Fonts o usa font di sistema.
/* Font personalizzati */
@font-face {
font-family: 'Montserrat';
src: url('../fonts/montserrat.woff2') format('woff2'),
url('../fonts/montserrat.woff') format('woff');
font-weight: normal;
font-style: normal;
}
/* Oppure usa Google Fonts (senza scaricare file) */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
/* Applica i font */
body {
font-family: 'Poppins', 'Segoe UI', sans-serif;
}
h1, h2, h3 {
font-family: 'Montserrat', 'Poppins', sans-serif;
font-weight: 700;
}
🔧 url_for() – Guida Completa
url_for() è una delle funzioni più potenti di Flask. Ecco come usarla in ogni situazione:
| Scopo | Sintassi | Risultato |
|---|---|---|
| File CSS | {{ url_for('static', filename='css/style.css') }} |
/static/css/style.css |
| Immagine | {{ url_for('static', filename='images/logo.png') }} |
/static/images/logo.png |
| JavaScript | {{ url_for('static', filename='js/script.js') }} |
/static/js/script.js |
| Font | {{ url_for('static', filename='fonts/custom.woff2') }} |
/static/fonts/custom.woff2 |
| Route | {{ url_for('home') }} |
/ |
| Route con parametri | {{ url_for('user_profile', username='mario') }} |
/user/mario |
| File in sottocartella | {{ url_for('static', filename='admin/css/admin.css') }} |
/static/admin/css/admin.css |
💡 Vantaggi di url_for()
Funziona ovunque sia il sito
Previene attacchi XSS
Cambia URL in un solo posto
Flask gestisce la cache
🏆 Best Practices
static/ ├── css/ │ ├── base.css ← Stili globali │ ├── home.css ← Stili specifici home │ └── responsive.css ← Media queries ├── js/ │ ├── main.js ← JavaScript globale │ ├── forms.js ← Validazione form │ └── animations.js ← Animazioni ├── images/ │ ├── logo/ │ ├── background/ │ └── icons/ └── fonts/
- ✅ BUONO:
main-nav.css,user-profile.js,company-logo.png - ❌ CATTIVO:
style1.css,script_finale.js,IMG_001.png
Aggiungi versioni ai file statici per forzare l’aggiornamento della cache dei browser:
<link rel="stylesheet"
href="{{ url_for('static', filename='css/style.css') }}?v=1.0">
Quando modifichi il file, cambia la versione: ?v=1.1
In produzione, minifica CSS e JavaScript:
- CSS: Rimuovi spazi, commenti, riduci nomi
- JavaScript: Usa strumenti come UglifyJS
- Immagini: Comprimi con tool come TinyPNG
💪 Esercizi Pratici
Facile
🎨 Sito Personale Stilizzato
Crea un sito personale con:
- Un file CSS con almeno 5 regole di stile
- Un’immagine del profilo
- Un logo nel header
- Font personalizzati (Google Fonts o locale)
- Usa
url_for()per tutti i file statici
Medio
⚡ Galleria Immagini Interattiva
Crea una galleria immagini con:
- 5 immagini nella cartella
static/images/gallery/ - CSS per una griglia responsiva (3 colonne desktop, 2 tablet, 1 mobile)
- JavaScript che mostra un’anteprima più grande al click
- Pulsanti “Precedente” e “Successivo” per navigazione
- Effetti hover sulle immagini
Difficile
🏗️ Dashboard Admin Completa
Crea una dashboard amministrativa con:
- Layout: Sidebar fissa + contenuto principale
- CSS: Sistema di colori (primary, secondary, danger, success)
- JavaScript:
- Toggle sidebar su mobile
- Validazione form in tempo reale
- Grafici fittizi con Chart.js (includi la libreria)
- Organizzazione:
- Separare CSS in
base.css,components.css,dashboard.css - Separare JS in
utils.js,charts.js,forms.js
- Separare CSS in
- Extra: Dark/light mode toggle con JavaScript
⚠️ Errori Comuni e Soluzioni
Sintomo: Il browser mostra “Failed to load resource” per CSS/JS/immagini
Cause comuni:
- Cartella non si chiama
static(maiuscole/minuscole contano!) - Percorso sbagliato in
url_for() - File non esiste nella posizione specificata
- Permessi di lettura sulla cartella
Debug: Apri “Strumenti sviluppatore” → “Network” e verifica gli URL
Sintomo: Modifichi i file ma nel browser vedi la versione vecchia
Soluzioni:
- Forza refresh cache: Ctrl+F5 (Windows) o Cmd+Shift+R (Mac)
- Aggiungi versione:
style.css?v=2 - Disabilita cache in DevTools: Network tab → Disable cache
- Modo sviluppo Flask: Assicurati che
debug=True
Sintomo: Il sito è lento, immagini sfocate o pixelate
Soluzioni:
- Ridimensiona: Usa dimensioni appropriate (non 4000px per thumbnail)
- Comprimi: TinyPNG per PNG/JPG
- Formati moderni: Usa WebP invece di JPG quando possibile
- Lazy loading:
loading="lazy"per immagini fuori schermo
📋 Riepilogo Concetti Chiave
Struttura
- Cartella
static/obbligatoria - Sottocartelle:
css/,js/,images/ - Organizzazione professionale
url_for()
- Sempre usare invece di percorsi hardcoded
- Sintassi:
{{ url_for('static', filename='path') }} - Portabilità e sicurezza
File Statici
- CSS: Stili e design
- JS: Interattività
- Immagini: Contenuti visivi
- Font: Tipografia
Best Practices
- Nomi file descrittivi
- Versioning per cache
- Minificazione in produzione
- Organizzazione logica
✅ Modulo 4 Completato!
Ora sai come rendere i tuoi siti Flask belli e interattivi. Pronto per gestire l’input degli utenti?
🎯 Cosa Aspettarti nel Prossimo Modulo
Form HTML
Crea form per raccogliere dati
Validazione
Controlla l’input degli utenti
Gestione Dati
Salva e processa informazioni