🎨 Modulo 4: File Statici

Rendi i tuoi templates bellissimi con CSS, JavaScript e immagini

📚

MODULO
4 di 8

⏱️

TEMPO
45 minuti

🎯

LIVELLO
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.

📂 Struttura del Progetto
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

1
Crea la cartella static

In PyCharm/VS Code:

  • Clic destro sulla cartella del progetto
  • New → Directory
  • Digita: static
  • Premi Invio

2
Crea le sottocartelle

Dentro static/ crea:

  • css/ → per i file CSS
  • js/ → per i file JavaScript
  • images/ → per le immagini
  • fonts/ → 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.

1
Crea il file CSS

Nella cartella static/css/:

  • Clic destro su static/css/
  • New → File
  • Digita: style.css

2
Scrivi il CSS di base

📄 static/css/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;
}

3
Collega il CSS al template

Modifica il file templates/base.html:

📄 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.

1
Prepara le immagini

Metti le tue immagini nella cartella static/images/. Per esempio:

  • logo.png → Logo del sito
  • hero.jpg → Immagine di copertina
  • profile.jpg → Foto profilo

2
Aggiungi immagini al template

📄 templates/home.html
{% 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 %}

3
Aggiungi stili per le immagini

📄 static/css/style.css – Aggiungi
/* 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.

1
Crea il file JavaScript

Nella cartella static/js/:

  • Clic destro su static/js/
  • New → File
  • Digita: script.js

2
Scrivi JavaScript di esempio

📄 static/js/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');
    }
});

3
Collega JavaScript al template

📄 templates/base.html – Aggiungi
<!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>

4
Esempio: Pagina con JavaScript specifico

📄 templates/contatti.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.

1
Aggiungi i file font

Nella cartella static/fonts/ metti i tuoi file font:

  • montserrat.woff2
  • montserrat.woff
  • montserrat.ttf

💡 Suggerimento: Scarica font gratuiti da Google Fonts o usa font di sistema.

2
Definisci i font nel CSS

📄 static/css/style.css – Aggiungi
/* 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()

URL Relativi
Funziona ovunque sia il sito
Sicurezza
Previene attacchi XSS
Manutenzione
Cambia URL in un solo posto
Performance
Flask gestisce la cache

🏆 Best Practices

1. Organizzazione delle Cartelle
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/

2. Nomenclatura dei File
  • ✅ BUONO: main-nav.css, user-profile.js, company-logo.png
  • ❌ CATTIVO: style1.css, script_finale.js, IMG_001.png

3. Gestione della Cache

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

4. Minificazione (Produzione)

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

Esercizio 1
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

Esercizio 2
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

Esercizio 3
Difficile

🏗️ Dashboard Admin Completa

Crea una dashboard amministrativa con:

  1. Layout: Sidebar fissa + contenuto principale
  2. CSS: Sistema di colori (primary, secondary, danger, success)
  3. JavaScript:
    • Toggle sidebar su mobile
    • Validazione form in tempo reale
    • Grafici fittizi con Chart.js (includi la libreria)
  4. Organizzazione:
    • Separare CSS in base.css, components.css, dashboard.css
    • Separare JS in utils.js, charts.js, forms.js
  5. Extra: Dark/light mode toggle con JavaScript

⚠️ Errori Comuni e Soluzioni

❌ 404 Not Found per file statici

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

❌ CSS/JS non si aggiorna

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

❌ Immagini troppo grandi

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?

ORA SEI QUI
🎨 Modulo 4
File Statici

MODULO 5

🎯 Cosa Aspettarti nel Prossimo Modulo

📝

Form HTML

Crea form per raccogliere dati

🔐

Validazione

Controlla l’input degli utenti

💾

Gestione Dati

Salva e processa informazioni

Torna in alto