Over the years, I've often relied on frameworks to provide a base of styles, be it Foundation, Bootstrap or even a custom framework. As adoption for modern browsers grew and with technology like CSS Grid and Flex becoming more powerful, I wanted to drop a lot of the bloat that the framework provided that I just wasn't using.
I ended up creating a custom framework that just provided a small set of starter files in SASS, that handled everything that most every project requires, including:
- Reset
- Typography scale
- Buttons
- Form elements
This provided me with a lighter set of starter files that worked well, but still felt quite heavy and intense. I wanted to abstract all components away, to just rely on a set of CSS files that provided the groundwork and foundations for me to build upon. I also decided I wanted to document and utilise a consistent naming technique and styling framework that enforced more consistency. Heavily inspired by Andy Bell, I decided to come up with something that feels more targeted for the projects I take on. I call the approach BEMU.
BEMU - Block, Element, Modifier, Utility
I decided to define a set of principles for my CSS layout. Let's break it down:
Putting the BEM into BEMU
BEM has been popular amongst us front-end developers for years. It works well at scale and I've been a huge fan for a number of years. I have found some developers can over-use and over-think it's usage, so I always stick to a few principles.
Only nest one-level deep
// Incorrect
.card__header__title {
display: flex;
}
// Correct
.card__header .card__title {
display: flex;
}
Keep modifiers simple and flexible
Modifiers can get messy very quickly. I try to make sure modifiers are used for valid reasons, if a utility doesn't suffice. I generally only use modifiers if a specific component has a variation that's unique to that element, e.g.:
.card {
width: 18rem;
}
.card--large {
width: 36rem;
}
I also use data attributes to manage things like state, for example:
<div class="alert" data-state="active"></div>
This provides a clear separation of concerns, and easier state management when thinking about JS. It also gives us a model of consistency in terms of how state can be managed, and how it compares to modifiers.
Utilities
Utilities are something that I've only recently began using, but they've been a revelation to how fluid and flexible my CSS has become. It's allowed me to write more consistent, reusable code that feels a lot cleaner and agile. I break my utilities up into two main areas.
Design Tokens
Design tokens are mainly generated through Goron. These utilities are defined in a config file, and automatically created in both helpful HTML classes, as well as CSS variables. This allows me to set out things like colors, type scale, fonts, spacing, alignment and a bunch more per project. This gives me a scaffolding to convert a design into a design system, to start thinking about how I can create reusable elements like background colors, text colors etc. This allows me to create very flexible HTML components, like so:
<p class="color-gray"></p>
<div class="bg-gray"></div>
As well as some reusable CSS variables:
.card {
color: var(--color-gray);
}
Now, this may seem a bit like Tailwind CSS. But, with the BEM mentality, it allows me to create a consistent set of components, that can be manipulated by utilities to become flexible. I can lay ground rules that apply to all variants of a card component for example, and then change things on a per component basis, say a background color on text color, like so:
<div class="card"></div>
<div class="[ card ] [ bg-gray ]"></div>
<div class="[ card ] [ bg-red ]"></div>
'What are the square brackets?' I here you ask... Well, they're a way of separating utilities from BEM, to keep a clear separation of concerns. It helps me defined what every card has, and what is a variation of a card. It also helps me think about when I may need to use a modifier, too.
Helpers
Every project has a few requirements that I generally use on all projects. This includes:
- Type scale powered by Utopia for a type scale that is fluid and responsive.
- CSS Reset for consistency and in all honesty, just makes life easier. Things like
prefers-reduced-motion
and resettingul, ol
that have classes are a god-send. It's well worth checking out. - A wrapper to contain content.
Wrapping Up
Everyone has their own methods in terms of what works for them, but the changes this year have really helped me to deliver better products that are lighter, more agile and feel higher quality. It's also allowed me to make use of CSS variables, and drop things like SASS compiling. I feel more lightweight, more vanilla and I'm really enjoying front-end work.
I've open sourced my starter framework, and it's called Blyth. I've also got an 11ty version, Blyth for 11ty, too.