CSS is deceivingly hard.
A frontend developer’s competency is commonly perceived by how close the site build resembles the visual mock-up. However, if we’re working on a large scale project, maintainability and scalability are far more valuable than simply good looks—techniques alone can’t maintain a CSS behemoth.
Through many projects I’ve worked on, a common (and painful) oversight I’ve noticed is the lack of a design system and coherent style guide. Without a solid foundation, we find the project quickly becoming an ordeal to maintain—CSS bloats unnecessarily; new components are loosely bolted to the existing stylesheet; coding style becomes inconsistent and so forth.
Better CSS starts before we code, we need to start from some high-level planning, contemplate on the design, and then architect and build.
Set top-level goals
A sensible first step is to establish top level goals we want our CSS to achieve. 3 common goals I aim for most projects are:
Maintainable CSS has the following qualities:
- An organised structure
- Predictable pattern and consistent methodology
- Well documented.
Overall, it's easy for any developer to join, work on and continuously retain the project’s quality.
The established CSS architecture should be designed to anticipate future growth. Its structure should be flexible, so it’s easy to extend for new features as well as refactor existing code.
Nowadays, responsive web design is the common standard. Moreover, we need to think beyond just screen widths, and focus on how to optimise displaying the content across all devices through our CSS.
Be a designer
Developers are also designers. A solid design system is an invaluable foundation to bridge UX, technology and branding—and developers are vital advocates on the technology side. We should try to participate in the early design discussions to understand the user and business goals, voice our concerns and recommend improvements.
Be empathetic to the end-users
A good design is user-centric. Our understanding of the users should shape our CSS approach. Some examples of things worth considering are:
- How users interact with the UIs to achieve their goal
- The user’s technology/device
- Screen sizes
- Cross browser compatibility
- Operating system
Collaborate with every team member
Different team members have varying levels of direct and indirect influence on the CSS.
The business owner can tell us about future developments for the project—this insight helps us plan for scalability.
The brand or web designers usually hold the source of design elements (e.g. brand colours, typography, size & scale, visual rhythms, etc.) and these elements rely on us to define it in code. It's important to work closely with designers to assimilate the UX artifacts and visual designs, so we can identify common design patterns to integrate it into the CSS.
Working with fellow developers, it’ll be most productive to establish the methodology as early as possible. Agree on the tooling, coding styleguide, naming conventions, architecture, and make sure to document everything for new or third-party developers.
Establish an architecture
In a nutshell, an architecture organises the CSS. We can adopt an existing architectural practice such as ITCSS (my favourite), SMACSS, ACSS, or we can build our own to suit. Regardless of our choice, a good architecture has the following qualities:
It employs a predictable and sensible structure. The stylistic approaches follow logical patterns, and the library of class names are coherent and apparent. This simplifies the development effort to adapt and collaborate.
Modular and scalable
There’s an obvious organisation to group and allocate files. Styles are organised in a streamlined hierarchy with a purposeful inventory of encapsulations.
Adept at handling CSS’s characteristics
It appreciates CSS’s characteristics and promotes good practices. CSS can be frustrating with its declarative nature, how specificity is handled, and dealing with efficiency. A good architecture establishes the coding style guide early and continues to contain the quality.
It works for everyone
Most importantly, the team should be able to agree on the set approach. Try to establish the coding styleguide and structure as early as possible, do invest a generous amount of time to discuss and define the right architecture.
A side point I’d like to quickly touch on is working with CSS Frameworks—my general advice would be to follow the framework’s native paradigm as much as possible.
Make your framework decision early. Plan and think about how it’ll work with the design system and what problems it can solve for you, and if it’ll be easy to maintain and scale well in the long term. If you find it too rigid to augment or scale, then perhaps try lighter frameworks/tools such as Skeleton, Bourbon, Susy etc.
- Design systems
- CSS styleguide and pattern library
- Choose your tools
- Post processor
- Build tools
After all the pre-planning, design and architecture it’s time to pick your weapon and unleash some CSS-fu!
At this stage we understand what we’re going to build so we know how to pick the most fitting tools to deliver. Here are some categories of tools to consider:
Today almost everyone is using CSS preprocessors. They have essential features, such as creating partials to compose the architecture, declare variables for design elements, and provide custom methods and tooling for versatility.
This is a relatively new practice that processes the CSS. As opposed to preprocessors, which deals with another language (that isn’t CSS) and compiles it to CSS, post processors takes the CSS and make it ‘better’ by performing tasks such as:
- Auto prefixing
- Provides fallbacks
- Generate sourcemaps
Developers should be lazy and let automation handle the tedious tasks. Gulp and Grunt are commonly used to automate tasks, including:
- Post processing
- Image optimisation
- CSS and SCSS linting
Visual styleguide/ pattern library
Visual styleguides or pattern libraries act as the ‘source of truth’ for design elements and expresses the design system. These tools are able to demonstrate responsiveness, provides consistency for user experience, readily reusable and easy to maintain.
Techniques and methodologies
There are many CSS techniques that promote good practice. On the flipside, though, many techniques may conflict each other, so it is important to document clearly in the coding styleguide.
It’s always important to consider the pros and cons of the nominated methodologies and how they align with our original top-level goals.
For example, my personal preference is adamantly 0-level nesting. From this, I benefit from minimal style clashing, so it’s easier for my CSS to achieve modularity and scale by easily adding new styles without nesting. However, if we introduce to the project a CSS framework or library that contains nesting, this clashes with my local styles, which defeats my objective and forcing me to compromise and nest.
As a result, I’ll need to weigh the pros and cons, decide which sets of techniques to follow and carry it out throughout the architecture.
Make it work for everyone
Like any fields of web development, good CSS is achieved with a solid plan and steady collaboration with the team. What makes CSS particularly challenging is due to its close ties to many facets of the project—it directly influences the end user's experience; it’s mostly responsible for rendering the visuals; it’s worked on by different people and needs to scale.
To build a successful project, always be mindful of the top-level goals we’ve set, invest generous amount of time early to establish a solid foundation and architecture, and the positive results will naturally follow.
Enough theoretical fluff, so how it actually work?
The next article is a technical step-by-step walk-through on one of my favourite approach to building CSS—Better CSS: Putting it together with Atomic, ITCSS and BEM. Watch this space!