title: "CSS Framework" page: css-framework section: Styling parent: Styling parent_href: /docs/css-framework

CSS Framework

what.css is a utility-first CSS framework with semantic components, dark mode, and cascade layers. Your CSS always wins — no !important needed.

Overview

Every wwwhat project includes what.css automatically. It uses four cascade layers in this order:

@layer base, utilities, components, interactions;
LayerContains
baseReset, CSS variables, theme tokens
utilitiesSpacing, layout, typography, colors
componentsButtons, cards, forms, tables, alerts
interactionsModals, drawers, tooltips, transitions

Because all framework styles live inside @layer, any CSS you write without a layer declaration automatically takes precedence. Override anything without fighting specificity.

Utility Classes

Spacing

Margin and padding use a numeric scale: 0, 1 (0.25rem), 2 (0.5rem), 3 (0.75rem), 4 (1rem), 6 (1.5rem), 8 (2rem).

PatternExampleResult
p-{n}p-4padding: 1rem
px-{n} / py-{n}px-6padding-left: 1.5rem; padding-right: 1.5rem
m-{n}mt-8margin-top: 2rem
gap-{n}gap-4gap: 1rem
space-y-{n}space-y-4margin-top: 1rem between children

Display & Layout

<div class="flex items-center justify-between gap-4">
  <span>Left</span>
  <span>Right</span>
</div>

<div class="flex-col space-y-2">
  <p>Stacked vertically</p>
  <p>With spacing between</p>
</div>

Available: flex, grid, block, inline-flex, hidden, flex-col, flex-wrap, flex-1, items-center, justify-between, justify-center, self-center.

Typography

ClassEffect
text-sm, text-lg, text-xl, text-2xlFont size
font-bold, font-semibold, font-mediumFont weight
text-center, text-rightAlignment
truncateOverflow ellipsis
uppercase, capitalizeTransform
text-mutedMuted color (gray-500)

Colors

Text, background, and border colors follow the same naming pattern:

<p class="text-primary">Primary text</p>
<p class="text-danger">Error text</p>
<div class="bg-gray-100 border border-gray-200 rounded-lg p-4">
  Subtle background with border
</div>

Available color groups: gray-{50-900}, primary-{50-900}, success, warning, danger, red, green, yellow, blue, indigo.

Component Classes

Buttons

<button class="btn btn-primary">Save</button>
<button class="btn btn-outline">Cancel</button>
<button class="btn btn-danger btn-sm">Delete</button>
<button class="btn btn-success btn-lg btn-block">Submit</button>

Variants: btn-primary, btn-secondary, btn-success, btn-warning, btn-danger, btn-outline, btn-ghost, btn-link. Sizes: btn-sm, btn-lg, btn-xl. Modifiers: btn-block, btn-icon, btn-loading.

Cards

<div class="card">
  <div class="card-header">
    <h3 class="card-title">Title</h3>
  </div>
  <div class="card-body">Content here</div>
  <div class="card-footer">Footer</div>
</div>

Variants: card-elevated, card-flat, card-bordered, card-interactive, card-horizontal. Sizes: card-sm, card-lg. Colors: card-primary, card-success, card-warning, card-danger.

Forms

<div class="form-group">
  <label class="form-label">Email</label>
  <input type="email" class="form-input" placeholder="you@example.com">
  <span class="form-hint">We'll never share your email.</span>
</div>

Input classes: form-input, form-textarea, form-select, form-control (universal alias), form-checkbox, form-radio, form-switch. Helpers: form-label, form-group, form-error, form-hint. Sizes: form-control-sm, form-control-lg. Validation: is-valid, is-invalid, invalid-feedback.

Tables

<div class="table-container">
  <table class="table table-striped table-hover">
    <thead><tr><th>Name</th><th>Role</th></tr></thead>
    <tbody><tr><td>Alice</td><td>Admin</td></tr></tbody>
  </table>
</div>

Alerts

<div class="alert alert-info">
  <div class="alert-content">
    <div class="alert-title">Heads up</div>
    <p class="alert-description">This is an informational message.</p>
  </div>
</div>

Variants: alert-info, alert-success, alert-warning, alert-danger. Sizes: alert-sm, alert-lg.

Grid System

CSS Grid utilities for column layouts:

<div class="grid grid-cols-3 gap-4">
  <div class="card card-body">One</div>
  <div class="card card-body">Two</div>
  <div class="card card-body">Three</div>
</div>

<!-- Spanning columns -->
<div class="grid grid-cols-4 gap-4">
  <div class="col-span-2">Wide column</div>
  <div>Normal</div>
  <div>Normal</div>
</div>

<!-- Responsive: 1 col on mobile, 3 on desktop -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
  <div>Card</div>
  <div>Card</div>
  <div>Card</div>
</div>

Available: grid-cols-1 through grid-cols-6, col-span-1 through col-span-3, col-span-full.

CSS Variables

The entire framework is built on CSS custom properties. Override them to customize your theme:

static/styles.css
:root {
  /* Brand colors */
  --w-primary-500: #8b5cf6;
  --w-primary-600: #7c3aed;
  --w-primary-700: #6d28d9;

  /* Typography */
  --w-font-sans: "Inter", sans-serif;

  /* Spacing scale */
  --w-spacing-4: 1.25rem;

  /* Component-specific */
  --w-btn-radius: 9999px;
  --w-card-radius: 1rem;
}

Key Variable Groups

GroupVariables
Colors--w-primary-{50-900}, --w-gray-{50-900}, --w-success-*, --w-danger-*, --w-warning-*
Semantic--w-bg, --w-text, --w-border, --w-surface, --w-muted
Typography--w-font-sans, --w-font-mono, --w-text-sm through --w-text-5xl
Spacing--w-spacing-{0-24}
Components--w-btn-*, --w-card-*, --w-alert-*, --w-modal-*, --w-input-*, --w-table-*

Dark Mode

Dark mode works two ways:

Automatic — Follows the OS/browser prefers-color-scheme preference. No setup required.

Manual — Add class="dark" to the <html> element. Use class="light" to force light mode and override OS preference.

<!-- Force dark mode -->
<html class="dark">

<!-- Force light mode (even if OS is dark) -->
<html class="light">

Theme Toggle

A common pattern for user-controlled dark mode:

<button onclick="toggleTheme()">Toggle Theme</button>

<script>
  // Restore preference on load
  (function() {
    var theme = localStorage.getItem('w-theme');
    if (theme === 'dark') document.documentElement.className = 'dark';
  })();

  function toggleTheme() {
    var isDark = document.documentElement.classList.contains('dark');
    document.documentElement.className = isDark ? 'light' : 'dark';
    localStorage.setItem('w-theme', isDark ? 'light' : 'dark');
  }
</script>

Dark mode automatically adjusts semantic tokens: --w-bg, --w-text, --w-border, --w-surface, and --w-muted all change to dark-appropriate values.

Responsive

Responsive variants follow a {breakpoint}:{class} pattern:

PrefixBreakpoint
sm:640px
md:768px
lg:1024px
xl:1280px
<!-- Stack on mobile, row on desktop -->
<div class="flex flex-col md:flex-row gap-4">...</div>

<!-- 1 column on mobile, 2 on tablet, 3 on desktop -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">...</div>

<!-- Hide on mobile -->
<nav class="hidden-mobile">Desktop navigation</nav>

Convenience classes: hidden-mobile (below 640px) and hidden-desktop (640px and above).

Customization

Add your own stylesheet after what.css. Thanks to cascade layers, your rules take priority without !important:

site/index.html
<link rel="stylesheet" href="/static/what.css">
<link rel="stylesheet" href="/static/styles.css">
static/styles.css
/* These override framework styles automatically */
.btn {
  border-radius: 9999px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.card {
  border: 2px solid var(--w-primary-200);
}

/* Add new component styles */
.pricing-card {
  background: linear-gradient(135deg, var(--w-primary-50), var(--w-white));
  border: 1px solid var(--w-primary-200);
  border-radius: var(--w-rounded-xl);
  padding: 2rem;
}
Tip: You can also override by setting CSS variables on the component class: .btn { --w-btn-radius: 9999px; }. This changes the variable the framework uses internally, keeping all other button styles intact.