Over the past few years, Webflow development has shifted heavily toward strict utility frameworks. The standard rulebook now says every margin, padding, and text style should be built by stacking pre-defined utility classes.
To be fair, these systems solved a real problem. If you run a large agency with ten developers building fifty SaaS landing pages a month, strict guardrails keep junior builders from breaking layouts.
Somewhere along the way, though, a helpful guideline turned into a rigid rule: the idea that if you aren't stacking four or five utility classes on every div, you aren't building "properly." When you are crafting a bespoke site with custom grids and heavy motion, that approach quickly gets in the way.
Here is why a lean, custom class system still works better for high-craft builds and how I structure mine so it stays clean and predictable.
Avoiding "div soup" and Navigator blindness
Utility frameworks promise speed, but on custom layouts, you often pay for it with deeply nested wrapper divs just to handle basic spacing:
<!-- Typical utility-heavy markup -->
<div class="margin-bottom-large">
<div class="padding-global">
<div class="card-wrapper layout-grid-item">
<div class="card-media-ratio-16-9 overflow-hidden">
<img src="..." class="image-cover" />
</div>
<div class="margin-top-small">
<h3 class="heading-style-h3 text-color-primary">Project Title</h3>
</div>
</div>
</div>
</div>In a visual builder like Webflow, the Navigator is your map of the page. When every layer is named padding-global or margin-vertical-xlarge, you can't tell what anything actually is without clicking into it.
The hidden specificity trap
There is also a technical catch that gets overlooked in visual builders: CSS specificity.
Every time you chain combo classes together in Webflow to tweak a style, you are quietly raising that selector's specificity. Once an element carries a three- or four-class chain just to handle basic layout and spacing, trying to override it later with a single utility class won't work. You end up either stacking even more combo classes on top or reaching for !important in custom CSS embeds.
Keeping styles tied to a single, flat component class with at most one modifier keeps specificity low and predictable from day one.
Motion needs stable anchors
When you build interactive sites with GSAP timelines, ScrollTrigger, and custom grids, you rarely stick to neat 8px or 16px intervals. Designs call for asymmetrical columns, custom aspect ratios, and scroll-driven choreography.
Trying to target generic utility classes like .margin-top-small > h3 in JavaScript is fragile. If someone swaps a spacing class in the designer, your animation breaks. Motion works best when it hooks onto clean, dedicated components.
How I structure custom styles instead
Using custom styles doesn't mean going back to messy Div Block 42 chaos. It just means keeping things simple, readable, and intentional:
<!-- Lean, semantic component markup -->
<article class="case-card">
<div class="case-card-thumb">
<img src="..." data-parallax-img />
</div>
<h2 class="case-card-title" data-split>Project Title</h2>
</article>Instead of dozens of atomic helpers, my setup relies on a few straightforward habits:
- Readable component names: Elements use simple, hyphenated names that describe what they actually do (
.navbar→.nav-contain→.nav-link, or.case-card→.case-card-thumb). Anyone opening the Navigator immediately knows what they are looking at. - A few lightweight layout tokens: I keep a small set of global helpers—like
.container, spacing modifiers like.pad-120, and my.main-grid-8layout grid—while letting individual components handle their own internal spacing. - Data attributes for JavaScript: I keep classes strictly for styling, and use
data-*attributes for interactions ([data-split],[data-parallax-img],[data-sfx]). If I restyle a card tomorrow, my GSAP animations keep working without touching a single line of JS. - Simple modifiers over long class stacks: When a component needs a variation or an active state, I scope it cleanly instead of chaining utilities:
.grid-box {
&.type-snake { ... }
&.type-stars { ... }
&.type-odometer { ... }
}
.accordion {
&.active {
.accordion-content { ... }
.accordion-tab svg { transform: rotate(135deg); }
}
}Easier translation to modern code
Because I also build directly in code with frameworks like Astro and React, keeping styles semantic in Webflow means my mental model never has to change. Moving a layout from a visual builder into a clean component file takes almost zero cleanup, and the HTML stays lean and accessible.
Wrapping up
Utility frameworks are great when your main goal is scaling standardised templates across a big team. But web development isn't one-size-fits-all. When you are building something bespoke, a lightweight, custom class system gives you lower specificity, cleaner markup, smoother animations, and way more room to design freely.