A Framework That Puts User Preferences First

Most CSS frameworks are built around the needs of developers. Halfmoon, an open-source framework that launched last year as a Bootstrap alternative with built-in dark mode, takes a different approach: it’s designed to let both developers and end users customize their experience.

“One size does not fit all” is the core philosophy here. Roughly half the population prefers dark UIs, while the other half prefers light. People have wildly different preferences when it comes to font sizes, spacing, and contrast. These variations matter most for tools and dashboards—interfaces people spend hours using to get work done. A UI that adapts to individual needs isn’t just a nice-to-have; it’s a productivity feature.

Built Entirely on CSS Custom Properties

Halfmoon is written using over 1,500 global CSS variables. This isn't merely a handful of color tokens—nearly every aspect of the framework’s design can be overridden, from spacing and border radii to component-specific values. Because it relies on native CSS custom properties rather than preprocessor variables, there’s no build dependency required.

The advantage over Sass or Less variables is significant. Preprocessors lock you into their toolchain. CSS variables work anywhere, with any stack. They can also be set and changed at runtime with JavaScript, which makes them ideal for user personalization.

There is, of course, a balance to strike. Creating variables for everything can make maintenance difficult. The lesson isn’t that every possible value should become a variable—it’s understanding how much flexibility you truly need to provide.

Choosing the Right Components

Defining what to include in a framework means making tradeoffs. Halfmoon includes most components you’d find in Bootstrap or Bulma, but its niche focus on dashboards and tools shaped several additions:

  • Five sidebar types with built-in toggle and overlay handlers—sidebars are common in dashboards and notoriously tricky to implement.
  • Two navbar varieties, including one pinned to the page bottom, useful for contextual action buttons (like bulk actions on selected table rows).
  • Omni-directional dropdowns across 12 placements.
  • A built-in keyboard shortcut system with a straightforward registration API.
  • Responsive utility classes sufficient for most use cases without needing a utility-first framework.

Some conveniences are notably absent: tabs, list groups, and spinners are scheduled for the next release (v1.2.0). Other features like carousels and tree navigation are considered out of scope for now. Upcoming plans also include a form validator, multi-select component, date/time picker, and data-table component.

Why User Personalization Matters

Operating systems have long let users set theme preferences, font sizes, and display densities. The web still lags behind. Browsers offer zoom, but it rarely saves settings or scales content predictably.

Personalization on the web can take several forms, each addressing a common usability gap:

  1. Selecting between light and dark modes, ideally respecting the OS-level preference automatically.
  2. Setting a default font size that persists across sessions—the ability to adjust readability matters more than aesthetic perfection.
  3. Adjusting the compactness of elements, similar to how Gmail lets users choose between spacious and dense inbox layouts.
  4. Choosing a primary color for buttons and links; purely cosmetic, but it creates a sense of ownership.
  5. Enabling high contrast mode, so users who need stronger foreground/background separation aren’t stuck with insufficient default contrast ratios.

Highly customizable frameworks make all of this trivial to implement. Since CSS variables can be updated at runtime via JavaScript, a user’s choice in a range slider or dropdown can set a variable’s value, save it to localStorage or a cookie, and restore it when the page loads.

For example, hitting the compactness toggle updates just two variables:

  • --content-and-card-spacing, from 3rem to 2rem
  • --card-border-radius, from 0.4rem to 0.2rem

Realistically, a single dropdown with “Default” or “Compact” options could drive those changes, giving users immediate visual feedback.

Distinct Looks, Not Templates

A frequent complaint about frameworks like Bootstrap is that everything built with them looks identical. Encouraging user-level customization is one step toward solving that problem. If core variables are meant to be overridden, websites built on the same framework won't all collapse into a single visual identity.

It’s not about exposing every knob, however. Knowing who the framework serves clarifies which settings matter. For tools and dashboards—where users spend sustained, focused time—personalization is a legitimate UX requirement.

Future plans include a high contrast user preference, additional templates and themes, and tools to make implementing these features easier for developers—no build system required, no lock-in beyond vanilla HTML, CSS, and JavaScript.