On Moving to a Utility-first CSS Framework
At Familiar, we’re constantly trying out new tools and processes to stay up-to-speed in the ever-evolving field of web design and development. Recently, we changed the way we approach writing CSS. We transitioned from using Bootstrap for almost all our web projects to a utility-first CSS framework: we experimented with Tachyons before settling in on Tailwind. From a designer’s perspective, here’s a look at why we made the change, some of the benefits and design implications, and the new best practices we’ve instilled.
In addition, to streamlining the handoff process from design to development, the goal in our transition was to find a framework that didn’t impose a default UI on our designs, but still helped execute those designs in an efficient and easily maintainable way. Tailwind provides “highly composable, low-level utility classes that make it easy to build complex user interfaces.”
The intuitiveness of a utility-based framework was greater than expected. Some of the benefits include:
- It’s easier to visualize what something looks like just by reading the markup.
- It’s easier for multiple people to work on the same site at once.
- It’s easier for designers to set design ground-rules clearly and directly in the code, particularly because all of the Tailwind variables are contained within one config file.
- It’s easier to make style updates and create exceptions without worrying about any implications to other parts of the site. This will be particularly handy for long-term maintenance.
- It’s easier for the design team to fine-tune elements that their expertise leads them to be specifically concerned about—typography, color, and spacing.
One of our initial concerns with a utility-first system was in maintaining consistency. For example, the need to define the font family, weight, size, and color of every heading on every template separately leaves the potential for unintentional discrepancies, especially as templates are updated. Keeping the number of styles in check is necessary to achieve hierarchy and maintain a consistent look and feel, both of which are essential to the utility of our client’s sites. Our solution to this is to create components for highly repeated elements as necessary.
As a rule, we create components for Headings 1–6, for elements within rich-text fields in the CMS like inline-links and bold or italic text, and potentially for buttons and form elements. The consistency of buttons and forms styles was one of the greatest strengths of Bootstrap, since they often take many properties to style, especially once you add in hover and focus states. While this was one of our biggest concerns in moving to a utility-first system, using components provides a simple and effective solution.
We also will set default classes on the body for background-color, text-color, font-family and leading. So far this has been enough to achieve a balance between flexibility and consistency.
Another concern we had was how powerful a utility-first system could be. We pride ourselves in successfully implementing creative moments of interactivity, responsiveness, and playfulness in our projects.
Just because it’s fussier to code, doesn’t mean it’s bad design.
Tailwind has a built in solution for this. It easily generates variant classes for breakpoints and pseudo-classes like hover, focus, and my favorite, group-hover. Additional, we can easily add our own utility classes, with these same variants, for things that aren’t built into Tailwind (yet!) such as animations, transitions, transforms, blend-modes, and many other glorious css-properties, including CSS-grid (but more on that in another post).
While the transition to a utility-first system initially started as an experiment in changing our front-end process, it has also had some interesting design implications. In addition to designing the initial look and feel, and key page comps for each project, the design team is also empowered to develop the fully customizable kit-of-parts that power Tailwind.
Breaking apart page comps and larger components into atomic blocks like font-size or colour helps us to be more efficient in the number of full page comps we need to produce, while still consistently scaling out the design language across an entire site or application system. Our entire design team pushes code, not just pixels, so a designer will directly set up these elements of the design system in the Tailwind config file.
While there are currently a surfeit of design system management tools hitting the marketplace, almost all of them are aimed at in-house product design teams. While they’re designed to scale up, the amount of upkeep they involve means they don’t necessarily scale down for smaller teams with a lot different projects going on at once.
By being able to set up the system directly in the code, the config file becomes the tool for maintaining the design system as the single source of truth.
It’s exciting to be liberated from Bootstrap, which imposes a default structure that can subconsciously leach into your designs, and lead to unnecessary similarities across projects. However, regardless of framework, what hasn’t changed is the need for a fastidious eye for detail , and clear lines of communication between everyone involved in order to maintain a high standard final product. It’s been a pleasant surprise how seamlessly the transition to Tailwind has enabled us maintain those standards more efficiently. See it in action on the projects below.