The way that I’ve written front-end stylesheets overtime has constantly evolved. I have found myself settling into a particular pattern of how I write stylesheets and how I think about the front-end. Under this philosophy front-end stylesheets can be broken into four major categories: base, components, patterns, and views. Each is a definable part of the project overall styles, and each has their own corresponding directory.
On a bit of a side note it can be very valuable to think of the naming conventions you use and the way you architect stylesheets as two different things. Naming conventions easily fall into the realm of aesthetic preference and tend to correspond more directly to an author’s way of thinking and personal style. Once the personal artistic license of naming systems is put to the side, it becomes much more possible to speak in a broad sense about building a systemic approach to constructing front-end styles.
If this architecture is addressed separately, it is much easier to talk about how front-and styles interact with one another in a structured and definable way. The front-end architecture could be defined as the ways in which design elements and visual components are extracted into their most basic bits and pieces, and how they interact with each other as they grow in complexity on the page. Similar to how atoms combine into molecules and ultimately organisms, I start my front-end styles with the most basic building blocks and grow outward in complexity.
/base
is the set of core elements. These are anything that is defined by HTML
itself including <body>
<p>
<a>
and <img>
. Base also includes any
non-rendering sass including mixins and functions. It’s important to note that
anything contained within this folder directly references the HTML tag and does
not include classes. The decision to not include classes is a bit of a line in
the sand, but it is a clear heuristic that doesn’t require second guessing.
After /base
, the next level of complexity is /components
. When populating the
components directory, these are stylesheets that include singular modular items.
Often, these are common elements like an .alert
, .subheader
, .button
, or
.badge
. While a component can have a state like warning or super tall, (a b.e.m.
example might look like .button--disabled
) the one thing that they don’t have
is a parent-child relationship. Another line in the sand, but it is easy to
determine “Is this an independent object, or is this a collection made of a
bunch of parts and pieces?”
If the object you are making is comprised of multiple objects, then it goes in
/patterns
, the next step in complexity. The patterns directory is reserved for
objects that have children, whom they effect. An example of this would be a
.hero-header
which could contain the .hero-header__title
and
.hero-header__description
. Patterns can also contain components within them,
and may elaborate the styles defined earlier in the components directory. This
is why the directory structure is so important. It allows objects to be
redefined or elaborated upon, without the need of higher levels of class
specificity. Like /components
, /patterns
can also have modifier states
that modify their appearance or structure such as --warning
or --banana
.
The last directory contains views. In an ideal world this directory stays empty
forever. This directory exists for styles specific to a single view that affect
multiple patterns within them. Definitions here are so specific that it is
nonsensical or even destructive to try to abstract them into a pattern.
Sometimes including it in the views folder can be more clear when looked at my
future developers. If a bunch of patterns I have created all have an alternate
state that says --homepage
, it is in fact less clear than if all those
modified styles were included after the patterns directory, and expressly showed
that the intent was for them to only appear in such away on a singular page.
This approach can also help to ensure that when overly specific and esoteric
code is written, it can be more easily identified, refactored, and destroyed.
Storing some styles here can also help protect components and patterns from
having so many modified states that they become meaningless.
Reduce, reuse, recycle
These concentric rings of complexity can have a positive influence on the code base as well as the design. While a design may be created as a holistic composition, it’s ultimately going to be broken down into a series of smaller and smaller parts. Having a file structure and technical approach that mirrors this process of refinement can help with design and achieve a greater level of simplicity and consistency, while also meaning that the code base continues to be manageable and scalable overtime.
As each design is abstracted into a pattern, it becomes easy to see where consistent components can be extracted out of multiple patterns. They can then become a single element with a higher usability and a lower specificity.
Overtime, as more and more design and visual styles are incorporated into the
project, /views
, /patterns
, and /components
can continue to broken down into
smaller and smaller bits. This ensures that the visual design of a project can
continue to evolve and incorporate new features and aesthetics without having to
section portions of the website or code base off from each other.
Illustration by Qian Sun.