“Learn the rules like a pro so you can break them like an artist.” – Pablo Picasso
CSS Implementation & Architecture: How to Know if You’re a Bad Person
In the same way that there’s no wrong way to eat a Reese’s*, we have multiple options when it comes to implementing CSS.
If you’re a malevolent person or you’ve suffered a traumatic cranial injury that prevents you from remembering that we’re now post 1996, then you’re likely partial to <span style=”color: red; text-decoration: underline; morality: none;”>inline styling</span>. Similarly, if you’re a lesser evil but still intent on making life difficult, then you’ve probably done some work with embedded CSS using the <style> tag.
On the other hand, if you’re of sound mind and body, are familiar with the concept of calendars and what they represent, and have no predilection for evil-doing, then you’re likely a proponent of external stylesheets. Furthermore, being the morally fibrous individual you undoubtedly are, you’re probably even in the habit of making sure your CSS is both legible and well organized.
The preferable structuring of sound CSS, or CSS authoring methodologies, is precisely the topic we’ll be covering in this post. As with CSS implementation, there are several methodologies to choose from; they are all geared towards being flexible, reusable, easily manageable, and efficient. However, as we’re dealing with Drupal 8 theming, the methodology we’ll be exploring today is SMACSS.
Laying the SMACSS Down
What It Is
SMACSS, a fun acronym for Scalable and Modular Architecture for CSS, was developed by Jonathan Snook in 2011. SMACSS is not a CSS extension, like Less or Sass, but rather a means of organizing styles rules into five easily identifiable categories. Subsequent class names and directory structures are based on those categories.
Visualization for Stylization via Categorization
While some complexity in styling sites — especially larger sites — is to be expected, at least a portion of that complexity can be avoided by breaking styles into five recommended categories. These categories are base, layout, module, state, and theme. By dividing our style rules accordingly, we develop a better understanding of exactly what it is we’re styling and are able to avoid complications wrought from cross-category stylization.
What’s in a name? A lot, actually…
Naming conventions allow us to quickly determine which category a style belongs to, as well as its role within that category. SMACSS calls for the use of prefixes to easily distinguish rule types. For example, where layout rules are concerned, the prefix ‘l-’ or ‘layout-’ can be used. Modules, which will be the bulk of your project, should simply be referenced by their names, rather than a prefix like ‘module’, as there will be so many. The prefixes you use and module names you pick are entirely up to you, just be sure that they’re both sensical and memorable.
Categories
Base
The base category is for default styles. These curmudgeonly champions of inflexibility (the only inflexibility we’re willing to tolerate in our styling) say, “If this element is present on the page, it better look like this, or else.”
Rules
- Base style rules are there to define just that, the basics, so be sure to define:
- Heading sizes
- Link styles
- Font styles
- Body background**
- Do not use classes or IDs, stick to tag selectors (html, body, a, etc)
- Do not use ‘!important’ tags, they should be completely unnecessary at this stage
Base style rules are there to define just that, the basics. Be sure to include heading sizes, link styles, font styles, and the body background** here. Base style rules should be defined using tag selectors (html, body, a), not classes or IDs. Under no circumstances should you be using ‘!important’ at this stage.
Generally element selectors are used exclusively with base styles (html, body, table, etc), but pseudo-class selectors ( a:hover), as well as attribute, child, and sibling selectors are acceptable if their use is warranted.
Layout
Layout rules segment a page into more manageable sections and work to hold modules together. For example, a <header> section holds the navigation module together. Rules used to describe what the header should look like belong in the layout, while a separate file should be used for rules governing individual modules themselves.
Rules
Layout rules can be broken into two sub-categories, major and minor styles. Major layout styles, like those pertaining to the header and footer, can be styled using IDs. Minor styles come into play when you want to provide your user with certain customization options. For example, if you want your user to have the option of a horizontal or vertical navigation, this can be accomplished by adding an appropriately prefixed layout class capable of changing the display and float properties of a list.
While it is perfectly appropriate to use IDs in order to style layout elements, it is important to note that this is not always the case. The difference in performance between CSS IDs and classes is almost negligible, and the use of IDs can complicate styling due to the increase in specificity. Therefore, the bulk of your styling should be done using classes and subclasses. It is also important to note that ID selectors don’t need to subscribe to the same naming conventions as classes as they are generally descriptive enough on their own. For example, ‘#l-header’ would be overkill.
Module
If base styles are the curmudgeons of our site, then modules are the social butterflies. Modules are the “modular” or reusable bits of our site. Good examples of modules are banners, lists, navigation items, and sidebars. These entities require the most consideration where flexibility is concerned as they should be readily usable throughout a site, regardless of parent elements.
Rules
Modules are the smaller components that make up your page, such as navigation elements, sidebars, widgets, etc. Modules reside within layout elements or within other modules inside layout elements. Modules should be designed as stand-alone entities, able to be moved or implemented anywhere on a site without breaking.
- Avoid using IDs and element selectors, stick to class names
- Element selectors are too ambiguous and general.
- If you have to use an element selector, only do so if it:
- Has a class of its own
- Is a fairly specific element (<header>, <footer>, not <span>, <div>)
- Is within one level of a class selector and can be targeted as a child
- If you have to use an element selector, only do so if it:
- Element selectors are too ambiguous and general.
When styling modules, stick to class names rather than using IDs or element selectors. Element selectors are too ambiguous (ex: <span>, <div>) and IDs are too specific. If you find that you absolutely have to use an element selector, only do so if it has a class of its own, is a fairly specific element (ex: <header>, <footer>), or is within one level of a class selector and can be targeted as a child.
Subclassing
Subclassing modules aids in the elimination of excess specificity. Rather than using parent elements as a means to add/amend styles, a subclass can be applied so that styling doesn’t become too convoluted, specific, or HTML reliant.
The subclassing example provided in the SMACSS book is an excellent one. I won’t replicate it for you here (that’s just silly and redundant), but I will summarize it. Basically, for a module to be truly flexible so that it might be used anywhere on the site, it can’t be dependent on a parent element that might not be found in the same area of the site where you’d like to add a module. To overcome reliance on HTML structure, we used subclasses. Subclasses provide whatever additional style is necessary and are used in addition to the base module class to achieve the desired effect.
State
State rules dictate how a module or layout appears in a particular state. For example, menus that are hidden or expanded, buttons that are clicked or disabled, links that are active or visited, the layout of our pages based on device viewport size, and how modules appearance differs by page or template.
Rules
State styles, though a great deal like module styles, differ from them in two ways. First, state styles can be applied to modules (button is clicked, menu is expanded) or layout styles (width adjusts based on device viewport). Second, state styles are indicative of a JavaScript dependency. For example, a class of ‘.is-hidden’ implies that JavaScript could be used to add/toggle the state so that the hidden element is displayed based on a user interaction. Therefore, state rules depend on both IDs for JavaScript selection and classes to render the appropriate styles.
This is !important
State are used to supplement as well as override other styles, therefore the use of ‘!important’ is not only allowed, but advisable in some situations. Please note that the operative words in the previous sentence are “some situations”, meaning situations in which ‘!important’ is actually necessary; don’t just fling it anywhere. Also, keep in mind that ONLY states should ever use ‘!important’.
States and Modules
In some cases, state rules will have to be made for a specific module. When this is necessary, the state class name should include the module name in it.
-
Example: .is-moduleName-active
This specific state style should also live with the module it pertains to, and not with other more versatile states.
Changing States
State changes are applied in one of three ways via class names, pseudo-selectors, or media queries. If you’re intent on writing good, clean CSS, then it’s highly likely that you’re already familiar with all three of these state-change options; for the sake of being thorough, let’s recap***.
Class name changes are executed with JavaScript. A good example of this is when a user performs an action (mouse click, key press) and a class is swapped or added with JavaScript to make a style change on the specified element.
Pseudo-selector changes can be done without the assistance of JavaScript. These are commonly used with links and are confined to elements that the pseudo-selector directly applies to, their descendents, and siblings.
Lastly, media queries apply styling rules to elements based on device viewport size. An excellent example of this is the way a site’s layout changes to accommodate usability on mobile screen sizes. In some cases, media queries are declared once and all styling that media query applies to is lumped together within it. However, SMACSS recommends that we instead declare media queries as needed with the module they apply to in order to keep all module styling in the same place. Yes, this means we’ll need to declare the same media query multiple times, but it’s a small price to pay for organizational bliss.
Theme
This category isn’t necessarily required, or even commonly used, but it merits mentioning. For example, when building a theme I might want to provide the user with color scheme options. The styles relating to layout, modules, and states would be stored in their respective corresponding stylesheets and directories, while the information relating to color schemes for the theme would be stored in a separate stylesheet.
Say I have a Harry Potter-based theme and I’ve provided color scheme choices based on each of the four wizarding houses. The Gryffindor option would center around shades of gold and red while the Slytherin color scheme would consist of variations of green and black. The theme category rules would allow for our theme structure to remain the same while easily switching the color scheme from Gryffindor to Slytherin, even though you would never actually want to do that because everyone with any sense knows that Slytherins are jerks with bad hair and poor taste in shoes.
In Summation
We’ve covered a lot, but still only really touched on the basics of the SMACSS methodology. For more information and detailed examples, check out the free online SMACSS book. To delve even deeper into SMACSS, once you’ve read the free portion, you can purchase the premium content for $13. I’ve provided a brief summary of the organization rules covered in this post for quick reference.
- Style rules should fall into one of five categories: base, layout, module, state, or theme.
- Base styles should use tag selectors primarily. No classes, IDs, or ‘!important’ allowed!
- Layout styles should be achieved with IDs supplemented by classes. Please note that generally the majority of your styling should be accomplished with classes and subclasses.
- When styling modules, stick to using class names; avoid IDs and element selectors. If you need to override or augment a style, us a subclass rather than a parent element to limit specificity that could cause breakage later.
- States changes can be implemented with class names using JavaScript, pseudo-selectors, and media queries. Module specific pseudo-selectors and media queries should be kept together with the rest of the module style rules. Styling states is the only time it is acceptable to use ‘!important’.
- Theme styles are for changing aspects of your theme like color schemes and fonts, not for influencing structural components.
- To ensure modules are easily usable throughout your site, limit specificity caused by relying too heavily on HTML. Instead, use classes and (when necessary) descriptive HTML5 elements like <header> and <footer> as those will likely only be used once throughout the site.
- Module specific state style rules (pseudo-selectors, media queries) should be kept with the module they apply to, rather than with more general state styles.
In the third installment of Drupal 8 Theming, we’ll be focused on building and editing templates with SensioLabs’ Twig templating engine. Thank you for reading!
*Not true. I think we all know that most appropriate way to eat a Reese’s is to gently chew off all the outer points before carefully cracking the thin layer of chocolate on the top and bottom so the peanut butter center can be wholly extracted . Then eating the chocolate “rind”, as it’s commonly known, just prior to dipping the middle in milk. Alternately, rolling the center into a ball, sticking it to the roof of your mouth, and drinking milk until it dissolves–dealer’s choice. Right? …RIGHT?
**Sometimes the body background-color property is neglected when defining base styles. In neglecting to declare a body background-color, if the user has set their browser background-color to something that clashes with or is too similar to your font color choice, then you may wind up with completely illegible site content.
***Yeah, take that brevity!
Did you miss the first post in this series? Click here!
For the NEXT post in this series, click here.