HTML è obbligatorio per una pagina web, CSS è opzionale, ma ampiamente consigliato!


La differenza tra le due immagini è evidente.
Possiamo però capire subito che una pagina senza CSS funziona comunque al 100%, ma sarà semplicemente un insieme di blocchi uno sotto l’altro.
CSS è acronimo di Cascading Style Sheets (fogli di stile in cascata).
Nel 1996, il web era caotico: ogni browser (Netscape Navigator, Internet Explorer) aggiungeva tag proprietari per distinguersi dai competitor.
Il risultato? Un sito appariva diverso (o si rompeva completamente) a seconda del browser.
Il W3C intervenne con CSS per separare il contenuto (HTML) dalla presentazione (CSS).
Adesso:
Una regola CSS è composta da un selettore e un blocco di dichiarazioni.
h1): a quale elemento/i vogliamo applicare determinati stili.color: blue;): cosa cambiamo. Composta da proprietà e valore.;.I selettori indicano a quali elementi HTML si vogliono applicare determinate regole di stile.
Selettore di elemento: tutti gli elementi con un certo tag.
Selettore di classe: tutti gli elementi con una certa classe (attributo class).
Selettore di ID: un elemento specifico con un certo ID (attributo id).
Nota: generalmente usi le classi per raggruppare stili, e gli ID solo quando serve un elemento unico.
Abbiamo visto che senza CSS la pagina è un insieme di blocchi uno sotto l’altro. In particolare, i singoli elementi sono di fatto dei box rettangolari che occupano un certo spazio nello schermo.
Questo modello è detto box model. Ma quali proprietà hanno questi box?
Se si aprono nuovamente i DevTools su una pagina e ci si sposta sulla tab Elaborati, si vede una rappresentazione interessante.
Già da questa vista, si può notare che ci sono quattro componenti fondamentali:
displayOgni elemento ha un comportamento predefinito rispetto a come occupa lo spazio:
<h1>, <p>, <div> sono elementi blocco → occupano l’intera larghezza disponibile e vanno a capo.<a>, <span>, <em> sono elementi inline → si allineano orizzontalmente, accanto al testo.Con la proprietà display, possiamo modificare questo comportamento predefinito:
block: occupa intera larghezza, va a capo.
inline: accanto ad altri, larghezza del contenuto.
I primi due combinatori selezionano figli (children, elementi a un livello inferiore).
Seleziona qualsiasi elemento p dentro div.
Risultato: entrambi i paragrafi diventano rossi.
Utili per evitare di aggiungere classi ovunque!
Gli ultimi due combinatori selezionano fratelli (sibling, elementi allo stesso livello).
+)Seleziona il primo fratello che segue un elemento.
Risultato: solo il primo paragrafo è in grassetto.
Molto utili con JavaScript quando usi querySelector()!
Ci sono tre modi per includere CSS in una pagina HTML.
1. Inline:
2. Nel tag <style> nell’<head>:
3. File CSS esterno:
Quando scriviamo CSS, spesso più regole si applicano allo stesso elemento. Quale regola vince?
Le regole più basse nel file sovrascrivono quelle sopra.
È come sovrascrivere una variabile: l’ultimo valore è quello valido.
Alcune proprietà si ereditano dai genitori, altre no.
Si eredita (proprietà di testo/font):
Tutti i figli e nipoti hanno testo nero, a meno che non lo sovrascrivano.
Abbiamo visto i concetti fondamentali di CSS necessari per lavorare con JavaScript e il DOM.
CSS è un linguaggio ricco di proprietà, selettori avanzati (pseudo-classi, pseudo-elementi), e tecniche di layout. Non è compito di questo modulo coprirle tutte.
Quando ci servirà un selettore, una proprietà, o una tecnica che non abbiamo visto, possiamo affidarci a:
Consiglio
Riprendiamo il ricettario e diamogli l’aspetto di una card semplice e ordinata.
Possiamo usare questi valori:
Il DOM (“Document Object Model”) è l’interfaccia che permette a JavaScript di interagire con il codice HTML.
Element.<html>, con <head> e <body> come figli.<html>
├─ <head>
│ └─ <title>
└─ <body>
├─ <h1>
├─ <p>
└─ <div>
└─ <button>
In JavaScript, possiamo scorrere questo albero e modificare gli elementi.
Un oggetto è una collezione di dati in relazione tra loro e funzionalità correlate.
Quando sono dentro un oggetto, variabili e funzioni prendono nomi specifici:
Quasi tutto quello che utilizziamo in JavaScript è un oggetto!
Per creare un oggetto utilizziamo le parentesi graffe:
Andiamo ad inserire proprietà e metodi come coppie chiave-valore separate da virgola:
Nota: non usiamo = ma : per assegnare i valori, e separiamo i membri con , e non ;
Gli oggetti servono per descrivere dati complessi all’interno della nostra applicazione.
Supponiamo di dover creare una rubrica: avremo bisogno di gestire dei contatti.
Vantaggi:
Accediamo alle proprietà e ai metodi dell’oggetto usando la notazione a punto.
Il nome dell’oggetto (studente) funge da spazio dei nomi: deve essere inserito prima per accedere a qualsiasi cosa all’interno dell’oggetto.
Un oggetto può avere proprietà che sono a loro volta oggetti:
Una volta creato, possiamo modificare i valori delle proprietà:
Un array è una lista ordinata di elementi.
In JavaScript, gli array sono oggetti speciali che:
Gli array sono molto utili per gestire elenchi e sequenze di dati.
Ogni elemento ha un indice che parte da 0:
Possiamo sapere quanti elementi ci sono con la proprietà length:
Abbiamo visto che gli array usano le parentesi quadre con numeri per accedere agli elementi.
Allo stesso modo, possiamo accedere alle proprietà di un oggetto con le parentesi quadre e il nome della proprietà:
Sono equivalenti! Gli oggetti sono anche chiamati array associativi perché funzionano come array con chiavi di testo invece che di numeri.
Solitamente preferiamo la dot notation, ma la bracket notation permette cose altrimenti impossibili:
Usiamo bracket notation quando:
Quando una proprietà intermedia può non esistere, l’accesso diretto può generare errore.
Con optional chaining (?.) interrompiamo la lettura in modo sicuro: se un passaggio è null o undefined, l’espressione restituisce undefined.
Usiamo ?. quando leggiamo dati annidati da oggetti, API o DOM e non siamo sicuri che tutti i livelli esistano.
L’operatore nullish coalescing (??) ci aiuta a impostare un valore di default.
null o undefined0, '', falseSe il dato è “assente” (null/undefined), applichiamo il default. Negli altri casi, manteniamo il valore originale.
Optional chaining (?.) e nullish coalescing (??) sono costrutti relativamente recenti, introdotti in ES2020.
Prima di ??, si usava spesso l’operatore logico OR (||) per impostare fallback:
Perché || funziona da fallback?
a || b restituisce a se a è truthy, altrimenti passa a b|| i valori falsy (0, '', false) attivano il fallback?? invece attiva il fallback solo con null o undefinedGli elementi di un array possono essere di qualsiasi tipo, inclusi oggetti. Spesso combiniamo array di oggetti per rappresentare dati strutturati:
const ricette = [
{ nome: 'Carbonara', tempo: 20, difficolta: 'Media' },
{ nome: 'Amatriciana', tempo: 25, difficolta: 'Media' },
{ nome: 'Cacio e pepe', tempo: 15, difficolta: 'Facile' }
];
// Accesso agli elementi
console.log(ricette[0].nome); // 'Carbonara'
console.log(ricette[1].tempo); // 25
// Iterazione con for
for (let i = 0; i < ricette.length; i++) {
console.log(ricette[i].nome + ' - ' + ricette[i].tempo + ' min');
}Possiamo anche avere il contrario: oggetti che contengono array:
const ricetta = {
nome: 'Carbonara',
tempo: 20,
ingredienti: ['Pasta', 'Uova', 'Guanciale', 'Pecorino'],
passaggi: [
'Cuoci la pasta',
'Taglia il guanciale a cubetti',
'Mescola le uova con il pecorino',
'Combina tutto insieme'
]
};
// Accesso ai dati
console.log(ricetta.nome); // 'Carbonara'
console.log(ricetta.ingredienti[0]); // 'Pasta'
console.log(ricetta.passaggi.length); // 4
// Iterazione sugli ingredienti
for (let i = 0; i < ricetta.ingredienti.length; i++) {
console.log('- ' + ricetta.ingredienti[i]);
}Array.isArray()Gli array sono oggetti! typeof ritorna 'object' per entrambi:
Per distinguere un array da un oggetto, usa Array.isArray():
Quando usarlo
Utile quando ricevi dati da API o funzioni e vuoi verificare il tipo prima di usare metodi come map() o filter().
Sono presenti due costrutti “for each” per iterare dati in modo più leggibile: for...of e for...in.
for...offor...of itera i valori di un oggetto iterabile.
Tuttavia, all’atto pratico, for...in è generalmente sconsigliato per iterare oggetti, perché itera anche le proprietà ereditate dalla catena di prototipi (capiremo più avanti cosa significa).
Di conseguenza, per iterare le chiavi di un oggetto è preferibile usare Object.keys() o Object.entries() insieme a for...of.
documentL’oggetto globale document è il punto di accesso a tutto il DOM.
Element che possiamo manipolare.ElementOgni elemento HTML nel DOM è rappresentato come un oggetto Element con proprietà e metodi.
Proprietà comuni:
textContent - testo puro (sicuro)innerHTML - contenuto HTML completoclassName - valore attributo classid - valore attributo idtagName - nome del tag ('DIV', 'P')Metodi comuni:
querySelector() - cerca elemento figlioclassList.add/remove/toggle() - gestisce classigetAttribute() / setAttribute() - legge/modifica attributiOttenuto un elemento, possiamo navigare l’albero usando proprietà che collegano elementi tra loro:
const elemento = document.querySelector('.box');
// Accedere ai figli (SOLO elementi)
const figli = elemento.children; // HTMLCollection (solo elementi)
const primoElemento = elemento.firstElementChild; // Primo elemento figlio
const ultimoElemento = elemento.lastElementChild; // Ultimo elemento figlio
// Accedere ai figli (TUTTI i nodi, incluso testo)
const tuttiNodi = elemento.childNodes; // NodeList (elementi + testo)
const primoNodo = elemento.firstChild; // Primo nodo (anche testo)
const ultimoNodo = elemento.lastChild; // Ultimo nodo (anche testo)
// Accedere al genitore
const genitore = elemento.parentElement;
// Accedere ai fratelli
const fratelloSuccessivo = elemento.nextElementSibling;
const fratelloPrecedente = elemento.previousElementSibling;Differenza chiave: children contiene solo elementi HTML, childNodes include anche nodi di testo (spazi, a capo).
getElementsBy...Importante: questi metodi ritornano collezioni live (HTMLCollection) che si aggiornano automaticamente quando il DOM cambia.
querySelectorSi tratta di alternative più moderne e flessibili rispetto ai metodi getElementsBy....
querySelector ritorna il primo match o null.querySelectorAll ritorna una collezione statica (NodeList, snapshot).| Metodo | Risultato | Live? | Selettore |
|---|---|---|---|
getElementById('id') |
Element |
No | Solo ID |
getElementsByClassName('class') |
HTMLCollection |
Sì | Solo classe |
getElementsByTagName('tag') |
HTMLCollection |
Sì | Solo tag |
querySelector('selector') |
Element |
No | CSS completo |
querySelectorAll('selector') |
NodeList |
No | CSS completo |
Generalmente, i metodi querySelector* sono preferibili, tranne quando serve una collezione live.
In tal caso, invece, si usano i metodi getElement*.
matches()Per verificare se un elemento corrisponde a un selettore:
Utile per validare o filtrare elementi dinamicamente.
I metodi di ricerca ritornano collezioni simili ad array, ma non sono array veri!
Come convertire in array vero:
Nota: per sicurezza, converti sempre in array quando vuoi scorrere con un ciclo.
Esercizio
Dato il seguente codice HTML:
id e stampiamo textContent.item.textContent.createElementProprietà principali:
textContent: testo puro.innerHTML: interpreta HTML.className: classe CSS.textContentInserisce solo testo puro, senza interpretare HTML.
textContent è da preferire quando possibile. Usa innerHTML solo quando controlli il contenuto.
append e prependremoveclassListelement.stylePossiamo modificare gli stili CSS direttamente con JavaScript usando element.style:
Nota: le proprietà CSS con trattino (background-color) diventano camelCase (backgroundColor) in JavaScript.
Quando usare classList vs style:
classList → preferibile per toggle show/hide, stati (attivo/inattivo), temi. Più manutenibile.style → utile per valori dinamici calcolati (es. posizione, dimensione da variabili).getAttribute e setAttributeDifferenza tra proprietà DOM e attributi HTML:
const link = document.querySelector('a');
// Proprietà DOM (accesso diretto)
link.href = 'https://example.com'; // Modifica proprietà
console.log(link.href); // Legge (URL assoluto normalizzato)
// Attributi HTML (via metodi)
link.setAttribute('href', '/nuova-url'); // Modifica attributo
const href = link.getAttribute('href'); // '/nuova-url' (valore esatto)Attributi data-* personalizzati:
Gli attributi data-* sono utili per memorizzare dati custom su elementi:
// HTML: <button data-user-id="123" data-action="delete">Elimina</button>
const button = document.querySelector('button');
// Accesso via getAttribute
const userId = button.getAttribute('data-user-id'); // '123'
// Accesso via dataset (più comodo!)
console.log(button.dataset.userId); // '123' (camelCase)
console.log(button.dataset.action); // 'delete'
// Modifica
button.dataset.userId = '456';
button.dataset.status = 'active'; // Crea data-status="active"Ricostruiamo la pagina da zero
Riprendiamo il ricettario della lezione 1, ma stavolta l’HTML deve essere vuoto: costruiamo tutta la pagina con JavaScript.
index.html lascia solo un contenitore vuoto: <div id="app"></div>.script.js crea un oggetto ricetta con titolo, descrizione, immagine, ingredienti, passaggidocument.createElement() per creare h1, img, p, h2, ul, olul e ol con un ciclo, creando un li per ogni elemento.textContent per il testo e setAttribute per src e alt dell’immagine.classList.add() per poter applicare gli stili CSS.La pagina finale deve avere la stessa struttura del ricettario originale.
Niccolò Maltoni