Modern CSS, No Build: How 37signals Ships Complex Apps with Vanilla Styles

Added Dec 4, 2025
Article: PositiveCommunity: NeutralMixed
Modern CSS, No Build: How 37signals Ships Complex Apps with Vanilla Styles

37signals built three substantial apps with vanilla CSS and no build tools, relying on modern features like custom properties, nesting, container queries, :has(), and CSS Layers. Their simple, flat architecture with semantic components, OKLCH colors, ch-based spacing, and additive utilities proves maintainable and powerful. The article urges teams to reconsider defaulting to Tailwind or preprocessors and to embrace native CSS where it suffices.

Key Points

  • Modern CSS features (custom properties, nesting, container queries, :has(), layers, color-mix(), clamp) remove the need for preprocessors and many build-time tools.
  • A flat, file-per-concept architecture plus semantic component classes keeps CSS maintainable while utilities remain additive and minimal.
  • An OKLCH-based color system and color-mix() enable robust theming, effortless dark mode, and dynamic palettes without duplication.
  • Content-driven layout uses ch units and character-based breakpoints to make responsiveness semantic and typography-aligned.
  • :has() and CSS Layers are game-changers—:has() enables declarative stateful styling, and layers resolve specificity without order hacks.

Sentiment

The HN community is cautiously positive about the modern CSS capabilities highlighted in the article, but skeptical of the broader claim that vanilla CSS is all you need for complex applications. Practical experience—multiple commenters describe eventually returning to React+Tailwind—tempers enthusiasm, and a substantive debate over CSS cascading versus Tailwind's utility model reveals a real philosophical divide rather than clear consensus.

In Agreement

  • Modern CSS features like custom properties, :has(), container queries, and OKLCH color have eliminated many historical pain points that drove developers to preprocessors and frameworks.
  • Frameworks introduce complexity, fragility, and supply chain risk; building directly on the web platform is a legitimate and simpler strategy for many teams.
  • The :has() selector and CSS custom properties together handle many state-styling patterns that previously required JavaScript.
  • Using character units (ch) for responsive breakpoints is a clever content-driven technique that adapts naturally across font sizes and device contexts.

Opposed

  • In practice, managing styles, templates, and controllers across separate files creates friction and magic-string dependencies without compile-time safety, as multiple teams discovered before returning to frameworks.
  • CSS cascading is a fundamentally problematic default for complex UIs; Tailwind's utility-class approach solves real developer pain around co-location, class naming, verbose selectors, and safely deleting unused styles.
  • The article's comparison of Tailwind to vanilla CSS is misleading because it omits Tailwind's component model, where reusable styles live in framework components rather than repeated utility classes.
  • Producing good-looking designs from scratch with vanilla CSS requires both discipline and design skill, making it less accessible for developers without a strong design background.
Modern CSS, No Build: How 37signals Ships Complex Apps with Vanilla Styles | TD Stuff