Writing CSS has changed a lot in the last few years. Browsers now ship nesting, container queries, :has() and modern colour functions, and the popular tools have been rebuilt around them. This guide compares three current approaches (Tailwind CSS v4, Open Props and CUBE CSS) and shows the native features worth using.
Tailwind v4 is configured in CSS instead of JavaScript and builds much faster than v3. Open Props gives you design tokens as plain CSS variables without a framework, and CUBE CSS is a methodology for teams that want structure without lock-in. Whichever you pick, the output is ordinary CSS that you build on your computer and upload to any hosting.
1. The landscape today
| Approach | Bundle size | DX | Learning curve | Fit |
|---|---|---|---|---|
| Utility-first (Tailwind v4) | Small; only classes you use | Excellent | Moderate | Product teams |
| Design tokens (Open Props) | Small; import only the parts you need | Good | Low | Designers who like pure CSS |
| Modular architecture (CUBE CSS) | Varies | Great long-term | High initially | Long-lived projects |
| CSS-in-JS (styled-components etc.) | Runtime cost | Good | Moderate | React-heavy SPAs |
| Vanilla CSS + modern features | Smallest | Depends | Low | Small sites |
No single answer. Small marketing site? Vanilla CSS. Product UI with a team? Tailwind or CUBE. Design system? Open Props.
2. Tailwind v4: what's new
Tailwind CSS v4.0 was released in January 2025 and is the current major version:
- Faster builds: a new engine (partly written in Rust) that the Tailwind team reports is several times faster than v3 for full builds, and far faster for incremental ones
- Zero config for most projects — no
tailwind.config.jsneeded, works with@import "tailwindcss" - CSS-first configuration — customise in CSS, not JS config file
- Container queries built in
- Auto content detection — scans your HTML/JS/TS without the
content:array - Native CSS cascade layers used for predictable specificity
Setup (Vite project)
npm install tailwindcss @tailwindcss/vitevite.config.ts:
import tailwindcss from '@tailwindcss/vite';
export default {
plugins: [tailwindcss()],
};src/app.css:
@import "tailwindcss";
/* Customise inline — no separate config file */
@theme {
--color-brand-50: oklch(0.98 0.02 260);
--color-brand-500: oklch(0.6 0.2 260);
--color-brand-900: oklch(0.2 0.1 260);
--font-sans: "Inter", sans-serif;
--spacing: 0.25rem; /* default spacing unit */
}Use in HTML:
<button class="bg-brand-500 text-white px-6 py-3 rounded-lg hover:bg-brand-900">
Click
</button>v4 migration from v3
npx @tailwindcss/upgradeThe upgrade tool (it needs Node.js 20 or later) rewrites most of your config and templates. Check these by hand afterwards:
ringnow defaults to 1px (it was 3px); usering-3for the old look.bg-opacity-*is gone; use the slash syntax, for examplebg-black/50.- Some scales were renamed: the old
shadow-smis nowshadow-xs, androunded-smis nowrounded-xs. - Borders and rings now default to
currentColorinstead of grey. - The
space-y-*selector changed;flex flex-col gap-4is usually the cleaner replacement. - Plugins are loaded in CSS, for example
@plugin "@tailwindcss/forms";.
3. Open Props: design tokens as CSS variables
Open Props is a set of CSS files full of custom properties (variables). There's no framework, and you can use it with or without a build step.
npm install open-props
# or link it from a CDN such as unpkg@import "open-props/style";
@import "open-props/normalize";
.card {
background: var(--surface-2);
padding: var(--size-fluid-3);
border-radius: var(--radius-3);
box-shadow: var(--shadow-3);
color: var(--text-1);
}
.button {
background: var(--blue-6);
color: white;
padding: var(--size-2) var(--size-4);
border-radius: var(--radius-2);
transition: background var(--ease-3) 150ms;
}
.button:hover {
background: var(--blue-7);
}Includes:
- Colours (a palette of hues and shades; the normalize file adds light and dark surfaces)
- Spacing (fixed and fluid sizes)
- Shadows
- Border radius
- Animations and easings
- Gradients
- Custom media queries such as
--md-n-above. These are not variables:@media (--md-n-above)needs a build step such as PostCSS with postcss-custom-media
No class pollution — just tokens. Pair with your own selectors or other frameworks.
4. CUBE CSS: architecture without a framework
CUBE = Composition, Utility, Block, Exception. A methodology, not a library.
The four layers
- Composition — global layout rules (macro level)
- Utility — single-purpose classes for small adjustments
- Block — named components with their own styles
- Exception — rare one-off overrides via data-attributes
Example folder structure
styles/
├── composition/
│ ├── stack.css /* vertical rhythm */
│ ├── cluster.css /* horizontal groups */
│ ├── sidebar.css /* content + sidebar layout */
├── utilities/
│ ├── color.css
│ ├── text.css
│ ├── spacing.css
├── blocks/
│ ├── card.css
│ ├── nav.css
│ ├── form.css
├── exceptions/ /* data-state overrides */
├── tokens.css /* CSS custom properties */
└── main.css /* imports all */Stack (composition primitive)
.stack {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.stack > * + * {
margin-block-start: var(--space-m);
}<section class="stack">
<h1>Welcome</h1>
<p>Article content…</p>
<button>Read more</button>
</section>Every direct child gets consistent spacing. No per-component margin tweaks.
Block (component)
.card {
background: var(--surface-2);
padding: var(--space-m);
border-radius: var(--radius-3);
}
.card__title {
font-size: var(--font-size-3);
font-weight: 600;
}
.card__body {
color: var(--color-text-2);
}Exception (state overrides)
[data-state="open"] { display: block; }
[data-state="closed"] { display: none; }
[data-loading="true"] .card { opacity: 0.5; pointer-events: none; }5. Modern CSS features worth using
Container queries
.card-grid {
container-type: inline-size;
}
.card {
padding: var(--space-s);
}
@container (min-width: 600px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
padding: var(--space-m);
}
}Responsive based on parent size, not viewport. Killer for reusable components.
:has() — parent selection
form:has(:invalid) button[type="submit"] {
opacity: 0.5;
pointer-events: none;
}CSS nesting (native)
.card {
padding: var(--space-m);
& h2 {
font-size: var(--font-size-3);
}
&:hover {
transform: translateY(-2px);
}
}No preprocessor needed.
color-mix() and oklch
:root {
--brand: oklch(0.6 0.2 260);
--brand-lighter: color-mix(in oklch, var(--brand) 70%, white);
}oklch gives perceptually-uniform colors — no more "muddy" gradients.
@scope
@scope (.card) {
h2 { color: var(--brand); }
}Styles only apply inside the scope, which is cleaner than BEM naming for component isolation. @scope is now in current versions of Chrome, Edge, Safari and Firefox, but older browsers lack it, so check your audience's browsers before relying on it.
6. Which to choose?
7. Migration tips
From Bootstrap → Tailwind
- Replace grid classes:
col-md-6→md:w-1/2 - Forms: use the
@tailwindcss/formsplugin (@plugin "@tailwindcss/forms";in v4) - Components: build your own; copy from ui.shadcn.com (free)
From CSS-in-JS → vanilla + tokens
- Extract colors, spacing, fonts to CSS variables
- Move component styles to CSS files
- Tree-shake styled-components/emotion packages
8. Hosting a modern CSS site on Domain India
Tailwind, Open Props and CUBE CSS all produce plain CSS files. Run the build on your own computer or in CI, then upload the output (for example Vite's dist/ folder) to public_html with the File Manager or FTP. Nothing needs to run on the server, so this works on cPanel hosting and DirectAdmin hosting. For WordPress or Laravel themes, build the CSS locally too and upload the compiled file with your theme. Shared hosting already compresses CSS for you, so there's nothing extra to switch on.
9. Common pitfalls
@apply sparingly).text-red-500!); use it sparingly.open-props/normalize, Tailwind's Preflight or a similar reset. Browsers differ more than you think.FAQ
Tailwind or vanilla CSS for small site?
For <10 pages with no team: vanilla CSS + Open Props is faster to write and understand. Tailwind shines when you have many pages or components to keep consistent.
Does Tailwind v4 work with WordPress / Laravel / Rails?
Yes — it's a CSS tool, framework-agnostic. Configure the build step to watch your templates.
Performance impact of Tailwind?
Tailwind generates only the classes you use, so production CSS is usually small, often smaller than a full Bootstrap stylesheet. Check your own build output to be sure.
Should I use CSS-in-JS in 2026?
Declining trend. Modern browser features (scoping, nesting, container queries) + vanilla CSS + tokens cover most cases without runtime cost.
Dark mode implementation?
color-scheme: light dark + prefers-color-scheme media query. Use CSS variables; flip values in @media (prefers-color-scheme: dark). Tailwind v4's dark: variant follows prefers-color-scheme by default, and you can switch it to a class or data attribute with @custom-variant.
Ready to publish your site? Upload the built files to cPanel hosting or DirectAdmin hosting. Questions about your plan? Open a support ticket.
Modern CSS builds to plain files that run on any Domain India hosting plan.
See hosting plans