DEV Community

Cover image for Stop Using JS for CSS
Ahmed Niazy
Ahmed Niazy

Posted on

Stop Using JS for CSS

Stop Using JS for CSS — Deep, Detailed Explanation (Pure JS)

🔥 The Core Idea

JavaScript should not be used to control layout, styling logic, spacing, colors, animations, or responsiveness — CSS is already optimized for these tasks and is handled directly by the browser engine (e.g., Chrome’s Blink, Safari’s WebKit).

JavaScript should only control state.
CSS should control style.

Whenever JS tries to handle style, you get:

  • lower performance
  • layout thrashing
  • hard-to-maintain code
  • more bugs
  • loss of browser optimizations

Let’s break down the article's arguments in detail, with pure JavaScript examples.


🧩 Why CSS Should Handle Style (Not JavaScript)

### 🔹 1. CSS handles layout & rendering natively

Browsers have an optimized rendering engine designed specifically to handle:

  • layout
  • box models
  • animations
  • transitions
  • media queries
  • responsiveness

CSS runs on the Compositor Thread, not the Main JS Thread.
This means CSS can animate smoothly even at 60fps while JS is doing heavy work.

When you try to animate or style using JS, everything is forced into the Main Thread, leading to jank and lag.


🚫 JS for styling causes problems

Let’s go through the article’s main problems explained in depth.


⚠️ Problem 1 — JavaScript re-renders are expensive

Changing styles with JS often forces layout recalculation, which is one of the most expensive operations in a browser.

Example of bad practice:

element.style.width = "200px";
element.style.height = "300px";
element.style.marginTop = "20px";
Enter fullscreen mode Exit fullscreen mode

Every line here may force the browser to calculate new layout.


⚠️ Problem 2 — JavaScript overrides browser optimizations

CSS has built-in optimizations:

  • cascade
  • inheritance
  • layered styles
  • GPU acceleration
  • parallel execution

When JS sets styles directly, these optimizations are bypassed.

Example:

// BAD
box.style.transform = "translateX(100px)";
Enter fullscreen mode Exit fullscreen mode

Instead:

.move {
  transform: translateX(100px);
}
Enter fullscreen mode Exit fullscreen mode
box.classList.add("move");
Enter fullscreen mode Exit fullscreen mode

Much faster and cleaner.


⚠️ Problem 3 — Mixed responsibilities → unreadable code

JS is for logic, CSS is for styling.

When devs mix both in JS files, code becomes:

  • harder to read
  • harder to debug
  • harder to maintain
  • harder for teams

Example of the bad pattern:

const button = document.querySelector("button");
button.style.background = "#4CAF50";
button.style.padding = "12px";
button.style.borderRadius = "10px";
Enter fullscreen mode Exit fullscreen mode

CSS should handle this:

.btn {
  background: #4CAF50;
  padding: 12px;
  border-radius: 10px;
}
Enter fullscreen mode Exit fullscreen mode
button.classList.add("btn");
Enter fullscreen mode Exit fullscreen mode

⚠️ Problem 4 — Losing progressive enhancement

If styling is tied to JS, and JS fails to load, the website breaks visually.

HTML + CSS should render correctly even without JS.

If your UI depends on JS to set colors, sizes, spacing… then your site has no fallback.


⚠️ Problem 5 — JS styling breaks caching

Browsers cache CSS files.
They do not cache inline JS-generated styles.

If you rely on JS for layout, the browser must recalculate everything from zero every reload.


⚠️ Problem 6 — Difficulty overriding styles

CSS offers:

  • !important
  • specificity
  • layered cascades
  • theming

But when JS injects styles inline:

<div style="color: red"></div>
Enter fullscreen mode Exit fullscreen mode

You cannot override them from CSS easily.


⚠️ Problem 7 — JS animations are slower

JS animation loops like:

setInterval(() => {
  box.style.left = box.offsetLeft + 2 + "px";
}, 16);
Enter fullscreen mode Exit fullscreen mode

This forces layout reflow every 16ms.

CSS animations:

@keyframes slide {
  0% { transform: translateX(0); }
  100% { transform: translateX(200px); }
}

.box {
  animation: slide 1s linear;
}
Enter fullscreen mode Exit fullscreen mode

CSS animations run on the GPU → smooth.


🌟 What JS should do instead

🔸 1. Control state

JS handles state changes only.

Example:

box.classList.toggle("is-open");
Enter fullscreen mode Exit fullscreen mode

CSS handles the style:

.box {
  height: 0;
  overflow: hidden;
  transition: height .3s ease;
}

.box.is-open {
  height: 200px;
}
Enter fullscreen mode Exit fullscreen mode

🌟 Pure JavaScript Examples (Correct Way)

### Example 1 — Toggle menu

❌ Bad (JS controls styles):

menu.style.display = menu.style.display === "none" ? "block" : "none";
Enter fullscreen mode Exit fullscreen mode

✔️ Good (JS controls state):

menu.classList.toggle("open");
Enter fullscreen mode Exit fullscreen mode
#menu {
  display: none;
}

#menu.open {
  display: block;
}
Enter fullscreen mode Exit fullscreen mode

### Example 2 — Dark mode

❌ Bad:

document.body.style.background = "#000";
document.body.style.color = "#fff";
Enter fullscreen mode Exit fullscreen mode

✔️ Good:

document.body.classList.add("dark");
Enter fullscreen mode Exit fullscreen mode
.dark {
  background: #000;
  color: #fff;
}
Enter fullscreen mode Exit fullscreen mode

### Example 3 — Animate element

❌ Bad:

let pos = 0;
setInterval(() => {
  pos++;
  box.style.left = pos + "px";
}, 10);
Enter fullscreen mode Exit fullscreen mode

✔️ Good:

box.classList.add("slide");
Enter fullscreen mode Exit fullscreen mode
.slide {
  animation: move 2s linear forwards;
}

@keyframes move {
  from { transform: translateX(0); }
  to   { transform: translateX(200px); }
}
Enter fullscreen mode Exit fullscreen mode

🌟 Conclusion (Very Important)

The article’s main message:

Use JavaScript for:

  • state
  • events
  • data
  • logic

Use CSS for:

  • layout
  • spacing
  • colors
  • themes
  • animations
  • responsiveness
  • transitions

Because CSS is faster, cleaner, and built exactly for this purpose — while JS slows down the browser and increases complexity when used for styling.

Top comments (0)