martedì 24 marzo 2026

Corso di JavaScript & Programmazione Web: 4 – Funzioni

4 – Funzioni

1. Definizione e richiamo di funzioni

Una funzione è un blocco di codice riutilizzabile che esegue un’operazione specifica.
Si definisce con la parola chiave function, seguita da un nome, eventuali parametri tra parentesi tonde e il corpo tra parentesi graffe.

📌 Sintassi base

function saluta() { console.log("Ciao mondo!"); } // Richiamo saluta();

➡️ Output:

Ciao mondo!

2. Parametri e valori di ritorno

Le funzioni possono ricevere parametri (input) e restituire un valore di ritorno (output) con la parola chiave return.

📌 Esempio

function somma(a, b) { return a + b; } let risultato = somma(5, 7); console.log(risultato);

➡️ Output:

12

3. Funzioni freccia (()=>{})

Introdotte in ES6, le funzioni freccia sono una sintassi più compatta, spesso usata con funzioni anonime o callback.

📌 Esempi

// Funzione classica function quadrato(x) { return x * x; } // Funzione freccia equivalente const quadratoArrow = (x) => x * x; console.log(quadrato(4)); // 16 console.log(quadratoArrow(4)); // 16

👉 Se il corpo contiene una sola istruzione, le graffe e return possono essere omessi.
👉 Attenzione: le funzioni freccia non hanno il proprio this, quindi si comportano diversamente in contesti di oggetti.

4. Scope delle variabili

Lo scope definisce la visibilità delle variabili:

  • Globale: dichiarata fuori da qualsiasi funzione → visibile ovunque.

  • Locale: dichiarata dentro una funzione → visibile solo lì.

  • Block scope (let, const): visibile solo all’interno delle parentesi graffe in cui è definita.

📌 Esempio

let globale = "Sono globale"; function esempioScope() { let locale = "Sono locale"; console.log(globale); // ✅ accessibile console.log(locale); // ✅ accessibile } esempioScope(); console.log(globale); // ✅ accessibile // console.log(locale); ❌ errore: locale non definita

5. Esercizio pratico – Funzione palindroma

Un palindromo è una parola che si legge uguale in avanti e indietro (es. "anna", "radar").

📌 Soluzione classica

function isPalindromo(parola) { let parolaInvertita = parola.split("").reverse().join(""); return parola === parolaInvertita; } // Test console.log(isPalindromo("anna")); // true console.log(isPalindromo("cane")); // false

📌 Soluzione con funzione freccia

const isPalindromo = (parola) => { return parola === parola.split("").reverse().join(""); }; console.log(isPalindromo("radar")); // true

6. Sintesi concettuale

  • Le funzioni permettono di organizzare e riutilizzare il codice.

  • Possono avere parametri in ingresso e valori di ritorno in uscita.

  • Le funzioni freccia rendono la sintassi più compatta, ma hanno differenze con this.

  • Lo scope regola la visibilità delle variabili.

  • Applicazione pratica: controllo di palindromi.

lunedì 23 marzo 2026

Corso di JavaScript & Programmazione Web: 3 – Strutture di controllo

3 – Strutture di Controllo

1. Introduzione generale

Le strutture di controllo costituiscono il cuore di ogni linguaggio di programmazione. Esse permettono di modificare il normale flusso sequenziale di esecuzione delle istruzioni, introducendo la possibilità di:

  • prendere decisioni (branching);

  • ripetere istruzioni (looping);

  • selezionare alternative in maniera efficiente.

Dal punto di vista teorico, tali strutture sono collegate alla logica booleana e all’algebra dei predicati, che rappresentano il fondamento matematico della programmazione. Secondo il teorema di Böhm-Jacopini (1966), qualsiasi algoritmo può essere implementato utilizzando solo tre strutture fondamentali:

  1. sequenza,

  2. selezione (if/else, switch),

  3. iterazione (for, while).

2. Strutture condizionali

2.1 If/Else

Il costrutto if permette di eseguire un blocco di codice solo se una condizione è vera. La forma generale è:

if (condizione) { istruzioni } else { istruzioni alternative }\text{if (condizione) \{ istruzioni \} else \{ istruzioni alternative \}}

📘 Esempio (Python)

x = 7
if x % 2 == 0:
    print("Numero pari")
else:
    print("Numero dispari")

📘 Esempio (JavaScript)

let x = 7;
if (x % 2 === 0) {
    console.log("Numero pari");
} else {
    console.log("Numero dispari");
}

2.2 Operatori logici

Gli operatori logici consentono di combinare condizioni:

  • AND (&& o and) → vero solo se entrambe le condizioni sono vere.

  • OR (|| o or) → vero se almeno una condizione è vera.

  • NOT (! o not) → inverte il valore della condizione.

📘 Esempio combinato

eta = 20
cittadinanza = "italiana"
if eta >= 18 and cittadinanza == "italiana":
    print("Puoi votare")

3. Strutture iterative

3.1 Ciclo For

Il ciclo for è utile quando si conosce a priori il numero di iterazioni.

📘 Esempio

for i in range(5):   # ripete da 0 a 4
    print("Iterazione:", i)

3.2 Ciclo While

Il ciclo while viene usato quando non si conosce il numero di iterazioni a priori, ma si ripete finché una condizione è vera.

📘 Esempio

n = 0
while n < 5:
    print("n vale:", n)
    n += 1

3.3 Ciclo For…of (o foreach)

Nei linguaggi moderni (JavaScript, Python, Java) esiste un costrutto per iterare direttamente sugli elementi di una collezione.

📘 Esempio (JavaScript)

let numeri = [2, 4, 6, 8];
for (let n of numeri) {
    console.log(n);
}

📘 Esempio (Python – foreach implicito)

numeri = [2, 4, 6, 8]
for n in numeri:
    print(n)

4. Switch/Case

Lo switch è un costrutto che semplifica la gestione di più condizioni alternative. È concettualmente simile a una catena di if/elif, ma più leggibile.

📘 Esempio (JavaScript)

let giorno = 3;
switch (giorno) {
    case 1:
        console.log("Lunedì");
        break;
    case 2:
        console.log("Martedì");
        break;
    case 3:
        console.log("Mercoledì");
        break;
    default:
        console.log("Altro giorno");
}

5. Esercizio applicativo – Stampare i numeri pari

Traccia

Scrivere un programma che stampi solo i numeri pari da 1 a N.

Soluzione 1 – Ciclo For con condizione

N = 20
for i in range(1, N+1):
    if i % 2 == 0:
        print(i)

Soluzione 2 – Incremento diretto (più efficiente)

N = 20
for i in range(2, N+1, 2):  # parte da 2 e salta di 2
    print(i)

Soluzione 3 – While loop

N = 20
i = 2
while i <= N:
    print(i)
    i += 2

Soluzione 4 – For…of con filtro (JavaScript)

let numeri = Array.from({length: 20}, (_, i) => i + 1);
for (let n of numeri) {
    if (n % 2 === 0) {
        console.log(n);
    }
}

6. Osservazioni critiche

  • Efficienza: la seconda soluzione evita condizioni logiche, riducendo il numero di confronti.

  • Generalizzazione: lo stesso approccio può essere usato per stampare multipli di 3, numeri primi, ecc.

  • Didattica: l’esercizio è ideale per introdurre il concetto di modularità e ottimizzazione.

7. Conclusione

Il modulo sulle strutture di controllo non è soltanto un momento introduttivo, ma segna il passaggio dall’uso “statico” del linguaggio a un utilizzo realmente algoritmico. Con if, for, while e switch si entra nella dimensione del calcolo automatico in senso stretto: decisioni e ripetizioni, gli stessi meccanismi logici che caratterizzano l’agire umano, trovano una formalizzazione esatta all’interno del linguaggio di programmazione.


domenica 22 marzo 2026

Corso di JavaScript & Programmazione Web: 2 – Fondamenti di programmazione

2 — Fondamenti di programmazione

1) Variabili — let, const, var (approfondimento)

Concetti chiave

  • const: riferimento immutabile di binding. Non si può riassegnare il nome a un altro valore. Se il valore è un oggetto/array, le sue proprietà/elementi possono comunque cambiare.

  • let: variabile riassegnabile con scope di blocco ( { ... } ). Usare per valori che cambiano.

  • var: scope di funzione (o globale se dichiarato fuori funzione), soggetto a hoisting (dichiarazione "spostata" in cima), comportamento problematico — evitare salvo comprensione storica.

Esempi pratici

// const
const PI = 3.14159;
PI = 3; // TypeError: Assignment to constant variable.
// let
let counter = 0;
if (true) {
let counter = 10; // scope diverso: non sovrascrive l'esterno
console.log(counter); // 10
}
console.log(counter); // 0
// var (evitare)
function f() {
if (true) {
var x = 1; // scope di funzione
}
console.log(x); // 1
}

Hoisting e Temporal Dead Zone (TDZ)

  • var x; è "hoisted" (dichiarazione spostata all'inizio), quindi console.log(x) prima della dichiarazione stampa undefined.

  • let/const sono anch’essi "visibili" ma non utilizzabili prima della dichiarazione — questo causa ReferenceError se provi ad accedervi nella TDZ.

Best practice: preferire const per valori che non cambiano, let quando serve riassegnare. Evitare var.

2) Tipi di dato: Number, String, Boolean (con casi speciali)

Number (IEEE 754 double precision)

  • Rappresentazione in virgola mobile → attenzioni a precisione.

  • Esempi: 42, 3.14, -0 (significato particolare), NaN, Infinity.

typeof 123; // "number"
typeof 3.14; // "number"
Number.isNaN(NaN); // true
1 / 0; // Infinity

Nota su NaN: NaN !== NaN. Usare Number.isNaN() per verificare.

BigInt

  • Per interi molto grandi: 123n è un BigInt (JS moderno).

const big = 9007199254740993n; // oltre MAX_SAFE_INTEGER

String

  • Testo: concatenazione con +, template literal con backticks `... ${expr} ...`.

"ciao" + " mondo"; // "ciao mondo"
`2 + 3 = ${2 + 3}`; // "2 + 3 = 5"

Boolean

  • true / false. Molte operazioni e valori sono truthy o falsy (es. 0, "", null, undefined, NaN sono falsy).

Type coercion (attenzione!)

  • "2" + 3"23" (concatenazione).

  • +"3" o Number("3") converte a numero.

  • Preferire conversioni esplicite.

3) Operatori matematici e aritmetica (con attenzione alla precisione)

Operatori principali

  • Aritmetici: +, -, *, /, % (modulo), ** (potenza)

  • Incremento/decremento: ++, --

  • Assegnazione composta: +=, -=, *=, /=

Precedenza (breve)

  1. ()

  2. **

  3. *, /, %

  4. +, -

  5. assegnazioni

Virgola mobile: problema classico

Esempio noto: 0.1 + 0.2 in JavaScript restituisce 0.30000000000000004 (perché i numeri sono rappresentati in base 2 e non tutte le frazioni decimali sono esatte).

Dimostrazione semplice (metodo stabile): se vuoi sommare 0.1 e 0.2 con esattezza decimale di 1 cifra:

  • moltiplica per 10: 0.1 * 10 = 1, 0.2 * 10 = 2

  • somma intera: 1 + 2 = 3

  • riporta a scala decimale: 3 / 10 = 0.3

Esempio pratico in codice (soluzione semplice):

function preciseAdd(a, b) {
const sA = a.toString();
const sB = b.toString();
const dA = (sA.split('.')[1] || '').length;
const dB = (sB.split('.')[1] || '').length;
const factor = 10 ** Math.max(dA, dB);
return (Math.round(a * factor) + Math.round(b * factor)) / factor;
}
preciseAdd(0.1, 0.2); // 0.3

Nota: per applicazioni finanziarie reali usare librerie per aritmetica decimale (es. decimal.js) o tipi specifici.

Divisione per zero

  • 1 / 0Infinity

  • 0 / 0NaN

Modulo con numeri negativi

  • % restituisce il resto, ma il segno segue il dividendo in JS: -5 % 3 === -2.

4) Operatorii di confronto e logici

Confronti

  • == (uguaglianza non rigorosa): effettua coercizioni.

  • === (uguaglianza stretta): no coercione — preferire ===.

  • != vs !== analoghi.

Esempi insidiosi

0 == false; // true
0 === false; // false
"" == 0; // true
null == undefined; // true
null === undefined; // false

Regola: usare === a meno di esplicita necessità di coercizione.

Logici (&&, ||, !)

  • Valutano operandi e short-circuit:

    • a && b: restituisce a se falsy, altrimenti b.

    • a || b: restituisce a se truthy, altrimenti b.

  • Utile per default: const name = input || "Anonimo" (ma attenzione se input === "").

Esempio:

function getDefault(input) {
return input || "default";
}
getDefault(""); // "default"
getDefault("ciao"); // "ciao"

Se vuoi distinguere "" da null/undefined, usa ?? (nullish coalescing) in JS moderno:

input ?? "default"; // ritorna input se non null/undefined; altrimenti default

5) Esercizi pratici 

Esercizio A — rapido (console)

Scrivi espressioni che valutino a true:

  1. 0 == false? (spiegare il perché)

  2. 0 === false? (spiegare perché no)

Soluzione (spiegata):

  1. 0 == false è true perché == converte false in 0 prima del confronto.

  2. 0 === false è false perché il tipo number non è uguale al tipo boolean.

Esercizio B — gestione stringhe e numeri

Dato l'input utente a = "3.5", b = "2", calcola la somma numerica corretta.

Soluzione:

const a = "3.5";
const b = "2";
const sum = parseFloat(a) + parseFloat(b); // 5.5

Esercizio C — problema di virgola mobile

Dimostrare il comportamento di 0.1 + 0.2 e risolverlo con scaling:

console.log(0.1 + 0.2); // 0.30000000000000004
console.log( (0.1*10 + 0.2*10) / 10 ); // 0.3

Discussione: spiegare perché accade e come risolvere per casi didattici.

6) Laboratorio guidato: Calcolatrice base

Requisiti minimi

  • Accetta due numeri (decimali possibili).

  • Opera le quattro funzioni di base: +, -, *, /.

  • Controlla input non numerico e divisione per zero.

  • Mostra risultato in modo leggibile (es. 2 decimali opzionali).

Versione 1 — Console (base)

function calc(a, b, op) {
const x = parseFloat(a);
const y = parseFloat(b);
if (Number.isNaN(x) || Number.isNaN(y)) {
return 'Errore: input non numerico';
}
switch(op) {
case '+': return x + y;
case '-': return x - y;
case '*': return x * y;
case '/':
if (y === 0) return 'Errore: divisione per zero';
return x / y;
default:
return 'Operatore non supportato';
}
}
console.log(calc("2.5", "1.2", "+")); // 3.7

Versione 2 — semplice UI HTML + JS (pulita e funzionante)

Copiare questo file .html e aprirlo con un browser:

<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8" />
<title>Calcolatrice Base</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.box { max-width: 420px; margin: auto; background:#f7f7f7; padding:16px; border-radius:8px; }
input, select, button { font-size:1rem; padding:8px; margin:6px 0; width:100%; box-sizing:border-box; }
.result { margin-top:12px; padding:10px; background:#222; color:#fff; border-radius:6px; text-align:center; }
</style>
</head>
<body>
<div class="box">
<h2>Calcolatrice Base</h2>
<label>Primo numero
<input id="a" type="text" placeholder="es. 3.5" />
</label>
<label>Secondo numero
<input id="b" type="text" placeholder="es. 2" />
</label>
<label>Operazione
<select id="op">
<option value="+">Addizione (+)</option>
<option value="-">Sottrazione (-)</option>
<option value="*">Moltiplicazione (*)</option>
<option value="/">Divisione (/)</option>
</select>
</label>
<button id="calcBtn">Calcola</button>
<div id="result" class="result" aria-live="polite">Risultato: —</div>
</div>
<script>
function safeParseNumber(s) {
if (s === null || s === undefined) return NaN;
// rimuove spazi e usa la virgola come possibile separatore
s = s.trim().replace(',', '.');
return Number(s);
}
function calc(aRaw, bRaw, op) {
const a = safeParseNumber(aRaw);
const b = safeParseNumber(bRaw);
if (Number.isNaN(a) || Number.isNaN(b)) {
return { ok: false, msg: 'Errore: uno dei due input non è un numero valido' };
}
if (op === '/' && b === 0) {
return { ok: false, msg: 'Errore: divisione per zero' };
}
// operazione: usiamo parseFloat-style, ma per risultati precisi usare preciseAdd ecc.
let res;
switch (op) {
case '+': res = a + b; break;
case '-': res = a - b; break;
case '*': res = a * b; break;
case '/': res = a / b; break;
default: return { ok: false, msg: 'Operatore non supportato' };
}
// formattazione: mostra fino a 10 cifre significative evitando notazione esponenziale per numeri piccoli
const display = Number.isFinite(res) ? Number(res.toPrecision(12)).toString() : String(res);
return { ok: true, value: display };
}
document.getElementById('calcBtn').addEventListener('click', () => {
const a = document.getElementById('a').value;
const b = document.getElementById('b').value;
const op = document.getElementById('op').value;
const out = calc(a, b, op);
const el = document.getElementById('result');
if (!out.ok) {
el.textContent = out.msg;
el.style.background = '#c0392b';
} else {
el.textContent = 'Risultato: ' + out.value;
el.style.background = '#2ecc71';
}
});
</script>
</body>
</html>

Spiegazioni implementative:

  • safeParseNumber supporta la virgola come separatore decimale (utile per utenti italiani).

  • calc verifica input, protegge dalla divisione per zero e restituisce sempre oggetti {ok, value/msg} per gestire errori con chiarezza.

  • toPrecision(12) evita stampare la lunga 0.30000000000000004 in caso di somme come 0.1 + 0.2; si potrebbe usare la versione preciseAdd per risultati esatti quando necessario.

7) Esercizi di consolidamento 

  1. Estendere la calcolatrice per supportare la percentuale: es. a % → restituisce a / 100.

  2. Memoria: aggiungere tasti M+, MC, MR (memoria).

  3. Chain calc (intermedio): permettere insert di più operazioni in un array e ridurle (es. 3 + 4 * 2). Nota: valutare precedenza operazioni.

  4. Precisione avanzata: implementare funzioni preciseAdd, preciseSub, preciseMul, preciseDiv che usano scaling intero per ottenere risultati corretti per numeri con molti decimali.

  5. Unit tests: scrivere test (con Jest o simple assertions) per le funzioni della calcolatrice.

8) Cheat-sheet rapido

  • Dichiarazioni: const a = 1; let b = 2; var c = 3;

  • Convertire a numero: Number("3.14"), parseFloat("3,14".replace(',', '.'))

  • Verifica NaN: Number.isNaN(x)

  • Confronto corretto: usare === e !==

  • String template: `Risultato: ${x}`

  • Profilo virgola mobile: 0.1 + 0.2 === 0.3false in JS; usare scaling per precisione.


sabato 21 marzo 2026

Corso di JavaScript & Programmazione Web: 1 – Introduzione a JavaScript

1. Introduzione a JavaScript
 

1 — Cos’è JavaScript e dove si usa

JavaScript è il linguaggio di programmazione che gira nei browser e rende le pagine web interattive: rispondere a click, modificare contenuti, chiamare servizi remoti, animare elementi. Oggi si usa anche lato server (Node.js), in app mobile / desktop (Electron, React Native) e in ambienti IoT, ma qui ci concentriamo sull’uso nel browser.

Punti chiave:

  • Linguaggio interpretato dal browser (Chrome, Firefox, Safari, Edge).

  • Manipola il DOM (Document Object Model) per cambiare la pagina al volo.

  • Asincrono per natura (callback, Promise, async/await).

  • Standard attuale: ES6+ (let/const, arrow functions, modules).

2 — Come inserire JavaScript in una pagina HTML

Esistono tre modalità principali:

A — Inline (NON consigliato per codice esteso)

<!doctype html>
<html>
<body>
<button onclick="alert('Ciao!')">Click</button>
</body>
</html>

Pratico per test, poco manutenibile.

B — Internal (all'interno di nella pagina)

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Internal JS</title>
</head>
<body>
<script>
console.log('Script eseguito dall\'internal <script>');
</script>
</body>
</html>

C — External (file .js separato — miglior pratica)

index.html

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>External JS</title>
</head>
<body>
<script src="app.js" defer></script>
</body>
</html>

app.js

console.log('Script esterno con defer');

Nota su defer: con defer lo script viene scaricato subito ma eseguito dopo che il DOM è pronto — comodo e sicuro. In alternativa puoi mettere lo script prima di </body>.

3 — Console del browser e strumenti di sviluppo (DevTools)

Come aprire la console

  • Chrome / Edge: Ctrl+Shift+I (Windows) o Cmd+Opt+I (Mac), poi tab Console. Oppure F12.

  • Firefox: Ctrl+Shift+K / Cmd+Opt+K.

  • Safari: attiva gli strumenti in Preferences → Advanced → Show Develop menu, poi Cmd+Opt+C.

Cose utili da DevTools

  • Console: vedi console.log, errori JS, esegui espressioni live.

  • Elements / DOM: ispeziona struttura HTML, modifica al volo.

  • Sources: vedi file JS, imposta breakpoint (debugger).

  • Network: verifica richieste HTTP e tempi.

  • Performance & Memory: profiling avanzato.

Metodi della console utili

console.log('info');
console.info('info');
console.warn('attenzione');
console.error('errore');
console.table([{name:'Anna', age:20},{name:'Luca', age:30}]);
console.dir(document.body); // esplora oggetto come oggetto

4 — Esercizio pratico: stampare un messaggio nella console e sulla pagina

Ti do tre soluzioni: la più semplice (inline), quella raccomandata (external + defer), e una che usa DOMContentLoaded (per sicurezza).

4.1 Esempio rapido — Inline (solo per prova)

Crea inline.html e aprilo nel browser:

<!doctype html>
<html>
<head><meta charset="utf-8"/><title>Inline JS</title></head>
<body>
<h1 id="titolo">Titolo pagina</h1>
<script>
console.log('Ciao console! (inline)');
document.getElementById('titolo').textContent = 'Ciao dalla pagina (inline)';
</script>
</body>
</html>

Apri DevTools → Console: vedrai il messaggio. La pagina mostra testo modificato.

4.2 Esempio raccomandato — External + defer

Crea index.html:

<!doctype html>
<html>
<head><meta charset="utf-8"/><title>External JS</title></head>
<body>
<h1 id="titolo">Titolo originale</h1>
<button id="btn">Cliccami</button>
<script src="app.js" defer></script>
</body>
</html>

Crea app.js nello stesso folder:

console.log('App.js caricato con defer');
const el = document.getElementById('titolo');
el.textContent = 'Messaggio stampato sulla pagina da app.js';
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
console.log('Hai cliccato il bottone!');
alert('Ciao! Hai cliccato il bottone.');
});

Apri index.html nel browser. Risultati:

  • Console: App.js caricato con defer

  • Pagina: titolo aggiornato

  • Clic sul bottone: log in console + alert

4.3 Esempio con DOMContentLoaded (quando non usi defer)

index-no-defer.html

<!doctype html>
<html>
<head><meta charset="utf-8"/><title>No Defer</title></head>
<body>
<h1 id="titolo">Titolo orig</h1>
<script>
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM pronto (DOMContentLoaded)');
document.getElementById('titolo').textContent = 'Aggiornato dopo DOMContentLoaded';
});
</script>
</body>
</html>

Questo assicura che il DOM sia pronto prima di accedere agli elementi.

5 — Spiegazioni pratiche veloci (concetti essenziali)

Variabili

var a = 1; // vecchio, evita per nuovi progetti
let b = 2; // variabile mutabile (scope di blocco)
const c = 3; // costante (non riassegnabile)

Tipi comuni

  • number, string, boolean, null, undefined, object, array (Array), function.

Funzioni

function saluta(name) {
return `Ciao ${name}!`;
}
const saluta2 = (name) => `Ciao ${name}!`; // arrow function

Manipolazione semplice del DOM

const p = document.createElement('p');
p.textContent = 'Paragrafo aggiunto dinamicamente';
document.body.appendChild(p);

Debugging veloce

  • Se nulla accade: apri Console → vedi errori (red).

  • Tipico errore: document.getElementById(...) is null → script eseguito prima che l’elemento esista → usa defer o DOMContentLoaded.

  • Errori di sintassi (typos): la console indicherà riga e file.

6 — Best practices minime (per partire bene)

  • Metti il codice JS in file separati (.js) e usa defer o module quando appropriato.

  • Preferisci let e const a var.

  • Evita document.write() (non adatto a pagine moderne).

  • Usa console.* per debug; rimuovi i log inutili in produzione o usa livelli di log.

  • Organizza codice in funzioni piccole e nominative.

  • Se lavori con moduli, type="module" abilita import/export e script sono in strict mode di default.

7 — Esercizi pratici con soluzioni (da svolgere in laboratorio)

Esercizio 1 — Console + Page (base)

Obiettivo: stampare “Benvenuto, [tuo nome]” in console e inserire lo stesso messaggio in un elemento <div id="welcome">...</div>.

Istruzioni:

  1. Crea welcome.html con <div id="welcome"></div> e importa welcome.js con defer.

  2. In welcome.js, definisci const name = 'TuoNome' e stampa console.log.

  3. Imposta document.getElementById('welcome').textContent = ....

Soluzione (welcome.js):

const name = 'Marco';
const msg = `Benvenuto, ${name}!`;
console.log(msg);
document.getElementById('welcome').textContent = msg;

Esercizio 2 — Interattività (intermedio)

Obiettivo: costruire una piccola app che chiede il nome via prompt, mostra il saluto nella pagina e aggiunge in console la lunghezza del nome.

Soluzione rapida:

const name = prompt('Come ti chiami?') || 'amico';
const el = document.getElementById('greeting');
el.textContent = `Ciao ${name}, piacere!`;
console.log('Lunghezza nome:', name.length);

Esercizio 3 — Bottone e listener (avanzato)

Obiettivo: crea un bottone che al click cambia il colore di sfondo della pagina e registra l’evento con console.table (timestamp, colore).

Soluzione rapida:

const btn = document.getElementById('colorBtn');
btn.addEventListener('click', () => {
const color = '#' + Math.floor(Math.random()*16777215).toString(16);
document.body.style.backgroundColor = color;
console.table([{time: new Date().toISOString(), color}]);
});

8 — Test di autovalutazione (con risposte)

  1. Come stampi un messaggio nella console del browser?
    Risposta: console.log('test');

  2. Quale attributo aggiungi al tag <script> per essere sicuro che il DOM sia caricato prima dell'esecuzione?
    Risposta: defer (oppure usare DOMContentLoaded).

  3. Come cambio il contenuto testuale di un elemento con id titolo?
    Risposta: document.getElementById('titolo').textContent = 'Nuovo testo';

  4. Perché è meglio mettere il codice JS in file esterni?
    Risposta: migliore manutenibilità, caching del browser, separazione contenuto/logica (best practice).

  5. Come apri gli strumenti di sviluppo in Chrome?
    Risposta: Ctrl+Shift+I o F12 (Windows), Cmd+Opt+I (Mac).

9 — Errori comuni e come risolverli 

  • Uncaught TypeError: Cannot read property 'textContent' of null → elemento non trovato: controlla id, ordina script con defer o usa DOMContentLoaded.

  • ReferenceError: x is not defined → variabile non dichiarata o errore di scope; controlla nomi.

  • Nessun messaggio in console → verifica che il file .js sia collegato correttamente (path relativo) e apri DevTools → Network per vedere se file caricato.

  • SyntaxError (riga X) → errore di sintassi (virgole, parentesi, template string backticks).

10 — Piccola checklist "prima di eseguire"

  • index.html e app.js nello stesso folder (o path corretti).

  • <script src="app.js" defer></script> presente.

  • Apri la pagina con un browser moderno (Chrome/Firefox).

  • Apri DevTools → Console per vedere messaggi ed errori.

  • Se non funziona, controlla Network → 404 sul file .js → path sbagliato.

venerdì 20 marzo 2026

Corso di CSS & Web Design: 10/10 – Codice completo di un sito internet

10 – Codice completo di un sito internet 

Ecco un file unico HTML + CSS + (poco) JavaScript pronto da copiare nell’editor e pubblicare. È un sito single-page per un artista di arti figurative: responsive, accessibile, con galleria a griglia, filtro per categorie, lightbox per visualizzare le opere, menu mobile e form contatti (mailto fallback). Le immagini sono segnaposto — sostituisci i percorsi in <img src="img/..." con i tuoi file.

<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Nome Artista — Arti Figurative</title>
<meta name="description" content="Sito ufficiale dell'artista Nome Artista. Biografia, galleria opere, mostre ed eventi, contatti." />

<!-- Font (sistema) e reset minimale -->
<style>
  :root{
    --bg:#faf9f7;
    --card:#ffffff;
    --muted:#6b6b6b;
    --accent:#b85b3b; /* cambiare secondo tavolozza artista */
    --accent-2:#2b2b2b;
    --maxw:1100px;
    --radius:12px;
    --gap:1.2rem;
    --shadow: 0 6px 20px rgba(10,10,10,0.08);
  }
  *{box-sizing:border-box}
  html,body{height:100%}
  body{
    margin:0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial;
    background:linear-gradient(180deg,var(--bg),#f6f5f3);
    color:var(--accent-2);
    line-height:1.45;
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
  }
  a{color:var(--accent); text-decoration:none}
  .container{max-width:var(--maxw); margin:0 auto; padding:2rem;}
  header.site-header{
    background:transparent;
    position:sticky;
    top:0;
    z-index:50;
    backdrop-filter: blur(6px);
    padding:1rem 0;
  }
  .nav-inner{display:flex;align-items:center;gap:1rem;justify-content:space-between;}
  .brand{display:flex;align-items:center;gap:.75rem}
  .brand .logo{
    width:56px;height:56px;border-radius:12px;display:inline-grid;place-items:center;
    background:linear-gradient(135deg,var(--accent),#f3b08a);color:white;font-weight:700;font-size:1.05rem;
    box-shadow:var(--shadow);
  }
  .brand .title{font-weight:700;font-size:1rem}
  nav.main-nav{display:flex;gap:1rem;align-items:center}
  nav.main-nav a{padding:.5rem .6rem;border-radius:8px;color:var(--accent-2);font-weight:600}
  nav.main-nav a:hover{background:rgba(0,0,0,0.04)}
  .btn-primary{
    background:var(--accent); color:white; padding:.5rem .8rem;border-radius:10px;font-weight:700;
    box-shadow:0 6px 18px rgba(184,91,59,0.18);
  }

  /* Hero */
  .hero{
    margin-top:1rem;
    display:grid;
    grid-template-columns: 1fr 420px;
    gap:var(--gap);
    align-items:center;
  }
  .hero .lead{
    background:linear-gradient(180deg, rgba(255,255,255,0.9), rgba(255,255,255,0.8));
    padding:2rem;border-radius:var(--radius);box-shadow:var(--shadow);
  }
  .hero h1{margin:0 0 .5rem;font-size:2rem}
  .hero p{margin:0 0 1rem;color:var(--muted)}

  .hero-visual{
    border-radius:var(--radius); overflow:hidden; box-shadow:var(--shadow);
    background:#111; min-height:320px; display:grid; place-items:center;
  }
  .hero-visual img{width:100%;height:100%;object-fit:cover;display:block}

  /* Sections */
  section{margin:2.2rem 0}
  h2.section-title{font-size:1.25rem;margin:0 0 .6rem}
  .lead-small{color:var(--muted);margin-bottom:1rem}

  /* Gallery grid */
  .filters{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}
  .filters button{
    background:transparent;border:1px solid rgba(0,0,0,0.06);padding:.45rem .7rem;border-radius:999px;font-weight:600;
  }
  .filters button.active{background:var(--accent);color:white;border-color:transparent}

  .gallery-grid{
    display:grid;
    grid-template-columns: repeat(3, 1fr);
    gap: .9rem;
  }
  .card{
    background:var(--card);border-radius:10px;overflow:hidden;position:relative;box-shadow:var(--shadow);
  }
  .card img{width:100%;height:260px;object-fit:cover;display:block;transition:transform .32s ease}
  .card:hover img{transform:scale(1.03)}
  .card .meta{padding:.7rem .9rem}
  .meta h3{margin:0;font-size:1rem}
  .meta p{margin:.35rem 0 0;color:var(--muted);font-size:.9rem}

  /* Lightbox modal */
  .modal{
    position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,0.65);
    z-index:1000;padding:2rem;
  }
  .modal.open{display:flex}
  .modal .sheet{background:linear-gradient(180deg,#fff,#fafafa);max-width:1100px;border-radius:12px;overflow:hidden;display:grid;grid-template-columns:1fr 350px;gap:1rem}
  .modal img{width:100%;height:100%;object-fit:contain;display:block;background:#111}
  .modal .info{padding:1.2rem}
  .modal .info h3{margin:0 0 .4rem}
  .modal .close{position:absolute;top:1rem;right:1rem;background:transparent;border:0;color:white;font-size:1.6rem}

  /* Events list */
  .events-list{display:grid;gap:.8rem}
  .event{display:flex;gap:1rem;align-items:flex-start;background:var(--card);padding:.8rem;border-radius:10px;box-shadow:var(--shadow)}
  .event .date{min-width:96px;color:var(--accent);font-weight:700}

  /* Contact */
  form.contact-form{display:grid;gap:.6rem;max-width:700px}
  label{font-size:.9rem;color:var(--muted)}
  input[type="text"], input[type="email"], textarea{
    padding:.6rem .7rem;border-radius:8px;border:1px solid rgba(0,0,0,0.08);
    font-size:1rem;background:white;
  }
  textarea{min-height:140px;resize:vertical}
  .form-actions{display:flex;gap:.6rem;align-items:center}

  footer.site-footer{margin-top:2rem;padding:2rem 0;background:transparent;border-top:1px solid rgba(0,0,0,0.04)}
  footer .foot-inner{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;color:var(--muted)}

  /* Responsive */
  @media (max-width:980px){
    .hero{grid-template-columns:1fr; }
    .gallery-grid{grid-template-columns:repeat(2,1fr)}
    .modal .sheet{grid-template-columns:1fr}
  }
  @media (max-width:620px){
    nav.main-nav{display:none}
    .menu-toggle{display:inline-block}
    .gallery-grid{grid-template-columns:1fr}
    header .nav-inner{gap:.5rem}
  }

  /* Mobile menu overlay */
  .mobile-nav{
    position:fixed;inset:0;display:none;z-index:80;background:rgba(0,0,0,0.4);
    align-items:flex-start;padding-top:6rem;
  }
  .mobile-nav.open{display:flex}
  .mobile-nav .panel{background:var(--card);width:100%;padding:1.2rem;border-radius:12px 12px 0 0}
  .mobile-nav a{display:block;padding:.8rem 0;border-bottom:1px solid rgba(0,0,0,0.04)}
</style>
</head>
<body>

<header class="site-header">
  <div class="container nav-inner">
    <div class="brand">
      <div class="logo" aria-hidden="true">NA</div>
      <div>
        <div class="title">Nome Artista</div>
        <div style="font-size:.85rem;color:var(--muted)">Arti figurative — pittura & scultura</div>
      </div>
    </div>

    <nav class="main-nav" role="navigation" aria-label="Menu principale">
      <a href="#home">Home</a>
      <a href="#bio">Biografia</a>
      <a href="#gallery">Opere</a>
      <a href="#events">Mostre</a>
      <a href="#contact">Contatti</a>
      <a class="btn-primary" href="#gallery">Visita la galleria</a>
    </nav>

    <button class="menu-toggle" aria-label="Apri menu" style="display:none" onclick="toggleMobile()">
      ☰
    </button>
  </div>
</header>

<!-- Mobile nav -->
<div id="mobileNav" class="mobile-nav" role="dialog" aria-modal="true" aria-hidden="true">
  <div class="panel container" role="navigation">
    <a href="#home" onclick="toggleMobile()">Home</a>
    <a href="#bio" onclick="toggleMobile()">Biografia</a>
    <a href="#gallery" onclick="toggleMobile()">Opere</a>
    <a href="#events" onclick="toggleMobile()">Mostre</a>
    <a href="#contact" onclick="toggleMobile()">Contatti</a>
  </div>
</div>

<main id="home" class="container">
  <!-- HERO -->
  <div class="hero" aria-labelledby="heroTitle">
    <div class="lead">
      <h1 id="heroTitle">Nome Artista</h1>
      <p class="lead-small">Opere recenti — sperimentazione tra colore, matericità e spazio. Studio a [Città]. Disponibile per esposizioni e commissioni.</p>
      <p style="margin-top:1rem"><a class="btn-primary" href="#gallery">Visita la Galleria</a> <a style="margin-left:1rem" href="#contact">Contattami</a></p>
      <hr style="margin:1.2rem 0; border:none; border-top:1px solid rgba(0,0,0,0.04)" />
      <h2 style="font-size:1rem;margin:0 0 .6rem">Ultima mostra</h2>
      <p style="color:var(--muted)">"Materia sospesa" — Galleria XYZ, 2025. Una serie di dipinti che interrogano la superficie come luogo di memoria e traccia.</p>
    </div>

    <div class="hero-visual" aria-hidden="true">
      <!-- sostituire con immagine reale -->
      <img src="img/hero-placeholder.jpg" alt="Opera in evidenza di Nome Artista" />
    </div>
  </div>

  <!-- BIOGRAFIA -->
  <section id="bio" aria-labelledby="bioTitle">
    <h2 class="section-title" id="bioTitle">Biografia & Statement</h2>
    <div style="display:grid;grid-template-columns:220px 1fr;gap:1rem;align-items:start">
      <img src="img/ritratto.jpg" alt="Ritratto dell'artista" style="width:220px;border-radius:10px;object-fit:cover" />
      <div>
        <p class="lead-small">Nome Artista (Città, 19XX) vive e lavora tra [Città]. La pratica artistica esplora la relazione tra materia e memoria attraverso pittura e installazione.</p>
        <p>Il lavoro nasce dall'attenzione al gesto e alla stratificazione. L'artista utilizza pigmenti naturali, materiali riciclati e tecniche miste per creare superfici che ricordano paesaggi interiori. Tra le mostre personali e collettive: Galleria A (2023), Festival B (2022), Museo C (2021).</p>

        <h3 style="margin-top:.8rem">Statement</h3>
        <p style="color:var(--muted)">"Cerco un equilibrio tra controllo e accidente: le superfici raccolgono tracce di processi, segni di tempo e presenza umana." — Nome Artista</p>
      </div>
    </div>
  </section>

  <!-- GALLERY -->
  <section id="gallery" aria-labelledby="galleryTitle">
    <h2 class="section-title" id="galleryTitle">Galleria Opere</h2>
    <p class="lead-small">Clicca su un'immagine per ingrandirla e leggere i dettagli. Usa i filtri per navigare per categorie.</p>

    <div class="filters" role="tablist" aria-label="Filtri galleria">
      <button class="filter-btn active" data-filter="all" aria-pressed="true">Tutte</button>
      <button class="filter-btn" data-filter="pittura">Pittura</button>
      <button class="filter-btn" data-filter="scultura">Scultura</button>
      <button class="filter-btn" data-filter="installazione">Installazione</button>
    </div>

    <div class="gallery-grid" id="grid">
      <!-- card (duplicare / sostituire immagini e dati reali) -->
      <article class="card" data-category="pittura">
        <a href="#!" class="open" data-src="img/opera1.jpg" data-title="Senza Titolo (2024)" data-desc="Olio su tela — 80x100 cm">
          <img src="img/opera1-thumb.jpg" alt="Senza Titolo, olio su tela" />
        </a>
        <div class="meta">
          <h3>Senza Titolo</h3>
          <p>Olio su tela — 2024</p>
        </div>
      </article>

      <article class="card" data-category="pittura">
        <a href="#!" class="open" data-src="img/opera2.jpg" data-title="Linea e Polvere (2023)" data-desc="Tecnica mista — 60x80 cm">
          <img src="img/opera2-thumb.jpg" alt="Linea e Polvere, tecnica mista" />
        </a>
        <div class="meta"><h3>Linea e Polvere</h3><p>Tecnica mista — 2023</p></div>
      </article>

      <article class="card" data-category="scultura">
        <a href="#!" class="open" data-src="img/scultura1.jpg" data-title="Corpo di Guardia (2022)" data-desc="Ferro e cera — 120x40x40 cm">
          <img src="img/scultura1-thumb.jpg" alt="Corpo di Guardia, scultura" />
        </a>
        <div class="meta"><h3>Corpo di Guardia</h3><p>Ferro e cera — 2022</p></div>
      </article>

      <article class="card" data-category="installazione">
        <a href="#!" class="open" data-src="img/install1.jpg" data-title="Campo (2019)" data-desc="Installazione site-specific">
          <img src="img/install1-thumb.jpg" alt="Installazione Campo" />
        </a>
        <div class="meta"><h3>Campo</h3><p>Installazione — 2019</p></div>
      </article>

      <article class="card" data-category="pittura">
        <a href="#!" class="open" data-src="img/opera3.jpg" data-title="Segno sopito (2020)" data-desc="Acrilico su tela — 70x90 cm">
          <img src="img/opera3-thumb.jpg" alt="Segno sopito, acrilico" />
        </a>
        <div class="meta"><h3>Segno sopito</h3><p>Acrilico — 2020</p></div>
      </article>

      <article class="card" data-category="scultura">
        <a href="#!" class="open" data-src="img/scultura2.jpg" data-title="Bastione (2021)" data-desc="Legno, pigmento">
          <img src="img/scultura2-thumb.jpg" alt="Bastione, scultura legno" />
        </a>
        <div class="meta"><h3>Bastione</h3><p>Legno & pigmento — 2021</p></div>
      </article>
    </div>
  </section>

  <!-- Lightbox modal -->
  <div id="modal" class="modal" role="dialog" aria-hidden="true" aria-labelledby="modalTitle">
    <div class="sheet" role="document">
      <img id="modalImg" src="" alt="" />
      <div class="info">
        <h3 id="modalTitle">Titolo opera</h3>
        <p id="modalDesc" style="color:var(--muted);margin-top:.4rem"></p>
        <p style="margin-top:1rem"><strong>Tecnica:</strong> <span id="modalTech"></span></p>
        <p style="margin-top:1rem"><em>Contattami per disponibilità e dimensioni originali.</em></p>
        <p style="margin-top:1rem"><a id="downloadBtn" href="#" target="_blank">Scarica immagine</a></p>
      </div>
      <button class="close" aria-label="Chiudi" onclick="closeModal()">✕</button>
    </div>
  </div>

  <!-- EVENTS -->
  <section id="events" aria-labelledby="eventsTitle">
    <h2 class="section-title" id="eventsTitle">Mostre ed Eventi</h2>
    <div class="events-list">
      <article class="event">
        <div class="date">Set 2025</div>
        <div>
          <strong>"Materia sospesa"</strong> — Galleria XYZ, Città. Catalogo e apertura al pubblico dal 12 settembre.
        </div>
      </article>

      <article class="event">
        <div class="date">Mar 2024</div>
        <div>
          <strong>Residenza artistica</strong> — Centro Arte Locale. Progetto di sperimentazione con materiali naturali.
        </div>
      </article>
    </div>
  </section>

  <!-- CONTACT -->
  <section id="contact" aria-labelledby="contactTitle">
    <h2 class="section-title" id="contactTitle">Contatti</h2>
    <p class="lead-small">Per richieste di esposizione, vendita o commissioni puoi compilare il form oppure scrivere a <a href="mailto:artista@esempio.com">artista@esempio.com</a></p>

    <form class="contact-form" id="contactForm" onsubmit="submitForm(event)" novalidate>
      <label for="name">Nome</label>
      <input id="name" name="name" type="text" required />

      <label for="email">Email</label>
      <input id="email" name="email" type="email" required />

      <label for="message">Messaggio</label>
      <textarea id="message" name="message" required></textarea>

      <div class="form-actions">
        <button type="submit" class="btn-primary">Invia messaggio</button>
        <small style="color:var(--muted)">Oppure scrivi a <a href="mailto:artista@esempio.com">artista@esempio.com</a></small>
      </div>
    </form>
  </section>

  <footer class="site-footer">
    <div class="foot-inner">
      <div>© <strong>Nome Artista</strong> — Tutti i diritti riservati</div>
      <div style="display:flex;gap:.6rem;align-items:center">
        <a href="#" aria-label="Instagram">IG</a>
        <a href="#" aria-label="Facebook">FB</a>
        <a href="#" aria-label="LinkedIn">LN</a>
      </div>
    </div>
  </footer>
</main>

<!-- JavaScript minimo: menu mobile, filtri, lightbox, form -->
<script>
  // Mobile menu toggling
  const mobileNav = document.getElementById('mobileNav');
  function toggleMobile(){
    const isOpen = mobileNav.classList.toggle('open');
    mobileNav.setAttribute('aria-hidden', !isOpen);
    document.body.style.overflow = isOpen ? 'hidden' : '';
  }

  // Gallery filtering
  const filterBtns = Array.from(document.querySelectorAll('.filter-btn'));
  const cards = Array.from(document.querySelectorAll('.gallery-grid .card'));
  filterBtns.forEach(btn=>{
    btn.addEventListener('click', ()=> {
      filterBtns.forEach(b=> { b.classList.remove('active'); b.setAttribute('aria-pressed','false')});
      btn.classList.add('active'); btn.setAttribute('aria-pressed','true');
      const f = btn.dataset.filter;
      cards.forEach(c=>{
        if(f==='all'){ c.style.display='block'; }
        else { c.style.display = (c.dataset.category===f) ? 'block' : 'none'; }
      });
    });
  });

  // Lightbox (modal)
  const modal = document.getElementById('modal');
  const modalImg = document.getElementById('modalImg');
  const modalTitle = document.getElementById('modalTitle');
  const modalDesc = document.getElementById('modalDesc');
  const downloadBtn = document.getElementById('downloadBtn');
  const openLinks = Array.from(document.querySelectorAll('.card .open'));
  openLinks.forEach(link=>{
    link.addEventListener('click', (e)=>{
      e.preventDefault();
      const src = link.dataset.src || link.querySelector('img').src;
      const title = link.dataset.title || link.querySelector('.meta h3')?.innerText || 'Opera';
      const desc = link.dataset.desc || link.querySelector('.meta p')?.innerText || '';
      openModal(src,title,desc);
    });
  });
  function openModal(src,title,desc){
    modalImg.src = src;
    modalImg.alt = title;
    modalTitle.textContent = title;
    modalDesc.textContent = desc;
    downloadBtn.href = src;
    modal.classList.add('open');
    modal.setAttribute('aria-hidden','false');
    document.body.style.overflow='hidden';
  }
  function closeModal(){
    modal.classList.remove('open');
    modal.setAttribute('aria-hidden','true');
    modalImg.src = '';
    document.body.style.overflow='';
  }
  modal.addEventListener('click', (e)=>{ if(e.target===modal) closeModal(); });

  // Basic contact form handler (mailto fallback) - demo only
  function submitForm(e){
    e.preventDefault();
    const name = document.getElementById('name').value.trim();
    const email = document.getElementById('email').value.trim();
    const message = document.getElementById('message').value.trim();
    if(!name || !email || !message){
      alert('Compila tutti i campi prima di inviare.');
      return;
    }
    // mailto fallback
    const subject = encodeURIComponent('Richiesta da sito — ' + name);
    const body = encodeURIComponent('Da: ' + name + ' ('+email+')\n\n' + message);
    window.location.href = 'mailto:artista@esempio.com?subject='+subject+'&body='+body;
  }

  // Accessibility helper: focus first link in modal when opened (optional)
  modal.addEventListener('transitionend', ()=> {
    if(modal.classList.contains('open')) modal.querySelector('.sheet').focus();
  });
</script>

</body>
</html>

Note d’uso e personalizzazione

  • Immagini: sostituisci tutti i file img/... con le tue immagini reali (miniature e versioni grandi per il lightbox). Mantieni dimensioni ottimali per web (es. 1200px lato lungo per immagini principali).

  • Colori & tipografia: varia le variabili CSS --accent, --bg, ecc. per adattarle all’identità artistica.

  • Accessibilità: il markup include alt, ruoli ARIA e focus basics; puoi estenderlo aggiungendo keyboard trapping nella modal per migliori standard.

  • Form: il form usa mailto: come fallback; per ricevere i messaggi davvero, integra un endpoint server (es. formspree, Netlify forms o tuo backend).

  • SEO / performance: aggiungi meta tags social (Open Graph), minifica CSS/JS in produzione e usa immagini ottimizzate (WebP).


giovedì 19 marzo 2026

Corso di CSS & Web Design: 9 – Progetto completo di un sito internet

9 – Progetto completo di un sito internet 

Struttura dettagliata del sito di un artista di arti figurative

🎯 Obiettivi del sito

  1. Presentare in maniera professionale l’artista (biografia, statement, contatti).

  2. Offrire una galleria di opere ordinata e facilmente navigabile.

  3. Creare uno spazio per eventi, mostre e news.

  4. Consentire il contatto diretto (form email o social).

  5. Esprimere coerenza estetica con lo stile dell’artista tramite un uso mirato di CSS (colori, tipografia, layout responsivo).

🗂 Architettura delle pagine

1. Homepage

  • Obiettivo: dare un impatto immediato, con immagine o slider di un’opera significativa.

  • Elementi:

    • Logo o firma dell’artista.

    • Menu di navigazione chiaro (Home, Biografia, Opere, Mostre, Contatti).

    • Testo breve introduttivo (es. "Arte che unisce forma e materia...").

    • Richiamo immediato a una sezione in evidenza (es. ultima mostra o opera del mese).

2. Biografia / Statement

  • Obiettivo: raccontare il percorso dell’artista e la sua filosofia.

  • Elementi:

    • Ritratto fotografico dell’artista.

    • Testo lungo con biografia narrativa.

    • Citazioni o statement sull’arte personale.

    • Eventuale timeline interattiva con tappe principali.

3. Galleria delle Opere

  • Obiettivo: mostrare le opere in modo ordinato e immersivo.

  • Struttura CSS da evidenziare:

    • Layout a griglia grid/flexbox.

    • Filtri (categorie: pittura, scultura, installazioni).

    • Hover effects: effetto zoom o overlay con titolo/opera.

  • Elementi:

    • Miniature cliccabili → lightbox con immagine grande + dettagli (titolo, tecnica, anno, dimensioni).

4. Mostre ed Eventi

  • Obiettivo: informare il pubblico su mostre passate, presenti e future.

  • Elementi:

    • Lista cronologica di eventi.

    • Schede con immagine locandina, data, luogo, breve descrizione.

    • Sezione "Eventi passati" con archivio consultabile.

5. Contatti

  • Obiettivo: facilitare la comunicazione con pubblico e gallerie.

  • Elementi:

    • Form contatti (nome, email, messaggio).

    • Link ai social network.

    • Eventuale indirizzo email diretto.

    • Mappa interattiva (se l’artista ha uno studio aperto al pubblico).

6. Footer (comune a tutte le pagine)

  • Elementi:

    • Copyright e nome artista.

    • Link rapidi al menu.

    • Icone social stilizzate.

    • Eventuale newsletter.

🎨 Scelte stilistiche CSS

  1. Palette colori

    • Ispirata alle opere dell’artista: colori neutri (sfondo bianco o nero) con accenti cromatici derivati dalle tele/sculture.

  2. Tipografia

    • Font serif elegante per i testi (narrazione biografia).

    • Font sans-serif moderno per i titoli e menu.

    • Uso del contrasto per leggibilità.

  3. Layout

    • Responsive design con media queries (mobile-first).

    • Griglie flessibili con CSS Grid per gallerie.

    • Spaziature ampie per valorizzare le opere.

  4. Animazioni ed effetti

    • Transizioni morbide al passaggio del mouse.

    • Fade-in per immagini della galleria.

    • Header con effetto sticky al scroll.

📑 Struttura file del sito

  • index.html → Homepage

  • biografia.html → Pagina biografia

  • galleria.html → Opere

  • mostre.html → Mostre ed eventi

  • contatti.html → Contatti

  • style.css → Foglio di stile principale

  • script.js → Eventuali interazioni dinamiche (lightbox, menu mobile)

  • Cartelle:

    • /img → immagini delle opere e foto artista

    • /css → fogli di stile aggiuntivi

    • /js → script


mercoledì 18 marzo 2026

Corso di CSS & Web Design: 8 – Effetti dinamici e animazioni

 8 – Effetti dinamici e animazioni

1. Pseudo-classi CSS

Le pseudo-classi permettono di applicare stili a elementi in stati particolari o in base alla loro posizione nel DOM.

1.1 :hover

  • Applica stili quando il mouse passa sopra l’elemento.

button:hover {
  background-color: #4fa3f2;
  color: white;
}

1.2 :focus

  • Applicato quando un elemento riceve il focus, ad esempio un input.

input:focus {
  border-color: #4fa3f2;
  outline: none;
}

1.3 :nth-child()

  • Seleziona elementi in base alla loro posizione.

li:nth-child(odd) {
  background-color: #f2f2f2; /* elementi dispari */
}

li:nth-child(3) {
  color: red; /* terzo elemento */
}

2. Transizioni e trasformazioni

2.1 Transform

  • Permette di modificare la posizione, dimensione o inclinazione di un elemento.

.box:hover {
  transform: scale(1.1);       /* ingrandisce */
  transform: rotate(10deg);    /* ruota */
  transform: translateX(20px); /* sposta orizzontalmente */
}

2.2 Transition

  • Definisce l’animazione fluida tra due stati.

.box {
  transition: transform 0.3s ease, background-color 0.3s ease;
}
  • Significato:

    • 0.3s → durata della transizione

    • ease → tipo di accelerazione

    • Possibile: linear, ease-in, ease-out, ease-in-out

3. Animazioni con @keyframes

Permettono di creare movimenti complessi e ripetitivi.

3.1 Sintassi di base

@keyframes esempioAnimazione {
  0%   { transform: translateX(0); background-color: red; }
  50%  { transform: translateX(50px); background-color: yellow; }
  100% { transform: translateX(0); background-color: red; }
}

.elemento {
  animation: esempioAnimazione 2s infinite ease-in-out;
}
  • Proprietà principali:

    • animation-name

    • animation-duration

    • animation-iteration-count (numero di ripetizioni o infinite)

    • animation-timing-function (ease, linear, etc.)

    • animation-delay

4. Creazione di pulsanti interattivi

Esempio Pulsante Hover

button {
  padding: 12px 25px;
  font-size: 16px;
  background-color: #4fa3f2;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
}

button:hover {
  transform: scale(1.1);
  background-color: #357abd;
}
  • Risultato: pulsante che cresce e cambia colore al passaggio del mouse.

5. Esercizio svolto: animare un menu a comparsa

Obiettivo

Creare un menu laterale che compare e scompare con animazione fluida.

HTML

<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <title>Menu Animato</title>
  <link rel="stylesheet" href="stile.css">
</head>
<body>
  <button id="menu-btn">☰ Menu</button>
  <nav class="side-menu">
    <a href="#">Home</a>
    <a href="#">Servizi</a>
    <a href="#">Contatti</a>
  </nav>

  <script>
    const btn = document.getElementById('menu-btn');
    const menu = document.querySelector('.side-menu');
    btn.addEventListener('click', () => {
      menu.classList.toggle('active');
    });
  </script>
</body>
</html>

CSS (stile.css)

body {
  font-family: Arial, sans-serif;
  margin: 0;
}

/* Bottone menu */
#menu-btn {
  padding: 10px 15px;
  font-size: 18px;
  cursor: pointer;
}

/* Menu laterale */
.side-menu {
  position: fixed;
  top: 0;
  left: -250px; /* nascosto fuori schermo */
  width: 250px;
  height: 100%;
  background-color: #333;
  display: flex;
  flex-direction: column;
  padding-top: 50px;
  transition: left 0.3s ease;
}

.side-menu a {
  color: white;
  text-decoration: none;
  padding: 15px 20px;
  transition: background-color 0.3s;
}

.side-menu a:hover {
  background-color: #4fa3f2;
}

/* Menu attivo */
.side-menu.active {
  left: 0; /* compare */
}

Risultato

  • Bottone ☰ che attiva il menu laterale.

  • Menu scorre dentro e fuori con animazione fluida.

  • Link interattivi con effetto hover.



Corso di JavaScript & Programmazione Web: 4 – Funzioni

4 – Funzioni 1. Definizione e richiamo di funzioni Una funzione è un blocco di codice riutilizzabile che esegue un’operazione specifica....