Modularizing Your Front-End Code for Long Term Maintainability and Sanity

March 25, 2013 | Matt Diehl

Modularizing Your Front-End Code

This post is about getting along with your code, making site maintenance enjoyable, and how modular front-end code can help solve your website woes.

Give anyone a week or two, and they can learn how to write HTML, CSS, and a bit of JavaScript. I love that it’s that easy, even if it makes my job seem simple. Like a lot of things today, building a small, functional website isn’t that hard if you have a little patience and know how to use Google. But bump the size of that website up to say, 40 variants, each with their own unique elements and functionality, share the code with a bunch of other developers, and then have them (and any new hires) all actively maintain it for six plus years. It’s not easy.

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?

Any developer who needs to make a change to the contact form should be able to find the exact CSS and JavaScript they need to work on within seconds. This is because each module should have its own CSS (or Sass/LESS) file that contains all of the applicable styles and media queries, and an equivalent JavaScript file (if necessary). By containing almost all of the styling and functionality within these separate files, developers should be able to know exactly what effect changing one line of CSS or JavaScript should have on the rest of the site.

Getting Started

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:

Events and News Variants

One is an events listing, with event dates in the left column, and title, place, and short description in the right. The next is a news listing; it also has a date in the left column, and in the right column, it has a news headline, introductory text, and news type. At the top of both variants is a filter bar. We could make these two separate modules, called “events_listing” and “news_listing,” but we’d end up duplicating a lot of CSS, and potentially JavaScript. Naming the module “filtered_listing” allows us to group the core styles and functionality together in a way that works for both items and could also be reused later on if the company wants to add, for example, a filterable job listing. Variations can be handled either by using a modifying class or by using different children elements.

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 (The Berndt Group) 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.

-  css/

  • min/

    • main.min.css (automatically generated via Sass)

  • sass/

    • modules/

      • _buttons.scss

      • _contact_form.scss

      • _slider.scss

      • _another_module.scss

    • _1.base.scss

    • _2.layout.scss

    • _3.modules.scss

    • 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:

https://gist.github.com/matt-diehl/5178112

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.

Writing the JavaScript

Break out your JavaScript files similarly to your CSS. Hopefully, it won’t be necessary to have an equivalent JavaScript file for every module used on the website, but the same rules apply. Place module-neutral functionality in a base JavaScript file and all modules in their own file. If JavaScript is necessary for the layout (but hopefully it isn’t), make a layout.js.

Just as it should be easy to determine where a module’s CSS file lives, it should be equally as easy to determine if a module has JavaScript dependencies, and if so, where those dependencies exist. Find a way that makes sense to you to distinguish JavaScript selectors from your general CSS selectors. I prefix elements that have JavaScript listeners with “js-”. This way, if I come across a class in some HTML called “js-contact_form-submit,” I can instantly know its function and where to edit it.

There are a number of design patterns in JavaScript, but of particular use to us is the module pattern, which provides a way of encapsulating all of the functionality of a module. To do so, we define an auto-executing function named after our module and encapsulate all of the necessary variables and functions within it. The following is a very basic example of this:

https://gist.github.com/matt-diehl/5188186

You’ll want to concatenate your various JavaScript files, just like we did with our CSS. This can be a little bit trickier than with Sass, but fortunately many of the tools I mentioned have utilities for doing this as well.

Conclusion

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.

About the Author

Matt
Matt Diehl

When I'm not making websites at TBG as a Senior Front-end Developer, I'm often making sites at home, learning more about building them, or playing guitar in a dingy basement in Paul Newman and the Ride Home.

Leave A Reply

comments powered by Disqus