Salta al contenuto
Note per Studenti HTML5 - struttura del documento, elementi semantici e form

HTML5 - struttura del documento, elementi semantici e form

In questa pagina 10

HTML (HyperText Markup Language) è il linguaggio con cui si scrive la struttura di una pagina web. La specifica ufficiale è l'HTML Living Standard del WHATWG, aggiornato di continuo (HTML5 è il nome storico della versione che ne ha fissato le basi nel 2014). Si legge insieme a Linguaggi di markup - SGML, HTML e XMLUn linguaggio di markup aggiunge al testo marcatori che ne descrivono la struttura. SGML (ISO 8879, 1986) è il metalinguaggio da cui derivano HTML fino alla 4.01 e XML 1.0 (W3C, 1998, un sottoinsieme semplificato); HTML5 ha un proprio algoritmo di parsing, tollerante, e non è né SGML né XML. Un documento XML è ben formato se rispetta la sintassi (un'unica radice, tag annidati e chiusi, attributi tra virgolette, nomi con maiuscole e minuscole distinte, entità per i caratteri speciali) ed è valido se in più rispetta uno schema. La DTD dichiara elementi (ELEMENT: EMPTY, ANY, #PCDATA, sequenza con la virgola, scelta con |, cardinalità ? * +) e attributi (ATTLIST: CDATA, ID, IDREF, enumerazioni; #REQUIRED, #IMPLIED, #FIXED); non ha tipi di dato e non conosce i namespace. XML Schema (XSD) è scritto in XML e ha tipi (xs:date, xs:positiveInteger), restrizioni con pattern, minOccurs e maxOccurs, key e keyref. I namespace (xmlns, xmlns:prefisso) identificano il vocabolario con un URI; gli attributi senza prefisso non appartengono a nessun namespace. XML è rigido e adatto a documenti e configurazioni (web.xml, pom.xml), HTML è tollerante e ha un vocabolario fisso; JSON è l'alternativa più compatta per scambiare dati e non ha attributi, schema standard o contenuto misto.Linguaggi di markup - SGML, HTML e XML → (da dove viene e come si confronta con XML) e prepara CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout → e JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →. Tutti gli esempi sono pezzi della pagina di prenotazione delle aule (Architettura delle applicazioni web - browser, server web e livelliUn'applicazione web è distribuita su più livelli (tier): presentazione (browser: HTML, CSS, JavaScript), logica applicativa (server web e application server) e dati (DBMS). Il client invia richieste HTTP, il server risponde; HTTP è senza stato, quindi lo stato dell'utente viaggia in cookie e sessioni. Il web server serve file statici, l'application server (container, per esempio Tomcat per le servlet Java) esegue codice che genera risposte dinamiche; spesso il web server fa da reverse proxy davanti all'application server. Il browser trasforma i byte della risposta in una pagina: decodifica, tokenizzazione e costruzione del DOM, CSS che diventa CSSOM, render tree, layout (reflow), paint e composizione; un script senza defer o async blocca il parsing, il CSS blocca il rendering. Origine = schema + host + porta; la same-origin policy limita ciò che uno script può leggere da altre origini. Web 1.0: pagine generate dal server, ogni azione ricarica la pagina; Web 2.0: AJAX, contenuti degli utenti, servizi REST; Web 3.0: dati con significato esplicito (RDF, linked data).Architettura delle applicazioni web - browser, server web e livelli →).

Struttura di un documento

html
<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Prenotazione aule - Dipartimento</title>
  <link rel="stylesheet" href="stile.css">
  <script src="app.js" defer></script>
</head>
<body>
  ...contenuto visibile...
</body>
</html>

Riga per riga:

Sintassi

  • Un elemento è tag di apertura, contenuto, tag di chiusura: <p>Testo</p>. Gli elementi vuoti (void) non hanno contenuto né chiusura: <br>, <hr>, <img>, <input>, <meta>, <link>. La barra finale (<br/>) è ammessa e ignorata.
  • Gli attributi stanno nel tag di apertura: nome="valore". Le virgolette sono facoltative se il valore è una parola senza spazi (type=text), ma conviene metterle sempre. Gli attributi booleani si scrivono senza valore: required, disabled, checked, hidden.
  • Nomi di tag e di attributi sono indifferenti alle maiuscole; si scrive in minuscolo.
  • Le entità servono per i caratteri riservati: &lt; &gt; &amp; &quot;, e &nbsp; (spazio non separabile). I commenti sono <!-- ... -->.
  • Gli spazi e i ritorni a capo multipli nel testo si riducono a uno nella visualizzazione.

Il parser corregge

A differenza di XML, un errore non ferma il parser: ne decide la correzione (WHATWG HTML, algoritmo di parsing). Esempi, verificati in un browser ricostruendo il DOM da una stringa:

sorgente DOM costruito
<table><tr><td>x</td></tr></table> aggiunge <tbody> fra table e tr
<p>uno<p>due due paragrafi: il secondo <p> chiude il primo
<p>testo<div>blocco</div> il <p> si chiude prima del <div> (un paragrafo non può contenere blocchi)
<ul><li>A<li>B</ul> ogni <li> chiude il precedente
<input required disabled> gli attributi booleani vengono riscritti required=""

Conseguenza: il DOM che JavaScript vede può differire dal sorgente (nel caso <tbody>, un selettore table > tr non troverà nulla). Per evitare sorprese si scrive HTML con tag chiusi e annidati correttamente; esistono validatori (per esempio quello del W3C) che confrontano la pagina con la specifica.

Testo e elementi di base

elemento uso
h1 ... h6 titoli, gerarchia: un h1 per pagina, poi h2, h3 senza saltare livelli
p paragrafo
ul, ol, li elenco puntato / numerato; dl, dt, dd elenco di definizioni
strong, em importanza forte / enfasi (significato); b, i solo aspetto
code, pre codice in riga / blocco che conserva spazi e a capo
blockquote, q citazione in blocco / in riga
br, hr a capo / interruzione tematica
span, div contenitori senza significato in riga / a blocco

Gli elementi si dividono (concetto di content model) in a blocco (iniziano su una riga nuova: p, div, ul, h1...) e in riga (inline: a, strong, span, img...). È una distinzione di default, che CSS può cambiare (CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →), mentre le regole su che cosa può contenere cosa (un p non contiene un div) restano.

Elementi semantici

Fino a HTML4 la struttura di una pagina si costruiva con <div id="header">, <div id="nav">: per il browser e per un lettore di schermo erano tutti uguali. HTML5 introduce elementi che dicono il ruolo del contenuto:

elemento ruolo
header introduzione della pagina o di una sezione (logo, titolo)
nav blocco di collegamenti di navigazione
main il contenuto principale; uno solo per pagina
section sezione tematica, di norma con un titolo
article contenuto autonomo che avrebbe senso da solo (un articolo, un commento)
aside contenuto collaterale (box laterale)
footer piè di pagina o di sezione
figure, figcaption figura con didascalia
time data o ora, con datetime leggibile dalle macchine

I vantaggi sono concreti: i lettori di schermo permettono di saltare a main o nav (si chiamano punti di riferimento, landmark), i motori di ricerca capiscono meglio la pagina e il CSS ha selettori significativi. Regola: usare div e span solo quando non c'è un elemento con il significato giusto.

html
<a href="/aiuto.html">Aiuto</a>                           <!-- relativo alla radice del sito -->
<a href="https://aule.example.org/api/aule">Elenco aule</a> <!-- assoluto -->
<a href="#nuova">Vai al modulo</a>                         <!-- frammento: l'elemento con id="nuova" -->
<a href="mailto:aule@example.org">Scrivici</a>
<a href="https://altro.example.org" target="_blank" rel="noopener">Altro sito</a>
<img src="aula-a1.jpg" alt="Aula A1 vista dal fondo" width="640" height="360">

Tabelle

Le tabelle servono per dati tabulari, non per impaginare (per quello c'è CSS). Le prenotazioni del 19 ottobre:

html
<table>
  <caption>Aule prenotate nel giorno scelto</caption>
  <thead>
    <tr><th scope="col">Aula</th><th scope="col">Dalle</th><th scope="col">Alle</th><th scope="col">Studente</th></tr>
  </thead>
  <tbody>
    <tr><th scope="row">Aula A1</th><td>09:00</td><td>11:00</td><td>Rossi</td></tr>
    <tr><th scope="row">Aula A1</th><td>14:00</td><td>16:00</td><td>Bianchi</td></tr>
  </tbody>
</table>
  • caption è il titolo della tabella; thead, tbody, tfoot raggruppano intestazione, corpo e piede; tr è una riga; th una cella di intestazione, td una cella di dati.
  • scope dice a che cosa si riferisce una th: col (la colonna sotto) o row (la riga a destra); i lettori di schermo leggono "Studente: Rossi" invece di una sequenza di valori.
  • colspan="2" e rowspan="2" fondono celle in orizzontale e in verticale. Una riga di totali che occupa tre colonne: <td colspan="3">Totale</td>.

Form

Un form raccoglie dati dall'utente e li invia al server. Il modulo di prenotazione:

html
<form action="/prenotazioni" method="post">
  <fieldset>
    <legend>Dati della prenotazione</legend>
    <p>
      <label for="aula_id">Aula</label>
      <select id="aula_id" name="aula_id" required>
        <option value="">Scegli...</option>
        <option value="1">Aula A1 (80 posti)</option>
        <option value="2">Aula B2 (45 posti)</option>
        <option value="3">Lab Info (30 posti)</option>
      </select>
    </p>
    <p>
      <label for="giorno">Giorno</label>
      <input type="date" id="giorno" name="giorno" required>
    </p>
    <p>
      <label for="ora_inizio">Dalle</label>
      <input type="time" id="ora_inizio" name="ora_inizio" required>
      <label for="ora_fine">alle</label>
      <input type="time" id="ora_fine" name="ora_fine" required>
    </p>
    <p>
      <label for="studente">Cognome</label>
      <input type="text" id="studente" name="studente" required minlength="2" maxlength="40">
    </p>
  </fieldset>
  <button type="submit">Prenota</button>
</form>
  • action è l'indirizzo a cui si invia (predefinito: la pagina stessa); method è get (predefinito) o post.
  • label for="x" collega l'etichetta al campo con id="x": cliccando sull'etichetta si seleziona il campo e il lettore di schermo la legge. Un campo senza label è inaccessibile; placeholder non la sostituisce.
  • name è il nome con cui il valore viaggia verso il server: un campo senza name non viene inviato. id serve per label, CSS e JavaScript. Qui i name sono i nomi delle colonne di prenotazione.
  • fieldset e legend raggruppano campi collegati.
  • Il pulsante <button type="submit"> invia; type="button" non fa nulla da solo (serve JavaScript); type="reset" ripristina i valori.

Tipi di input

type campo note
text (predefinito), search testo su una riga
email, url, tel testo con controllo di formato (email, url); tastiera adatta tel non controlla nulla
password testo nascosto
number numero min, max, step
date, time, datetime-local selettori nativi il valore inviato è AAAA-MM-GG, HH:MM: coincide con le colonne SQL DATE e TIME
checkbox casella inviato solo se spuntata (valore on se manca value)
radio scelta unica fra quelli con lo stesso name
hidden non visibile per passare un dato fisso
file upload richiede enctype="multipart/form-data"
submit, button, reset pulsanti

Altri controlli: <select> con <option> (il value è ciò che viaggia, il testo è ciò che si vede), <textarea> per testo su più righe, <button>. L'elemento <datalist> suggerisce valori a un input di testo.

GET e POST

method decide dove vanno i campi:

  • GET: nell'URI, dopo il ?, come nome=valore separati da & (query string). Il browser, inviando un form con giorno=2026-10-19, studente=Dall'Olio Anna e una casella solo_libere spuntata, richiede:
  GET /prenotazioni?giorno=2026-10-19&studente=Dall%27Olio+Anna&solo_libere=on HTTP/1.1

I valori sono codificati: spazio diventa +, l'apostrofo %27 (percent-encoding, Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →). GET è sicuro e idempotente: non deve modificare nulla (RFC 9110); la richiesta si può mettere nei segnalibri, condividere, mettere in cache; i dati restano visibili in cronologia e nei log, quindi mai password.

  • POST: nel corpo del messaggio. Il modulo di prenotazione compilato con "Dall'Olio & Rossi" invia (catturato da un server di prova):
  POST /prenotazioni HTTP/1.1
  Content-Type: application/x-www-form-urlencoded

  aula_id=1&giorno=2026-10-19&ora_inizio=09%3A00&ora_fine=11%3A00&studente=Dall%27Olio+%26+Rossi

Nell'URI non compare nulla; non è idempotente: ripetere la richiesta può creare una seconda prenotazione (per questo il browser chiede conferma prima di rinviare). Si usa per operazioni che modificano lo stato. Si noti %3A per i due punti e %26 per la & che fa parte del valore: senza codifica sarebbe stata un separatore.

Il formato del corpo dipende da enctype: application/x-www-form-urlencoded (predefinito), multipart/form-data (obbligatorio con i file: ogni campo è una parte separata da un boundary, come descritto in Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →, sezione sui moduli), text/plain (da non usare). Un form HTML invia solo GET e POST; PUT e DELETE richiedono JavaScript (Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →).

Validazione nativa

Il browser controlla i campi prima di inviare, se il form ha gli attributi giusti; in caso di errore blocca l'invio e mostra un messaggio sul primo campo errato.

attributo controlla
required campo non vuoto (per select, un valore diverso dall'option con value="")
type="email", url, number, date... formato del valore
minlength, maxlength lunghezza del testo
min, max, step intervallo e passo di numeri, date, ore
pattern="[A-Za-zÀ-ÿ' ]+" espressione regolare, che deve coincidere con tutto il valore; title spiega il formato nel messaggio

min="08:00" max="19:00" step="1800" su un type="time" accetta ore da 08:00 a 19:00 a passi di 30 minuti. Alcuni dettagli da conoscere:

Accessibilità di base

L'accessibilità (accessibility) è fare in modo che la pagina sia usabile da chi non vede, non usa il mouse o ha una vista debole. Con HTML ben scritto si ottiene gran parte del risultato:

  • lang su html; alt su ogni immagine; label su ogni campo; th scope e caption nelle tabelle;
  • gerarchia dei titoli ordinata (h1, h2, h3, senza scegliere il livello per la grandezza: quella è compito di CSS);
  • elementi nativi al posto di quelli imitati: un <button> è focalizzabile con Tab, si attiva con Invio e Spazio e il lettore di schermo lo annuncia come pulsante; un <div onclick> non fa nulla di questo;
  • testi dei link significativi: "Elenco aule", non "clicca qui";
  • tutto raggiungibile e utilizzabile da tastiera, con il focus visibile (non togliere il contorno senza sostituirlo);
  • contrasto sufficiente fra testo e sfondo; l'informazione non affidata solo al colore;
  • ARIA (attributi role, aria-label, aria-live...) solo quando non esiste un elemento nativo: la prima regola di ARIA è non usarla se HTML basta. Esempio utile: <p id="esito" role="status"> fa leggere al lettore di schermo il messaggio di conferma quando cambia; <nav aria-label="Principale"> distingue due nav.

Esempio completo

La pagina dell'applicazione, con header, nav, main a due section, footer, la tabella e il form sopra, è composta così:

html
<body>
  <header>
    <h1>Prenotazione delle aule</h1>
    <nav aria-label="Principale">
      <ul>
        <li><a href="#prenotazioni">Prenotazioni</a></li>
        <li><a href="#nuova">Prenota</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <section id="prenotazioni"> <h2>Prenotazioni del 19 ottobre 2026</h2> <!-- table --> </section>
    <section id="nuova">        <h2>Nuova prenotazione</h2>             <!-- form  --> </section>
  </main>
  <footer>
    <p>Dati di esempio. <a href="mailto:aule@example.org">Segnala un problema</a></p>
  </footer>
</body>

Il lato server che riceve il POST (la servlet PrenotazioniServlet) e la tabella costruita da JavaScript invece che scritta a mano sono nell'esercizio Esercizio - Tabella delle prenotazioni costruita con il DOM e filtrata (applicazione web).

Errori tipici

  • Dimenticare <!DOCTYPE html> o <meta charset>: lettere accentate rotte, modalità quirks.
  • Campo senza name: non viene inviato.
  • label senza for o for che non coincide con l'id.
  • method="get" per un'operazione che modifica dati, o per una password.
  • <img> senza alt; <div> al posto di <button>.
  • Annidamenti illegali (<p><div>): il parser corregge e il DOM cambia.
  • Usare le tabelle per l'impaginazione.
  • Fidarsi della validazione nativa come unico controllo.
  • Saltare livelli di titolo (da h1 a h4) per ottenere un aspetto.

Domande d'esame

  1. Differenza fra GET e POST nell'invio di un form. GET: campi nell'URI (query string), richiesta sicura e idempotente, messa in cache e nei segnalibri, dati visibili. POST: campi nel corpo, per modifiche di stato, non idempotente, Content-Type application/x-www-form-urlencoded o multipart/form-data. Esempio con il form di prenotazione.
  2. Perché usare header, nav, main, section invece di div? Hanno un significato che i lettori di schermo e i motori di ricerca capiscono (punti di riferimento), rendono il CSS più chiaro; div è neutro. main è unico.
  3. Scrivere un form per prenotare un'aula con validazione nativa. Campi aula_id (select, required), giorno (type="date"), ora_inizio e ora_fine (type="time", min, max), studente (required, minlength, pattern), tutti con label for e name uguale alla colonna; spiegare che il server deve rifare i controlli.

Versione ripasso

Documento. <!DOCTYPE html> (modalità standard), <html lang="it">, <head> con meta charset="UTF-8", meta viewport, title, link rel="stylesheet", script defer; <body>. Attributi booleani senza valore (required); nomi di tag indifferenti alle maiuscole; elementi vuoti br, img, input, meta. Il parser corregge invece di fallire: aggiunge tbody, chiude i p davanti ai blocchi.

Semantica. header, nav, main (uno), section, article, aside, footer, figure, time: danno ruoli e punti di riferimento; div e span sono neutri. Titoli h1-h6 in gerarchia. strong/em hanno significato, b/i solo aspetto.

Link e immagini. href assoluto, relativo, #frammento, mailto:; target="_blank" con rel="noopener". img con alt (vuoto se decorativa), width, height.

Tabelle. table, caption, thead/tbody, tr, th scope="col|row", td, colspan, rowspan. Solo per dati.

Form.

Validazione nativa. required, minlength, maxlength, min, max, step, pattern (su tutto il valore), type; novalidate la spegne; minlength conta solo dopo la modifica dell'utente. Comoda ma aggirabile: il server rifà i controlli (Organizzazione fisica dei dati e accesso programmatico alle basi di datiUn DBMS è formato da un gestore delle connessioni, un parser, un ottimizzatore che sceglie il piano di esecuzione usando le statistiche del catalogo, un esecutore, i metodi di accesso (heap, ordinato, hash, B-tree, indici), il buffer manager e il gestore delle transazioni (lock e log). Il costo si misura in accessi a blocchi del disco. L'ottimizzatore riscrive l'espressione algebrica (selezioni e proiezioni il prima possibile, prodotto con selezione = join, ordine dei join) e sceglie gli algoritmi: scansione o indice per le selezioni, nested loop, block nested loop, index nested loop, sort-merge o hash join per i join (con 1000 e 100 blocchi, 10 pagine di buffer: 11 mila accessi con block nested loop, 3300 con hash join). La progettazione fisica sceglie organizzazione dei file, indici ed eventuale denormalizzazione in base al carico. Le applicazioni accedono ai dati con SQL incorporato, interfacce a livello di chiamata (ODBC, JDBC, DB-API di Python), ORM o routine memorizzate: connessione, cursore, execute con parametri, fetch, commit o rollback. Mai concatenare l'input dell'utente nell'SQL (SQL injection): query parametrizzate. Un'applicazione web è a tre livelli: browser, server applicativo (HTTP senza stato, sessioni e cookie) e DBMS.Organizzazione fisica dei dati e accesso programmatico alle basi di dati →); estensione con setCustomValidity (JavaScript - linguaggio, DOM ed eventiJavaScript (standard ECMAScript, Ecma-262) è il linguaggio dei browser: tipizzato dinamicamente, con sette tipi primitivi (number, string, boolean, undefined, null, bigint, symbol) e gli oggetti (anche array e funzioni); typeof null vale "object" per un errore storico; == converte i tipi, === no (si usa sempre ===); valori falsy: false, 0, 0n, "", null, undefined, NaN. let e const hanno visibilità di blocco e una zona morta prima della dichiarazione, var visibilità di funzione e hoisting; const impedisce di riassegnare il nome, non di modificare l'oggetto. Funzioni: dichiarazione (hoisted), espressione, arrow function (this lessicale), parametri predefiniti, rest e spread, destructuring. Array: map, filter, reduce, find, some, every, sort (senza comparatore ordina come stringhe). Closure: una funzione ricorda le variabili dell'ambiente in cui è nata. Eventi: addEventListener; propagazione in tre fasi (cattura, target, bolla), stopPropagation, preventDefault, delegazione con event.target e closest. DOM: albero di nodi; querySelector, createElement, append, replaceChildren, textContent (sicuro) contro innerHTML (rischio di XSS), classList, dataset. Moduli ES (type="module", import e export) sono differiti e in modalità strict. Event loop: un solo thread, call stack, coda dei task (setTimeout, eventi) e coda dei microtask (promise, await) svuotata dopo ogni task: l'esecuzione asincrona (fetch, async e await, Promise.all) è alla base di AJAX e il codice lungo blocca la pagina.JavaScript - linguaggio, DOM ed eventi →).

Accessibilità. lang, alt, label, th scope, gerarchia dei titoli, elementi nativi (button, non div onclick), uso da tastiera con focus visibile, contrasto, testi dei link chiari, ARIA solo se serve (role="status", aria-label).

Errori tipici

  • Campo senza name, label senza for.
  • GET per modificare dati o per password.
  • img senza alt.
  • Annidamenti illegali.
  • Tabelle per l'impaginazione.
  • Validazione solo nel browser.

Contesto: Linguaggi di markup - SGML, HTML e XMLUn linguaggio di markup aggiunge al testo marcatori che ne descrivono la struttura. SGML (ISO 8879, 1986) è il metalinguaggio da cui derivano HTML fino alla 4.01 e XML 1.0 (W3C, 1998, un sottoinsieme semplificato); HTML5 ha un proprio algoritmo di parsing, tollerante, e non è né SGML né XML. Un documento XML è ben formato se rispetta la sintassi (un'unica radice, tag annidati e chiusi, attributi tra virgolette, nomi con maiuscole e minuscole distinte, entità per i caratteri speciali) ed è valido se in più rispetta uno schema. La DTD dichiara elementi (ELEMENT: EMPTY, ANY, #PCDATA, sequenza con la virgola, scelta con |, cardinalità ? * +) e attributi (ATTLIST: CDATA, ID, IDREF, enumerazioni; #REQUIRED, #IMPLIED, #FIXED); non ha tipi di dato e non conosce i namespace. XML Schema (XSD) è scritto in XML e ha tipi (xs:date, xs:positiveInteger), restrizioni con pattern, minOccurs e maxOccurs, key e keyref. I namespace (xmlns, xmlns:prefisso) identificano il vocabolario con un URI; gli attributi senza prefisso non appartengono a nessun namespace. XML è rigido e adatto a documenti e configurazioni (web.xml, pom.xml), HTML è tollerante e ha un vocabolario fisso; JSON è l'alternativa più compatta per scambiare dati e non ha attributi, schema standard o contenuto misto.Linguaggi di markup - SGML, HTML e XML →, CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →, Esercizio - Form HTML di prenotazione con validazione nativa e in JavaScript (applicazione web). Scheletro del documento.

html
<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Prenotazione aule - Dipartimento</title>
  <link rel="stylesheet" href="stile.css">
  <script src="app.js" defer></script>
</head>
<body> ...header, nav, main (section), footer... </body>
</html>

meta viewport serve al responsive sui telefoni; <!DOCTYPE html> evita la modalità quirks; meta charset va nei primi 1024 byte.

Come corregge il parser (provato in un browser):

sorgente DOM
<table><tr><td> aggiunge <tbody>
<p>uno<p>due due paragrafi
<p>testo<div> il p si chiude prima del div
<ul><li>A<li>B ogni li chiude il precedente

Tabella accessibile.

html
<table>
  <caption>Aule prenotate nel giorno scelto</caption>
  <thead><tr><th scope="col">Aula</th><th scope="col">Dalle</th><th scope="col">Alle</th><th scope="col">Studente</th></tr></thead>
  <tbody><tr><th scope="row">Aula A1</th><td>09:00</td><td>11:00</td><td>Rossi</td></tr></tbody>
</table>

Form di prenotazione.

html
<form action="/prenotazioni" method="post">
  <label for="giorno">Giorno</label>
  <input type="date" id="giorno" name="giorno" required>
  <label for="studente">Cognome</label>
  <input type="text" id="studente" name="studente" required minlength="2" maxlength="40" pattern="[A-Za-zÀ-ÿ' ]+">
  <button type="submit">Prenota</button>
</form>

Richieste prodotte.

GET /prenotazioni?giorno=2026-10-19&studente=Dall%27Olio+Anna HTTP/1.1

POST /prenotazioni HTTP/1.1
Content-Type: application/x-www-form-urlencoded

aula_id=1&giorno=2026-10-19&ora_inizio=09%3A00&ora_fine=11%3A00&studente=Dall%27Olio+%26+Rossi

Nel corpo di un POST una & che fa parte del valore diventa %26. multipart/form-data con i file. Con type="date" e type="time" i valori sono nei formati delle colonne SQL.

Domande d'esame, tracce.

  • GET contro POST: dove vanno i campi, sicuro e idempotente, segnalibri, dati visibili.
  • Perché gli elementi semantici invece di div: ruoli e punti di riferimento, main unico.
  • Form di prenotazione con validazione nativa; il server rifà i controlli.

Esercizi su questo argomento

Teoria collegata