Part III: Component-oriented CSS architecture
When building a large-scale application, structuring the code for ease of extension and maintenance is an important consideration. What people usually forget about is that even a CSS code should be architected properly.
In Exponea, we value the power of fast prototyping a lot; we often encourage people who do not specialize in frontend code to prototype UI. One thing we have been struggling with though is maintaining code quality when moving as fast as we do at Exponea. And how can one keep visual consistency and pixel perfection?
Over time we came up with two answers:
- Component-oriented CSS architecture
- Living documentation in the form of Component Showcase
Design style guides
When it comes to maintaining a visually consistent style, nothing beats project design style guides. These allow developers to navigate through design decisions without having to discuss too much detail with a design team.
However, form matters. A style guide which is maintained only as a picture and thus offers no direct visible connection to the code on a site is of limited use to developers.
That’s why we are putting together a Component Showcase that lives separately from the app and acts as a one-stop shop. Specifically, it:
- Serves as design documentation and the single source of truth in design discussions,
- Steers developers to the correct component,
- Acts as a live example of use on a simple data model,
- Documents the components interface,
- Helps to manually check components during the QA process
That way even people without specialization in frontend technologies can put together a prototype and know it will take only cosmetic changes to become a final production-ready feature.
“Where should I place that CSS code?”
In larger code-bases, the consistency of the code will inevitably suffer over time as new features are implemented and contributors come and go.
In Exponea, many components were architected so that all the code related to a single component was placed in a single directory. But then again, quite a few components did not follow this rule.
Further aggravating things, some component style customizations were scattered over different modules.
Lastly, certain monolithic files did not follow any structure at all.
Making changes in components written in the different styles resulted in marked productivity differences.
It was high time we adopted a CSS architecture and defined style guides.
Component-oriented CSS architecture
Originally we took the best parts of the code structure — component-orientation — and placed it before anything else to write as much code as we could as full-featured components.
However, that’s easier said than done:
- Some parts of the CSS code serve cross-cutting concerns (base styles, resets, layouts)
- CSS in the browsers lacks encapsulation: styles leak from one component to another, especially in the case of nested components
Luckily, when thinking through this problem and putting together a reference to effectively draw on, we discovered the Component CSS architecture (composed from BEM and SMACSS practices).
Not only did Component CSS help us complete the architecture landscape by allocating space for base styles, layouts, and other styles that can’t be simply “componentized”, it also cemented our belief we were moving in the right direction with the CSS stylesheets for components. We discovered that each component consisted of the following parts:
- Root element
- Inner structure
- Modifiers (special variant of the custom element or its state) — Should the component expand to full page width? Is the component open?
- Context (where is the component placed in the component tree) — Does the component need to look different when placed against an unusual background?
This illustration nicely highlights that:
That’s actually very similar to the BEM (Block, Elements, Modifiers) thinking.
By structuring component styles in this way, we placed all the component-related code in a single place, making it straightforward to read the styles.
By way of example, let’s look at the <calendar> component:
Documentation for code consistency
Last but not least, it was necessary to document the CSS code style guides so we could consult the guide for suggestions every time we changed the code, and use the guidelines in the code review process. That largely simplified keeping the code consistent and reliable over time.
Component-oriented CSS in the context of Angular 2
The CSS component-oriented architecture is definitely not the last stop on our journey. In the longer run, we are going to adopt Angular 2 and introduce a great new feature into the ecosystem: inline styles.
In Angular 2, component styles are linked from the component’s interface in the same manner a template is referenced:
As a sweet consequence, our component-oriented architecture is very easy to migrate to Angular 2 and thus, among other things, emulate encapsulation of styles.
This then is what I set out to share with you about our strategy for dealing with component styling, and maintaining consistency in the context of fast development in a large team. Our approach brings not only productivity boost, but also clears the path to Angular 2 for us.
You may have noticed I did not mention our strategy for dealing with the rest of the frontend code. That’s on purpose because we would like to give you an overview of our plans for migration from Angular 1.5 to Angular 2.0 in our next blog in this series. Stay tuned!