Hero Image

Why Everyone Should Learn Core CSS and JavaScript

April 2026

Frameworks are good, but they are overrated. The HTML, CSS, and JS stack just works, and here is why that matters.

I spent years reaching for abstractions before I understood the platform they sat on. That was a mistake.

Every framework is built on HTML, CSS, and JavaScript. When you only know the framework, you're building on borrowed intuition. You can't debug what you don't understand. You can't optimize what's invisible to you.

This article is for developers who want to reclaim that understanding. Frameworks are tools—good tools. But the platform they rest on isn't going anywhere. Learn it.


Frameworks Are Good. Overrated, But Good.

I will say it plainly: React, Vue, Tailwind, and their cousins are useful. They solve real problems at scale. But we've reached a point where developers treat them as the starting line instead of the finish line.

A framework is a shortcut. Shortcuts are only useful if you already know the terrain. If you don't, you're just lost faster.

The HTML, CSS, and JavaScript stack is not legacy. It is not a stepping stone to something better. It is the runtime. Every framework compiles down to it. Every browser executes it. Understanding it directly is not nostalgia—it is engineering.


The Stack Just Works Because It Is the Platform

When you write HTML, CSS, and JS, you're writing for the platform. Not a wrapper. Not a virtual machine. The actual platform. That means:

  • Zero build steps
  • Zero dependency trees
  • Zero abstraction leakage

A .html file opens in any browser on any device from the last decade. That's not a limitation. That's power.

The Cascade Is a Feature, Not a Bug

css
/* Base styles */
.card {
  padding: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: white;
}

/* Variants via the cascade */
.card.featured {
  border-color: #2563eb;
  box-shadow: 0 4px 6px -1px rgba(37, 99, 235, 0.1);
}

.card.compact {
  padding: 8px;
  font-size: 14px;
}

The cascade lets you model state and variation with nothing but class names and specificity. No CSS-in-JS runtime overhead. No utility class generation step. The browser parses this in microseconds because it's native.

When you understand specificity, inheritance, and the box model, you can express complex UI states with minimal code and zero performance tax.

CSS Custom Properties: The Mutable Variables You Already Have

css
:root {
  --color-primary: #2563eb;
  --color-surface: #ffffff;
  --space-unit: 8px;
}

.card {
  background: var(--color-surface);
  padding: calc(var(--space-unit) * 2);
  border: 2px solid var(--color-primary);
}

/* Change the entire theme in one line */
[data-theme="dark"] {
  --color-primary: #60a5fa;
  --color-surface: #1f2937;
}

CSS custom properties are live, mutable variables. Change a value on a parent element and every child updates instantly. No re-render cycle. No virtual DOM diff. The browser's style engine handles this at the compositor level—fast by default.

Frameworks often reimplement this with JavaScript state and pay the performance tax for the privilege.


JavaScript: Direct Platform Access

Frameworks abstract the DOM. Sometimes that helps. Sometimes it gets in the way. Core JavaScript gives you direct access to browser APIs without the indirection.

Event Delegation at Scale

javascript
// One listener for a thousand items
document.getElementById("product-list").addEventListener("click", (event) => {
  const button = event.target.closest(".add-to-cart");
  if (!button) return;

  const productId = button.dataset.productId;
  addToCart(productId);
});

This scales linearly. One listener. Constant memory. React's synthetic event system does something similar under the hood, but if you only know React, you don't understand why. You also don't know that closest() eliminates the need for prop drilling and ref forwarding.

The platform already solved this.

Intersection Observer: Performance Without the Library

javascript
const imageObserver = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.classList.remove("lazy");
      imageObserver.unobserve(img);
    }
  });
});

document.querySelectorAll("img[data-src]").forEach((img) => {
  imageObserver.observe(img);
});

No library needed. The browser ships IntersectionObserver—a native API that watches element visibility with better performance than scroll listeners. It runs off the main thread where possible. Frameworks wrap this in hooks and components, but the underlying API is simple, stable, and universal.

Form Handling Without the Ceremony

javascript
const form = document.getElementById("checkout");

form.addEventListener("submit", async (event) => {
  event.preventDefault();

  const data = Object.fromEntries(new FormData(form));
  // data = { email: '...', address: '...', ... }

  try {
    const response = await fetch("/api/checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });

    if (!response.ok) throw new Error(response.statusText);
    window.location.href = "/success";
  } catch (err) {
    form.querySelector(".error").textContent = err.message;
  }
});

FormData is a built-in interface that serializes form fields automatically. Object.fromEntries() converts it to a plain object in one line. No controlled component state. No two hundred lines of reducer logic.

The browser's form handling is robust, accessible, and battle-tested across decades of use.


Debugging Is Where Core Knowledge Pays Off

Here's a real scenario: A button click in a React app does nothing. The state looks correct. The handler is bound. You spend an hour in React DevTools.

The problem? A CSS rule with pointer-events: none on a parent div. React can't help you there. CSS can.

Another one: A form submits twice. You check the event handler, state updates, API calls. The issue? You attached the listener twice because you didn't clean up a useEffect. JavaScript fundamentals, not React specifics.

Frameworks add layers. Layers add places for bugs to hide. Core knowledge strips those layers away.

Reading the Computed Box

javascript
const element = document.querySelector(".modal");
const styles = window.getComputedStyle(element);

console.log(styles.width); // "400px"
console.log(styles.paddingLeft); // "24px"
console.log(styles.getPropertyValue("margin-top")); // "16px"

When a layout breaks, getComputedStyle tells you exactly what the browser resolved after all cascade, inheritance, and calculations. No guessing. You ask the platform directly.


Performance: The Stack Is Already Optimized

Browsers are the most optimized runtime on earth. Billions of dollars and decades of engineering have gone into parsing HTML, computing styles, and executing JavaScript.

When you add a framework, you add weight. Sometimes that weight is justified. Often it is not.

Progressive Enhancement With Zero JavaScript

html
<details class="accordion">
  <summary class="accordion-trigger">Section One</summary>
  <div class="accordion-content">
    <p>Content here...</p>
  </div>
</details>
css
.accordion {
  border: 1px solid #e5e7eb;
  border-radius: 6px;
}

.accordion-trigger {
  padding: 12px 16px;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}

.accordion-trigger::-webkit-details-marker {
  display: none;
}

.accordion-content {
  padding: 0 16px 16px;
}

.accordion[open] .accordion-trigger {
  color: #2563eb;
}

Zero JavaScript. Zero dependencies. The <details> element handles open/close state, keyboard navigation, and accessibility semantics natively. CSS styles it. Works on every browser, every device, zero bundle size overhead.

Frameworks often reimplement this with dozens of lines of stateful code.


The Honest Truth

I've worked with developers who spin up Next.js in minutes but can't center a div without Flexbox cheatsheets. That's not a knock on them. It's a symptom of an industry that's rushed to abstraction.

Frameworks are good. They speed up teams, enforce consistency, handle edge cases. But they're overrated as a starting point. You don't need React for a landing page. You don't need Tailwind to style a form. You don't need a build step to ship something useful.

The HTML, CSS, and JavaScript stack works because it is the stack. It's what browsers run. It's what users download. It's powered the web for thirty years and will power it for thirty more, regardless of what framework is trending.

Learn the cascade. Learn the event loop. Learn how the browser paints a page. Learn that fetch is a standard API—you don't need Axios. Then pick up a framework with confidence, not dependence.

The web is built on HTML, CSS, and JavaScript. Everything else is packaging.

ResumeLinkedInx.com
Available for work