Changing CSS properties with JavaScript
The previous lesson ended with elements stored in const variables. Now you can do something visible with them. There are two ways to change how an element looks from JavaScript: write CSS properties onto the element directly, or add and remove classes that your stylesheet already describes. Both have their place, and knowing which to reach for keeps a script from turning into a pile of hard-coded colors.
Writing styles with element.style
Every element has a style property. Assigning to it works like writing a style attribute in the HTML:
const title = document.querySelector('#page-title');
title.style.color = '#b03a2e';
title.style.backgroundColor = '#fdf2e9';
title.style.padding = '8px 12px';
title.style.borderLeft = '4px solid #b03a2e';
Three rules cover most of the mistakes people make here:
- Property names with hyphens turn into camelCase.
background-colorbecomesbackgroundColor,border-leftbecomesborderLeft,font-sizebecomesfontSize. In JavaScript a hyphen would be read as a minus sign. - Values are strings written exactly as in CSS, units included.
title.style.width = '300px'works.title.style.width = 300is ignored, because CSS wants a unit on any length other than zero. - An invalid value is dropped without a sound. No error appears in the console, the old value stays and the page looks unchanged. When a style refuses to apply, check the spelling of the value before anything else.
To undo a style you set, assign an empty string: title.style.color = ''. The element falls back to whatever the stylesheet says.
Why these styles win
element.style writes inline styles, the same as a style="..." attribute. Inline declarations beat rules from your stylesheet unless a rule there is marked !important. That is convenient for a quick change and confusing later, when you edit the stylesheet and nothing happens because a script wrote an inline value earlier. Inspect the element in the developer tools and you will see the inline style listed at the top.
Reading styles with getComputedStyle
element.style only reads back inline values. If the color came from a stylesheet, title.style.color returns an empty string, which surprises nearly everyone the first time. To read the value the browser is actually using, ask for the computed style:
const styles = getComputedStyle(title);
console.log(styles.color); // "rgb(176, 58, 46)"
console.log(styles.fontSize); // "32px"
Computed values come back normalized: colors as rgb(), font sizes in pixels, whatever units you wrote in the stylesheet. The hex color #b03a2e is red 176, green 58, blue 46, so the first line matches the style set above. The object is read only. To change something, go back to style or to classes.
Switching classes with classList
Setting five properties one at a time gets old fast, and it scatters design decisions through your script. The cleaner habit is to describe each look in CSS and let JavaScript decide which classes an element carries. If classes still feel new, the CSS course introduces them in its lesson on the style tag and class attribute.
<style>
.note { padding: 6px 10px; border-left: 3px solid #ccc; }
.note.is-done { color: #777; text-decoration: line-through; border-color: #2e8b57; }
.is-hidden { display: none; }
</style>
const notes = document.querySelectorAll('.note');
notes[0].classList.add('is-done');
notes[1].classList.toggle('is-done'); // adds it, because it was missing
notes[2].classList.remove('is-hidden'); // no error, even though it was never there
console.log(notes[0].classList.contains('is-done')); // true
The classList methods are few and worth memorizing:
add('name')adds a class. Adding one that is already there does nothing.remove('name')takes a class away, again without complaint if it is missing.toggle('name')adds the class if it is absent and removes it if present, then returnstrueorfalseto tell you which happened.contains('name')answers whether the element has the class.replace('old', 'new')swaps one class for another.
Avoid assigning to className for this job. notes[0].className = 'is-done' replaces the entire class attribute, so the paragraph loses note as well, along with every rule that targets .note.
The is- prefix is only a naming habit, but a useful one. Reading the stylesheet months later, you can tell at a glance which classes describe a state that a script switches on and off.
Custom properties for themes
CSS custom properties, often called CSS variables, give you a third option that suits color themes. Define the variable in your stylesheet, use it in as many rules as you like, then change its value from JavaScript with setProperty, which takes the name exactly as CSS writes it:
document.documentElement.style.setProperty('--accent', '#2e8b57');
Every rule that uses var(--accent) updates at once. document.documentElement is the <html> element, so the new value reaches the whole page.
Which one to use
Use classList whenever the change is a state: done, hidden, selected, open, has an error. Use style for values only the script can know, such as a width calculated from a number someone typed or a position that follows the mouse. Use a custom property when one value feeds many rules at once.
Try it
Take the bench-notes page from lesson 1, paste it into the online HTML editor and add the <style> block above to its head. In a script at the end of the body, add is-done to the second note. Then edit the .is-done rule in the stylesheet, maybe a different border color, and watch the page follow without touching the script. Nothing responds to clicks yet; that wiring is the subject of the events lesson.