Skip to content

🎨 CSS Methodologies - The Great Divide

The Senior Mindset: There is no “perfect” CSS solution—only trade-offs. A senior engineer chooses based on the project’s scale: Tailwind for rapid prototyping and design system enforcement, CSS Modules for zero-runtime overhead, or CSS-in-JS for maximum dynamic flexibility.


Tailwind provides low-level utility classes that you compose directly in your HTML/JSX.

  • How it works: Instead of writing .card { display: flex; }, you write <div class="flex">.
  • Pros:
    • No context switching: You never leave your HTML file.
    • Bundle optimization: Tailwind purges unused CSS, leading to tiny, static CSS files (usually < 100kb).
    • Design Tokens: Forces you to use a predefined scale for colors, spacing, and typography.
  • Cons: “Class soup” can make HTML look messy; learning curve for specific utility names.

The “standard” approach for many large-scale applications. It uses standard CSS but scopes class names locally to the component.

  • How it works: You import a .module.css file. The build tool (Vite/Webpack) renames .button to something unique like .Button_module_abc123.
  • Pros:
    • Zero runtime cost: It’s just a plain CSS file served by the browser.
    • Standard CSS: Use all native features like Nesting, Variables, and Media Queries.
    • Isolation: No more “Global Scope” collisions where one developer’s .header breaks another’s.
  • Cons: You still have to manage separate files for logic and styles.

Styles are defined using tagged template literals directly within your JavaScript files.

  • How it works: You create a component like const Button = styled.button and define its styles there.
  • Pros:
    • Dynamic Styling: Easily change styles based on props (e.g., <Button primary="{true}">).
    • Dead Code Elimination: If you delete the JS component, the CSS is deleted automatically.
    • Theming: Built-in support for switching themes (Dark/Light mode).
  • Cons: Runtime Overhead. The browser has to execute JavaScript to generate and inject CSS into the DOM, which can impact performance in high-frequency UI updates.

FeatureTailwindCSS ModulesStyled Components
PerformanceBest (Zero runtime)Excellent (Zero runtime)Moderate (Runtime cost)
Type SafetyRequires pluginsVia Typed CSS ModulesNative (via Props)
Developer SpeedVery High (once learned)ModerateHigh
Learning CurveModerate (Utility names)Low (Standard CSS)Low (Template literals)
Design SystemBuilt-in via configManual via variablesHigh (via ThemeProvider)

Even with Tailwind, don’t let your components grow into 50-line class strings.

  • Senior Move: Use the cva (Class Variance Authority) library. It allows you to define “variants” for your components (e.g., size: "sm" | "lg", intent: "primary" | "danger") in a structured way that works perfectly with Tailwind or CSS Modules.

2. Native CSS Variables (Custom Properties)

Section titled “2. Native CSS Variables (Custom Properties)”

Regardless of the methodology, use native CSS variables for your Design Tokens.

  • Strategy: Define --brand-primary: #007bff; in a :root selector. This allows you to update the color in one place and have it reflect across Tailwind, CSS Modules, and even legacy code simultaneously.

Stop relying solely on the viewport size.

  • The Shift: Use Container Queries (@container). This allows a component to change its layout based on the space available in its parent container, rather than the whole screen. This makes components truly “pluggable” in any layout.

💡 Seniority Note: Before picking a tool, check your Target Browser support. If you are building for ultra-low-end devices, the runtime cost of CSS-in-JS might be too high. If you are building an enterprise dashboard with thousands of developers, the strict constraints of Tailwind might be your best friend to prevent “CSS Bloat.”


  • [[Frontend-Design-Systems]]
  • [[Optimization-Web-Performance]]
  • [[Frontend-Frameworks-Architecture]]