Architecting Front-end Styles

Architecting Front-end Styles

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.