Prima di cominciare a trattare i modi in cui JavaScript interagisce con gli stili e le classi, ecco una regola importante. Si spera che sia abbastanza scontata, ma non guasta ripeterla.
Ci sono in genere due modi di applicare uno stile ad un elemento:
- Creare una classe CSS ed aggiungerla:
<div class="...">
- Scrivere direttamente le proprietà dentro
style
:<div style="...">
.
JavaScript può modificare sia le classi che le proprietà all’interno di style
.
Dovremmo sempre preferire le classi CSS a style
. Quest’ultimo dovrebbe essere usato solo se le classi non sono sufficienti.
Per esempio, è ragionevole l’uso di style
se calcoliamo dinamicamente le coordinate di un elemento e vogliamo impostarle con JavaScript, come in casi analoghi a questo esempio:
let top = /* calcoli complessi */;
let left = /* calcoli complessi */;
elem.style.left = left; // es '123px', calcolato al momento dell'esecuzione
elem.style.top = top; // es '456px'
Per gli altri casi, come rendere rosso un testo o aggiungere un’immagine di sfondo, definiamo degli stili CSS e poi applichiamo la classe con JavaScript. È più flessibile e più facile da gestire.
className e classList
Modificare una classe è una delle operazioni più comuni negli script.
Molto tempo fa c’era una limitazione in JavaScript: una parola riservata come "class"
non poteva essere una proprietà di un oggetto. Tale limitazione non c’è più, ma a quel tempo era impossibile avere una proprietà "class"
come elem.class
.
Quindi per le classi fu introdotta la proprietà "className"
che è simile: l’attributo "class"
ha il suo corrispettivo DOM in elem.className
.
Per esempio:
<body class="main page">
<script>
alert(document.body.className); // main page
</script>
</body>
Se assegniamo un valore a elem.className
rimpiazziamo l’intero contenuto dell’attributo "class"
. Talvolta è il risultato che vogliamo ottenere, spesso invece vogliamo aggiungere/rimuovere una singola classe.
Esiste un’altra proprietà per quello: elem.classList
.
La proprietà elem.classList
è uno speciale oggetto con i metodi add/remove/toggle
per aggiungere/rimuovere/alternare una singola classe.
Per esempio:
<body class="main page">
<script>
// aggiunge una classe
document.body.classList.add('article');
alert(document.body.className); // main page article
</script>
</body>
Possiamo agire pertanto sia sulla stringa intera delle classi rappresentata da className
, oppure sulle singole classi usando classList
. La scelta dipende dalle nostre esigenze.
Metodi di classList
:
elem.classList.add/remove("class")
– aggiunge/rimuove la classe.elem.classList.toggle("class")
– aggiunge la classe se non esiste, diversamente la rimuove.elem.classList.contains("class")
– verifica che esista una determinata classe, restituiscetrue/false
.
In aggiunta classList
è iterabile, quindi possiamo elencare tutte le classi con for..of
in questo modo:
<body class="main page">
<script>
for (let name of document.body.classList) {
alert(name); // main, e dopo page
}
</script>
</body>
La proprietà style di un elemento
La proprietà elem.style
è un oggetto corrispondente a ciò che è scritto dentro l’attributo "style"
. Impostando elem.style.width="100px"
otteniamo lo stesso effetto che otterremmo scrivendo width:100px
dentro l’attributo style
.
Per le proprietà composte da più di una parola, si usa l’iniziale maiuscola dalla seconda parola in poi (camel case):
background-color => elem.style.backgroundColor
z-index => elem.style.zIndex
border-left-width => elem.style.borderLeftWidth
Per esempio:
document.body.style.backgroundColor = prompt('background color?', 'green');
Le proprietà con il prefisso del browser come -moz-border-radius
, -webkit-border-radius
seguono anch’esse la stessa regola: un trattino comporta l’uso del maiuscolo.
Per esempio:
button.style.MozBorderRadius = '5px';
button.style.WebkitBorderRadius = '5px';
Resettare la proprietà style
Talvolta vogliamo assegnare uno stile e successivamente rimuoverlo.
Per esempio, per nascondere un elemento, possiamo impostare elem.style.display = "none"
.
Successivamente potremmo voler rimuovere style.display
come se non fosse impostato. Invece di delete elem.style.display
dovremmo assegnargli una stringa vuota: elem.style.display = ""
.
// se eseguiamo questo codice, il <body> lampeggerà
document.body.style.display = "none"; // hide
setTimeout(() => document.body.style.display = "", 1000); // ritorna alla normalità
Se assegniamo una stringa vuota a style.display
, il browser applica come di consueto le classi CSS ed i suoi stili predefiniti, come se non ci fosse alcuna proprietà style.display
.
style.cssText
Di solito usiamo style.*
per assegnare le proprietà di stile individualmente. Non possiamo impostare tutti gli stili in questo modo div.style="color: red; width: 100px"
, perché div.style
è un oggetto ed è in sola lettura.
Per impostare tutti gli stili come stringa c’è una speciale proprietà style.cssText
:
<div id="div">Button</div>
<script>
// qui possiamo impostare speciali clausole di stile come "important"
div.style.cssText=`color: red !important;
background-color: yellow;
width: 100px;
text-align: center;
`;
alert(div.style.cssText);
</script>
Questa proprietà è usata di rado, poiché un tale assegnamento rimuove tutti gli stili esistenti: non li aggiunge, ma li sostituisce. Potrebbe eliminare inavvertitamente qualcosa di necessario. Possiamo tuttavia usarla in sicurezza per i nuovi elementi, quando siamo certi che non cancelleremo uno stile preesistente.
Lo stesso risultato può essere ottenuto impostando un attributo: div.setAttribute('style', 'color: red...')
.
Prestate attenzione alle unità di misura
Non dimenticate di aggiungere le unità di misura CSS ai valori.
Ad esempio, non dovremmo impostare elem.style.top
a 10
, piuttosto a 10px
. Altrimenti non funzionerebbe:
<body>
<script>
// non funziona!
document.body.style.margin = 20;
alert(document.body.style.margin); // '' (stringa vuota, l'assegnamento è stato ignorato)
// aggiungiamo ora l'unità di misura CSS (px) - e funziona
document.body.style.margin = '20px';
alert(document.body.style.margin); // 20px
alert(document.body.style.marginTop); // 20px
alert(document.body.style.marginLeft); // 20px
</script>
</body>
Nota: il browser “spacchetta” la proprietà style.margin
nelle ultime linee e deduce da essa style.marginLeft
e style.marginTop
.
Stili calcolati: getComputedStyle
Modificare uno stile, quindi, è semplice. Ma come leggerlo?
Vogliamo, ad esempio, conoscere la dimensione, i margini, il colore di un elemento. Come fare?
La proprietà style
agisce solo sul valore dell’attributo "style"
, senza considerare alcuna cascata CSS.
Pertanto non possiamo leggere nulla che derivi dalle classi CSS tramite elem.style
.
Qui, per esempio, style
non rileva il margine:
<head>
<style> body { color: red; margin: 5px } </style>
</head>
<body>
The red text
<script>
alert(document.body.style.color); // vuoto
alert(document.body.style.marginTop); // vuoto
</script>
</body>
…ma cosa dovremmo fare se avessimo bisogno, ad esempio, di incrementare il margine di 20px
? Dovremmo prima conoscerne il valore corrente.
C’è un altro metodo per quello: getComputedStyle
.
La sintassi è:
getComputedStyle(element, [pseudo])
- element
- L’elemento di cui leggere il valore.
- pseudo
- Uno pseudo-elemento se richiesto, per esempio
::before
. Una stringa vuota o nessun argomento significa l’elemento stesso.
Il risultato è un oggetto con gli stili, come elem.style
, ma, a differenza di quello, tiene conto di tutte le classi CSS.
Per esempio:
<head>
<style> body { color: red; margin: 5px } </style>
</head>
<body>
<script>
let computedStyle = getComputedStyle(document.body);
// adesso possiamo ricavarne il margine ed il colore
alert( computedStyle.marginTop ); // 5px
alert( computedStyle.color ); // rgb(255, 0, 0)
</script>
</body>
Ci sono due concetti nei CSS:
- Un valore di uno stile computed è il valore derivante dall’applicazione di tutte le regole e dell’ereditarietà dei CSS: il risultato della cascata CSS. Può essere simile a
height:1em
ofont-size:125%
. - Un valore di uno stile resolved è quello applicato realmente sull’elemento. Valori come
1em
o125%
sono relativi. Il browser prende i valori computed e li converte tutti in unità di misura fisse e assolute, per esempio:height:20px
ofont-size:16px
. Per le proprietà geometriche i valori resolved possono avere la virgola, comewidth:50.5px
.
Molto tempo addietro getComputedStyle
è stato creato per ottenere i valori computed, ma si scoprì che i valori resolved erano molto più utili e lo standard è cambiato.
Attualmente, quindi, getComputedStyle
restituisce il valore resolved della proprietà, di solito espressa in px
per le proprietà geometriche.
getComputedStyle
richiede il nome completo della proprietàDovremmo sempre chiedere l’esatta proprietà che si desidera, come paddingLeft
o marginTop
o borderTopWidth
. Diversamente il risultato corretto non è garantito.
Per esempio, se ci sono le proprietà paddingLeft/paddingTop
, cosa otterremmo con getComputedStyle(elem).padding
? Niente, o forse un valore “generato” a partire dai valori di padding noti? Non esiste una regola standard in questo caso.
Ci sono altre incongruenze. Ad esempio, alcuni browser (Chrome) mostrano 10px
nel documento in basso, ed altri (Firefox) – invece no:
<style>
body {
margin: 10px;
}
</style>
<script>
let style = getComputedStyle(document.body);
alert(style.margin); // Firefox restituisce una stringa vuota
</script>
:visited
sono nascosti!I link visitati possono ricevere un colore tramite la pseudoclasse CSS :visited
.
Tuttavia `getComputedStyle non dà accesso a quel colore, poiché diversamente, una pagina arbitraria potrebbe scoprire se l’utente ha visitato un link creandolo e verificandone gli stili.
JavaScript potrebbe non rilevare gli stili applicati da :visited
. C’è una limitazione nei CSS, inoltre, che vieta su :visited
l’applicazione di stili che modifichino le proprietà geometriche. Questo per garantire che, per una pagina malevola, non ci sia una via traversa di testare se un link è stato visitato e quindi di violare la privacy.
Riepilogo
Per gestire le classi abbiamo a disposizione due proprietà DOM:
className
– il valore stringa, ottimo per gestire l’intero insieme delle classi.classList
– l’oggetto con i metodiadd/remove/toggle/contains
, ottimo per gestire le classi individualmente.
Per modificare gli stili:
-
La proprietà
style
è un oggetto contenente gli stili CSS, le proprietà composte da più di una parola sono trascritte in camel case. Leggere e scrivere con questa proprietà equivale a modificare individualmente gli stili con l’attributo"style"
. Per vedere come applicareimportant
e per altre esigenze poco comuni – c’è una lista di metodi su MDN. -
La proprietà
style.cssText
corrisponde al contenuto completo dell’attributo"style"
, l’intera stringa degli stili.
Per leggere gli stili resolved (che tengono conto di tutte le classi, dopo che tutti i CSS sono stati applicati e sono stati calcolati i valori risultanti):
- Il metodo
getComputedStyle(elem, [pseudo])
restituisce un oggetto simile astyle
con tali valori. Questi sono in sola lettura.
Commenti
<code>
, per molte righe – includile nel tag<pre>
, per più di 10 righe – utilizza una sandbox (plnkr, jsbin, codepen…)