CSS Styles and the DOM — Complete Guide
In this tutorial, you will learn about CSS Styles and the DOM. We cover key concepts, practical examples, and best practices to help you master this topic.
Reading and setting CSS styles through the DOM involves inline style manipulation, computed styles via getComputedStyle, and CSS custom properties for dynamic theming.
What You'll Learn
- How to set inline styles using the style property
- How to read computed styles with getComputedStyle
- How to work with CSS custom properties through JavaScript
- The difference between inline, computed, and resolved styles
Why It Matters
Dynamic styling enables themes, animations, responsive adjustments, and user preferences. Without the style API, you would need to predefine every possible style combination in CSS classes.
Real-World Use
- A dark mode toggle reads and sets CSS custom properties for theme colors
- A resizable panel updates element widths in response to mouse drag
- A color picker changes background colors in real time as the user adjusts sliders
flowchart LR A[Styles in JS] --> B[Inline style] A --> C[Computed style] A --> D[Custom properties] B --> E[element.style.property] C --> F[getComputedStyle] D --> G[setProperty / getPropertyValue]
Setting Inline Styles
Inline styles are applied directly to the element and have the highest specificity except for !important.
const box = document.getElementById('animated-box');
// Set individual properties (camelCase property names)
box.style.width = '200px';
box.style.height = '200px';
box.style.backgroundColor = 'tomato';
box.style.transition = 'all 0.3s ease';
box.style.transform = 'rotate(0deg)';
// Properties with hyphens become camelCase
// background-color → backgroundColor
// margin-top → marginTop
// -webkit-transform → WebkitTransform (capital W)
console.log('Inline width:', box.style.width);
console.log('Inline bg:', box.style.backgroundColor);
// Animate on click
box.addEventListener('click', function() {
this.style.transform = 'rotate(45deg)';
});
Expected output: The box appears with tomato background and rotates 45 degrees on click. The console shows the inline width and background values.
Reading Computed Styles
The getComputedStyle method returns the final resolved styles after all CSS rules (external, embedded, inline) have been applied.
const element = document.querySelector('.styled-element');
// Get computed styles
const computed = getComputedStyle(element);
console.log('Computed color:', computed.color);
console.log('Computed font-size:', computed.fontSize);
console.log('Computed display:', computed.display);
console.log('Computed margin:', computed.margin);
// getComputedStyle returns ALL properties
// Access any property by camelCase name
console.log('Padding top:', computed.paddingTop);
// Important: computed values are in absolute units (px, etc.)
// Even if the CSS uses rem or em, the computed value is in px
Expected output: The computed values show the actual rendered styles in absolute units. These values reflect the cascade of all CSS rules affecting the element.
Working with CSS Custom Properties
CSS custom properties (variables) can be read and set on any element and are inherited by descendants.
// Set a custom property on the root element
document.documentElement.style.setProperty('--primary-color', '#3498db');
document.documentElement.style.setProperty('--border-radius', '8px');
document.documentElement.style.setProperty('--spacing', '1rem');
// Read a custom property
const primary = getComputedStyle(document.documentElement)
.getPropertyValue('--primary-color').trim();
console.log('Primary color:', primary);
// Update theme
function setTheme(theme) {
if (theme === 'dark') {
document.documentElement.style.setProperty('--bg', '#1a1a2e');
document.documentElement.style.setProperty('--text', '#e0e0e0');
} else {
document.documentElement.style.setProperty('--bg', '#ffffff');
document.documentElement.style.setProperty('--text', '#333333');
}
}
setTheme('dark');
Expected output: The primary color value is logged. The page theme switches to dark mode with the specified background and text colors.
Using CSS Transitions with JavaScript
Combine JavaScript style changes with CSS transitions for smooth animations.
<style>
.fade-box {
width: 200px;
height: 200px;
background: #3498db;
transition: opacity 0.5s ease, transform 0.5s ease;
}
.fade-box.hidden {
opacity: 0;
transform: scale(0.8);
}
</style>
const box = document.querySelector('.fade-box');
const toggleBtn = document.getElementById('toggle-btn');
// Method 1: Toggle a class
toggleBtn.addEventListener('click', function() {
box.classList.toggle('hidden');
});
// Method 2: Direct style property changes
function fadeOut(element) {
// Trigger the transition by changing inline styles
// But first ensure the current opacity is set
element.style.opacity = '1';
// Force a reflow so the browser registers the starting state
void element.offsetWidth;
// Now set the target state
element.style.opacity = '0';
element.style.transform = 'scale(0.8)';
}
Expected output: The box fades out with a scaling effect over 0.5 seconds when the button is clicked. The reflow trick ensures the transition plays from the correct starting state.
Measuring Elements
Get the actual dimensions and position of elements using offset and bounding client rect properties.
const element = document.querySelector('.measured');
// Offset properties (relative to positioned parent)
console.log('Offset top:', element.offsetTop);
console.log('Offset left:', element.offsetLeft);
console.log('Offset width:', element.offsetWidth);
console.log('Offset height:', element.offsetHeight);
// Bounding client rect (relative to viewport)
const rect = element.getBoundingClientRect();
console.log('Rect top:', rect.top);
console.log('Rect left:', rect.left);
console.log('Rect width:', rect.width);
console.log('Rect height:', rect.height);
console.log('Rect bottom:', rect.bottom);
console.log('Rect right:', rect.right);
// getBoundingClientRect is useful for
// scroll-based animations and positioning
Expected output: The offset values show position relative to the offset parent. The bounding rect shows position relative to the viewport. These values are pixels.
Common Mistakes
- Setting style properties to numbers without units —
element.style.width = 200does nothing. You must include the unit:element.style.width = '200px'. - Reading style for values set by CSS classes — The
styleobject only reads inline styles. UsegetComputedStyleto read values from stylesheets. - Forgetting to trim getPropertyValue results —
getPropertyValueincludes leading/trailing whitespace. Use.trim()to clean the value. - Assuming getComputedStyle returns live values — The returned object is a snapshot. If CSS changes, call getComputedStyle again to get fresh values.
- Not triggering a reflow before transitions — When changing styles between two states, the browser may batch the changes and skip the transition. Force a reflow with
void element.offsetWidthbetween state changes.
Practice Questions
- What is the difference between element.style.width and getComputedStyle(element).width? element.style.width reads only inline styles and returns empty if not set inline. getComputedStyle returns the final resolved width after all CSS rules apply.
- How do you set a CSS custom property with JavaScript? Use
element.style.setProperty('--property-name', 'value'). - Why might setting element.style.opacity = 0 not trigger a CSS transition? If the element is initially display:none or the transition property is not set. Also, the browser may batch the change. Use the reflow trick to force two distinct style states.
- Challenge: Write a function that gradually animates an element from one set of styles to another over a given duration using requestAnimationFrame, without relying on CSS transitions.
FAQ
Mini Project
Build a theme switcher that toggles between light and dark modes. Define all theme colors as CSS custom properties on :root. When the user clicks the toggle, update all custom properties via JavaScript. Use smooth transitions on the body and main container. Store the user preference in localStorage so it persists across page loads.
What's Next
Continue with Lesson 8: Creating and Removing Nodes to learn advanced node creation patterns including document fragments and efficient bulk insertion.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro