This post is about getting along with your code, making site maintenance enjoyable, and how modular front-end code can help solve your web site woes.
Modularizing your front-end code can be a great way to make the daunting task of building and maintaining a giant site a lot more manageable. In a nutshell, this means grouping elements of your site into small, contained, reusable chunks. Getting started with building modular code is fairly simple, but the details of implementation vary.
What is a Module?
First, it’s good to clarify what is meant by a module. A module is a unique element that has a specific set of functionalities and is not tied to the layout of a website. Wherever the module resides on the site, it has the same general sub elements and functionality. A module is not a header, footer, sidebar, etc. These are strictly layout items.
A common example of a module is a form. Most websites have at least a contact form and often other types of forms – event registration, help request, etc. In general, all of these forms look and perform quite similarly. Because of this, we group the styling and functionality together as a module.
Why Use Modular Code?
Before writing even a line of code, print out all of the designs and put them side by side. You’ll save yourself a great deal of headache if you do a lot of upfront planning. Ideally, modular architecture is a philosophy that is understood and preached from the start of site planning, but you’ll probably need to make your own interpretation of the designs either way.
Start by locating all of the main layout elements, and note every variation from the norm. It’s easy to identify parts like header and footer, but often the “main” area is broken up in unique ways. Hopefully most parts are consistent throughout, but come up with logical names for each part and variation. I usually use “content_primary,” “content_secondary,” and so on for the main area and avoid names like “content_left” or “content_right” since those have little semantic meaning beyond their appearance on one screen.
Once you’re finished with the layout, move on to the modular level. The toughest part is straddling the line between too general and too specific when naming modules. Because we want our styles to be reusable, we want to apply fairly general class names that make sense in any context they are applied. However, making the class names too general reduces semantics and can make working with variations difficult – if it feels like a stretch, it might be time for a new module. You’ll probably rename and reorganize modules throughout the process. That’s why it’s important to look at the whole picture before jumping into coding.
Once you have a broader view of the site and its components, you might consider pointing out minor differences between module-level items to the designer and asking if the differences could be reduced or eliminated.
Consider the following two variants:
Building the Front-end
With planning out of the way, you can start coding. Since the HTML and CSS are so closely linked, we’ll cover them together.
For a long time, my only tool was a text editor, and it’s still my most important, but it gets difficult to maintain dozens of static files while I’m doing my job. Making a few small changes in the footer and header becomes rather tedious. I recommend looking at some of the awesome front-end development tools/static site generators that have been popping up recently. Mixture is a promising commercial tool that just went beta, but there are a lot of great and actively-maintained Open Source, usually command line, tools, such as Middleman, DocPad, and several others.
Most of these tools handle the compiling of Sass, Coffeescript, and other languages, and provide fairly advanced templating functionality to keep your files DRY (non-repetitive). They also start up a server right on your computer to preview the site as you build, and many provide live-reloading so changes are reflected immediately after saving a file.
I recommend building out one page completely and then start pulling it apart to define your main layout and any partials. Using conditionals, you can adjust states on navigation items, page backgrounds, and more, without having to create an entirely new file.
Writing the CSS
Our approach to CSS at TBG is mostly adopted from SMACSS (Scalable and Modular Architecture for CSS), by Jonathon Snook. I highly recommend reading his book if you’re looking to improve your CSS skills. Using Sass as our preprocessor, we divide up our style sheets into the following general structure.
- main.min.css (automatically generated via Sass)
- main.scss (where we @import all of our Sass files)
Files preceded by an underscore indicate that they are hidden/to be imported into another file. In this instance, we will be importing all of our style sheets into main.scss, which will then be compiled and minified into main.min.css.
All of our modules are broken into separate files within the modules folder, and everything else can be defined as either a base rule or layout rule. You may find other rules necessary (such as states or themes), depending on the application, but these work most of the time.
The base style sheet defines default styles for basic, non-classed elements, such as paragraphs and headings. It also includes global helper classes that are usable on almost any element, and global Sass mixins (colors, media queries, etc.).
Layout rules include the styles for all of the core containers on the site (header, footer, main, sidebar, etc.), as well as any reusable styles that pertain specifically to how an element or its children are stacked/positioned. We prefix these reusable styles with an “l-” to make their purpose and location very clear. Some examples of these reusable styles include “l-stacked,” “l-grid” and “l-inline.”
One of the great benefits about using Sass is that you can define all of your media queries in one style sheet (base.scss), using mixins, and then use the mixins in all of the other style sheets. This way all of the styling for your module, including media queries, can always be found in the same style sheet. If you need to change a breakpoint, you only need to adjust it in one place. Let’s take a look at what our contact form style sheet might look like:
One of the easiest ways to get tangled in a sloppy mess of CSS is by making selectors overly specific. Notice how there isn’t a single child selector in the above example. A child selector in CSS targets elements within other elements – “.content p” selects all paragraphs within elements that have the class “content.” Reducing the number of nested selectors leads to faster rendering, reduces specificity (a good thing), and makes styles significantly easier to reuse. If we had chosen to use a child “input” selector in the above example, we would have ended up applying those styles to every input, including submit inputs, something we probably didn’t mean to do. To get around that, we would have to either explicitly state every type of input it should be applied to, or override the default behavior. It’s better to apply the specific class to only the HTML elements that need to appear that way. By writing CSS using only class names and very few type selectors (input, label, p, etc.), we can easily apply classes to any element without writing extra CSS.
It isn’t always possible to apply class names to everything, such as when content is entered through a rich text editor. My general rule is to avoid nesting selectors any more than 2-3 levels deep and use direct descendant selectors (example: .content_primary > p) whenever possible, to avoid having unexpected children elements unnecessarily inherit CSS.
Also, avoid using IDs within CSS if at all possible. IDs are too specific and the speed of modern rendering engines makes any performance benefit unnoticeable. It also limits you to one use of that module per page. One other point is to only use “!important” when it makes absolute sense (!important indicates that the attribute’s value should override everything except inline styles). I try to limit my use of “!important” to element states, such as “collapsed,” that need to overwrite styles in order to work.
To recap, here’s a basic rundown of writing modular CSS:
- Use a preprocessor, such as Sass, to keep files small, easy to find, and easy to maintain.
- Organize CSS by type: base, layout, modules, and optionally states and themes.
- Prefix reusable layout styles with “l-” to make them easy to find.
- Define all of your media queries in one location, but keep all module-specific CSS contained within that modules Sass/LESS file.
- As much as possible, only style classes, not types or IDs.
- Use classes generously in the HTML.
- Avoid child selectors as much as possible. When you have to use child selectors, use the direct descendant selector (>) and avoid nesting more than 2-3 levels deep.
- Only use “!important” when it makes absolute sense.
Learning how to modularize your front-end can pay off in a big way. The extra work you go to in the beginning leads to a much cleaner code base that is easy to maintain for a long time. Because it’s designed to be scalable, it works on sites large and small. Read about other approaches to building with modular code and come up with a solution that works and makes sense to you.