In any large scale project CSS can often be put on the back burner while some of the more “important” features of the project are built out. In reality, CSS can make or break your site (literally!). You may be thinking “it’s just CSS – it can’t be that hard” but when building an enterprise level site, a well thought out CSS design can save you a tremendous amount of time in the future. For the sake of this post, we’ll assume you have a basic understanding of CSS and a basic understanding of AEM component development.
Selectors are arguably the most important concept to grasp in modern CSS, even more than styling. Without selectors, there isn’t a “cascading” part of the style sheets. Incorrect selectors can cause even more problems. A general rule of thumb is to use about 2-3 selectors, and no more than 6. Too few selectors, and your CSS will likely affect more elements than intended. Too many, and your CSS becomes limited, confusing, and difficult to maintain.
Thus, the number one rule for selectors is:
Select classes at the lowest level, and make them as specific as possible, while still being reusable.
Otherwise, you’ll often find your CSS more difficult to maintain, and sometimes it’ll even have unintended consequences on other parts of your site. Just because CSS is loaded for a specific component, does not mean that it will not affect other elements on the same page.
This typically means we should try to:
- Design global site-level defaults
- Design CSS at a component level
- Override on a page-by-page basis as necessary
- Avoid #id selectors in CSS (limited reusability)
A general rule for making the component reusable across pages, is to rely on classes only present in the component itself. Rarely is there a guarantee that your wrapper class will always be the same, especially in future reuse cases. In AEM, this includes the generated wrapper and its classes, as the classes will change based on the “path” specified in the include statement. Exceptions include tightly coupled wrapper classes (I want a different style if the component is in this wrapper), and implementing CSS for a specific component instance, where you’re usually better off with page-specific CSS.
Why is that? Preferring page-specific CSS imports vs. instance-specific:
- The CSS itself is more specific (Which page is this limited CSS pointing to again?)
- Less confusing from a context standpoint (Where is this class in the component? Oh, it’s in some wrapper or parent that is not tightly coupled.)
- Much easier to maintain (If the parent class or layout on the page changes, then you have to refactor CSS.)
- Global default style
- AEM design-level CSS defaults
- Component CSS defaults using only markup in the component
- Tightly-coupled components CSS defaults
- Page-level/page components CSS defaults
- CSS for specific component instances (usually with loosely coupled wrapper)
Overriding CSS will typically follow this order as well, where the lower levels override the ones above them.
A well planned and thought out CSS design is just as important as any other part of your site, and is a major contributor to the success or failure of a project. When dealing with complex sites, you should really take the time to sit down and think about a strategy for your CSS, while keeping the above-mentioned points in mind.
Make sure to be on the lookout for part 2 of this blog post, where we touch on accessibility, selector priority, and how to better organize your CSS.