Even though CSS is relatively easy to write, it can be quite hard to maintain. The specificity, the global scope of everything, and the lack of guidance can easily lead to inconsistency, code duplication, and over-complication.
I’ve long been curious what a really well-documented CSS codebase looks like. Here, I’ll share my experience, along with the expectations I have towards my vision of well-documented stylesheets.
It surprises me where I hear people say that commenting CSS is not that important. I imagine none of them have had to deal with 10,000+ line stylesheets! Often I’ve struggled with what HTML results in what specific style. Without having a solid context about the development decisions taken, debugging efforts increase. WTFs per minute increase exponentially too.
Many times I’ve spent hours to figure out what the developer intended, why she didn’t do it the another way, why is this layout seemingly so complex. There is much pain buried in these “why” questions.
So, here we go! Let’s examine the 4 big signs of a well-documented CSS codebase.
1) CSS Tech Stack & Toolchain
There are likely things as part of our CSS code base like third-party libraries, mixins, or other tools. Looking in the package manager’s dependencies list doesn’t give a lot of context why the decisions were made to add these things, what they do exactly, and how we’re using them.
It would be good for everyone to know why a certain library or tool was introduced. Imagine, for example, that a third-party library was introduced only to solve what has become an obsolete CSS issue. If we had context like that, we could make more informed decisions.
There sometimes can be quite a few third-party libraries in a project. Have you ever spent a bunch of time on web searching each one figuring out what it even is? It can be quite a challenge to know or to keep track of what each exactly does.
A well-documented codebase would include a description for each dependency. Perhaps you could include a tweet-length (140 characters) code comment explaining why it is there. That would give anyone else in the code base a head start on why something is there.
I like adding these descriptions right in the place where I
2) CSS Conventions
Good coding conventions result in consistent, readable, and unambiguous source code. They standardize the structure and coding style of an application so that you and others can easily read and understand the code.
It’s important to know if there are any project-specific naming conventions or methodologies in place (like BEM, OOCSS, SMACSS, or ACSS). I’ve seen cases where a certain methodologies principles are applied but the actual rules followed are modified based on the preferences of the developers involved. So an indication how strictly we must follow the methodology principles would be good to leave in a well-documented code base.
This brings up the larger issue of CSS style guides. A naming convention is just one choice as part of a complete styling strategy. Other parts might be:
- How is code sectioned?
- How are files structured?
- How are properties ordered?
- How is commenting done?
- How is the formatting done (indentation, rule declarations)?
- … and many more rules or anti-patterns like nesting more then 3 levels deep, avoiding ID selectors, using !important only for utility classes and etc.
All this makes up a complete CSS style guide. Having a shared vocabulary like this I’d consider a strong plus towards consistency.
3) CSS Architecture
Most scalable projects follow some type of architecture in terms of ordering styles. In a well-documented codebase, the fundamental principles that the project follows when structuring and sectioning styles should be mentioned.
I was first inspired to explore CSS architecture by watching Harry Roberts’s talk about managing CSS projects. Here’s Harry:
CSS architecture seems to be somewhat in vogue right now. It’s something you’ve no doubt heard mentioned numerous times over the past year or so, and with good reason: UIs (and the teams that build them) are getting bigger and more complicated than ever before.
There are a number of aspects of CSS which make it troublesome. It’s declarative, meaning there is no logic or control flow to tell other developers much about the state or construction of the project. It operates in a global namespace, meaning we get collisions, leaking styles and inadvertent regressions. It utilizes inheritance, making everything somewhat interdependent and brittle. Finally, the unavoidable specificity model can cause problems when selectors fight each other for prominence.
Therefore, he introduces a concept for architecting CSS called ITCSS. If you are working on a project of reasonable scale, chances are someone already defined similar principles or ideas that aim to resolve these problems. So in a well-documented codebase, I would expect to see them written somewhere.
One could tell if the architecture is explained well enough if you can answer the following question: Where should new styles or stylesheets be added?
4) CSS Component Descriptions and Examples
A common pattern is to separate the logical modules into CSS components (or “blocks” according to BEM). Some of them might be re-usable, some may not, but the important thing is that they are the building blocks of our project. Therefore, describing what they are should be a top priority in a well-documented codebase.
Ideally, you should arrange and group them, name them, and establish rules between them to generate an overview of all components. A well-described CSS component doesn’t only include information about what the component does but also has other valuable intel like example HTML markup and the context in which it’s meant to be used. Going one step further brings up the issue of Pattern Libraries. A pattern library is a collection of reusable components that can be used together to create a website. With modular, component-based architecture becoming a trend, they can bring huge value.
The goal of a pattern library is to show what can be built with existing patterns (components). But let’s take a look at what additional information can be displayed alongside each pattern also. Vitaly Friedman shared a good summary on how taking the pattern library to the next level looks like. He states that focusing on components isn’t good enough:
One of the main problems with pattern libraries is that, while they provide an overview of components, they often leave a lot open to interpretation. Components can be combined in a variety of ways, consistently and inconsistently. It’s great to be able to see what button variants and iconography are available and what kinds of tables and pricing tags one may use, but what if you need to design or build an interface that contains all of these components at once — and perhaps another that doesn’t yet exist in the library?
A list of modules alone wouldn’t convey any context or any specifics on how the modules should (and should not) be used.
Based on Vitaly’s post and Brad Frost’s anatomy of a pattern in a pattern library, here are a few ideas I can imagine each of our patterns (components) could have, despite the usual unique name, code sample and a description of the component’s purpose. Basic (fundamental):
- Tags or categories: The assigned tags or categories for the component. Developers could tag their components with “in use”, “needs refactoring” tags and etc.
- Responsive preview: A real-life, resizable preview of the component, using the actual snippet of code being used in production. Alternatively, just a screenshot.
- Versioning and legacy, team members involved or responsible: In a bigger team, the ownership of the (family of) components and which team members have been actively developing them could be really helpful for maintenance and further development.
… and here are a few more advanced:
- Performance impact: Sometimes CSS could be heavy too. An indicator of performance or a “warning signs” section, outlining not only performance impact but also any common mishaps when the pattern is used incorrectly.
- Accessibility implications: Indicator of accessibility requirements. Some components might require more work to maintain accessibility, especially if they interact with other components.
- Related patterns: A quick overview of related components or the family of components that a given component belongs to. Could use an explanation of when to use a component, when not to, and why.
- Fallback and print previews.
… the list goes on and on to whatever makes sense for your specific use-case.
A well-documented CSS codebase enforces consistency, boosts maintainability, and helps the team to build a shared vocabulary. It is a prerequisite for efficient CSS design and development. Moreover, based on my experience, it inevitably leads to better performance. I strongly believe that these are the signs of the professional execution of a project.
If you have thoughts, please feel free to add them in the comments below, so together we can come closer to better documentation practices.
I follow all the advice and suggestions from http://codeguide.co/ (created by MDO – co-creater of Bootstrap). Lots of great info on there for developing flexible, durable, and sustainable CSS.
Also rscss (check rscss.io) has a good explanation about page components and their inner contents and I have been following it for a while now as it is very similar to the way I built websites before using only pure CSS.
Using a folder structure similar to ITCSS to help organize SASS files makes it a joy to work with, both in small and very very large projects.
It’s not really about following one rule or the other, is about thinking of every element group in a website as an individual and reusable component. This will make the code base DRYer and keep everyone’s sanity safe.
A historical note, there had been efforts like CSSDOC , too, that came with some good ideas. I’m not sure what happened to the project and whether or not it got folded into something bigger.
I’ve been working with web components more and more and I love the way it lets you handle some of these issues. I generally have a file for page layout, a file for page appearance (h1-6, p, a, etc. defaults), and the rest is handled by each component itself. Each page is a new webcomponent so I also have page specific styles that only get loaded when a page is loaded.
The site I’m currently working on is built with Polymer and utilises components for each section of the UI. It became clear the header element which is included in most pages didn’t quite work for the changing requirements of the project. Making the required changes was a simple matter of redesigning the local markup, updating the local styles, and then adjusting the JS to connect the existing interface with the new UI. Everything was in that single header.html file and every page continues working as intended. Drastic changes to a key element made simple by taking an object oriented approach and keeping the CSS and JS scoped.
Regarding nr. 1, if it’s an open source project, then maybe the commit that introduced the dependency can explain why it was added. That would be a good way to provide this type of information without having to maintain it in the docs.
Hey, thanks for taking the time to write this! I think a few examples/snippets of CSS would make this article even better
Nice article. I was also inspired by Harry Robert’s talk an year ago and since then I am trying to to write my CSS and to teach my colleagues how to write their CSS into more scalable and readable, through the power of architecture, conventions and documenting.