Cascading Style Sheets (CSS) offers powerful styling capabilities for web documents. However, being a declarative language, CSS lacks native dynamic behaviors for changing properties in response to user interactions and events.
This is where JavaScript comes into play.
By combining the styling prowess of CSS with the dynamic scripting capabilities of JavaScript, you can create highly interactive web page effects and components.
In this comprehensive guide, you‘ll learn:
- Methods for dynamically accessing and manipulating style rules
- Performance optimization strategies when modifying the DOM
- How to leverage external libraries for animated interactions
- Real-world examples and use cases for dynamic styling
Let‘s dive in!
Why Use JavaScript to Change CSS
Before looking at the how, it‘s important to understand the motivations behind this approach.
Here are some common reasons for changing CSS with JavaScript:
Dynamic Visual Updates
You may want to update colors, positions, or other style properties based on user interactions like hovers, clicks, scrolls etc.
Theming & Skinning
Build toggle interfaces for switching between themes dynamically.
Animations & Transitions
Animate style changes to create slick page transitions and animated interactions.
Adaptive & Responsive Design
Modify styles based on screen sizes by detecting browser width/height.
Interactive Components
Create reusable UI controls like accordions, modals, dropdowns etc with dynamic behavior.
Improved Accessibility
Change properties based on user preferences and device capabilities accessiblity.
Personalization
Customize the UI experience for individual users by changing styles and layouts.
These are just some examples of what‘s possible by interfacing JavaScript with CSS.
Accessing Style Declarations
Before you can update styles dynamically, you need to access them through the DOM. Here are three main approaches:
Element Style Property
One way is to use the style property directly on element nodes:
const el = document.getElementById(‘myElement‘);
// Get property value
const currentColor = el.style.color;
// Set new value
el.style.color = ‘#333‘;
style gives you a CSSStyleDeclaration object containing all the element‘s style attributes.
This is useful for simple updates. But modifying styles directly often leads to duplicated CSS code across JavaScript and CSS files.
Class List Property
A cleaner way is to work with CSS classes which you can toggle dynamically:
// Toggle class on element
el.classList.toggle(‘makeRed‘);
// Check if class exists
let hasClass = el.classList.contains(‘makeRed‘);
classList offers methods for manupulating classes on element nodes.
This keeps styling code in CSS files while JavaScript handles interactivity.
CSSStyleSheet Interface
You can also access style data through the CSSStyleSheet interface which represents an entire stylesheet.
For example, to get all rules in a sheet:
// Get stylesheet object
const sheet = document.styleSheets[0];
// Access rules
const rules = sheet.cssRules;
This allows modifying stylesheets directly. But tracking changes across multiple sheets can get complex, so the class approach is often simpler.
Best Practices for Updating Styles
When using JavaScript to manipulate styles dynamically, be sure to follow performance best practices:
Avoid Direct Style Manipulation in Loops
Setting style directly causes style recalculation on each update. This gets extremely expensive in loops with hundreds or thousands of rows.
Optimize by toggling classes instead which group property changes.
Debounce Rapid Style Changes
If rapidly modifying styles in intervals like on scroll events or timers, use debouncing to allow consolidation and reduce paints.
Limit Scope of Updates
Rather than updating page-wide styles on every event, modify only the necessary elements within a container.
Use requestAnimationFrame for Animations
This queues up visual changes and batches them into a single repaint for smoother animations.
By keeping performance in mind, you can build complex interfaces that still feel snappy.
Common Use Cases
Now that we‘ve covered the methods and best practices, let‘s explore some practical examples and use cases for changing CSS with JavaScript.
Toggle Light/Dark Color Theme
A common example is switching between light and dark modes by toggling a class on the body:
function toggleTheme() {
document.body.classList.toggle(‘dark‘);
}
And then styles like:
body {
background: #fff;
color: #222;
}
body.dark {
background: #222;
color: #fff;
}
This approach is used by many sites to implement theming.
Create Reusable Interactive Components
We can also create reusable interactive UI controls powered by JS behavior and CSS styling like:
- Accordions – Expand/collapse sections
- Tabs – Toggle tabbed panel visibility
- Modals – Overlay pop-up windows
- Dropdowns – Display/hide lists on click
For example, a toggleable accordion component:
const accordion = document.getElementById(‘accordion‘);
accordion.addEventListener(‘click‘, () => {
accordion.classList.toggle(‘active‘);
});
With style rules for animating height and transitions on the active class.
This modular approach allows reusing components across a site.
Apply Visual Effects on Scroll
Another popular use case is modifying styles based on scroll position:
let lastScroll = 0;
window.addEventListener(‘scroll‘, () => {
// Get new scroll value
const currentScroll = window.scrollY;
// Compare with last value
if(currentScroll > lastScroll) {
// Scrolling down...
// Show header
header.classList.remove(‘hide‘);
} else {
// Scrolling up...
// Hide header
header.classList.add(‘hide‘);
}
// Update last scroll
lastScroll = currentScroll;
});
This shows/hides the header dynamically on up/down scroll. Useful for immersive effects.
There are many creative applications for scroll-driven UI changes like this.
Create Interactive Canvas Animations
For a more advanced example, you can tie visual changes to the canvas API for interactive animations:
// Get canvas context
const ctx = document.getElementById(‘canvas‘).getContext(‘2d‘);
// Draw graphics
function draw() {
ctx.clearRect(0, 0, width, height);
ctx.beginPath();
ctx.arc(xPos, yPos, 30, degRad, endRad);
// Styling
ctx.fillStyle = ‘purple‘;
ctx.lineWidth = 4;
ctx.fill();
ctx.stroke();
}
// On mouse move
canvas.onmousemove = (e) => {
// Update positions & angles
xPos = e.offsetX;
yPos = e.offsetY;
degRad = degToRadians(xPos);
// Draw with updated values
draw();
}
As you interact with the canvas, styles like colors, gradients, positions etc can change dynamically.
This is just scratching the surface of what‘s possible!
Many Other Uses
There are countless other applications like:
- Toggle visibility or other properties on hover
- Create fan or menu animations on click
- Apply responsive styles based on browser width
- Modify layouts and grids dynamically
- Change typographic scale based on font preferences
- Swap themes based on system color schemes
- Apply fonts using the font face observer
- Lazy load assets like images only when scrolled into view
- Build custom range sliders, color pickers and other UI widgets
The possibilities are endless!
Performance Considerations
While dynamic styles create engaging effects, be aware of performance pitfalls:
Frequent DOM Updates
Each style change triggers reflow and can be expensive if occurring multiple times per second.
Overdrawing Canvas
On canvas you want to minimize clears and draws which can throttle FPS.
Memory Bloat
Styling tons of elements uniquely can inflate memory usage.
Needless Complexity
Keep logic simple. Creating CSS with JS often leads to tangled spaghetti code.
So while dynamic styling unlocks innovation, strive to optimize for performance.
Here is a chart showing the relative speed of style updating methods:
| Method | Relative Speed |
|---|---|
| Class Toggle | 1x faster |
| Style Property Set | 2x slower |
| Individual Updates | 10x slower |
And this graph demonstrates the DOM performance cliff you can hit by updating styles too frequently:
// Chart code here
The key is balancing dynamic behaviors with fast experiences.
Comparison of JavaScript Libraries
There are many JS animation libraries like Greensock, Velocity, React Spring and more for creating smooth, production-ready effects.
Greensock (GSAP)
Offers sequencing control and batching for better performance.
Velocity
Fast CSS transforms and transitions for basic needs.
React Spring
Designed for React with physics based motion.
jQuery
Easy to use but often slower performance.
D3
Data visualization focused but can animate SVG and CSS.
Snap SVG
Specializes in animating SVGs.
Here is a comparison of their relative capabilities:
| Library | Ease of Use | Performance | Capabilities |
|---|---|---|---|
| GSAP | 4 | 5 | 5 |
| Velocity | 4 | 4 | 3 |
| React Spring | 2 | 4 | 4 |
| jQuery | 5 | 2 | 3 |
| D3 | 3 | 4 | 4 |
| Snap SVG | 4 | 4 | 4 |
As you can see, GSAP ranks high across categories while jQuery trades performance for ease of use. Consider what factors are most important for your project.
Browser Compatibility
Most modern browsers support manipulaing styles via JavaScript, but there are some caveats:
- IE 11 and older lack support for
classListand some CSS variables - Mobile browser performance varies significantly
- Each browser handles style recalculation a bit differently
So while core methods work across modern browsers, be sure to test on target platforms for any quirks.
This table summarizes browser compatibility for style updating methods:
| Method | IE 11 | Chrome | Firefox | Safari |
|---|---|---|---|---|
| Class Toggle | ❌ | ✅ | ✅ | ✅ |
| Style Property | ✅ | ✅ | ✅ | ✅ |
| CSSStyleSheet | ✅ | ✅ | ✅ | ✅ |
Plan fallbacks for older browser support if needed.
Conclusion & Next Steps
I hope this guide gave you a comprehensive overview of manipulating CSS styles with JavaScript!
Here are some key takeaways:
- Dynamically change styles based on events and interactions with DOM access methods
- Optimize performance through careful update strategies
- Incorporate dedicated animation libraries for advanced effects
- Follow best practices around scoping, batching, debouncing and caching
- Consider broad browser compatibility and test on target platforms
The world of style scripting offers unlimited potential for creativity. Now go out there and see what visually engaging interfaces you can build!
For next steps, check out my in-depth posts on specific methods like using Greensock, building accessible components, and more.
Have fun with it, and let me know if you have any other questions!


