css in depth

By Keith J. Grant

Just what is Modular CSS? Read this article and find out!

Save 37% off CSS in Depth with code learncss at manning.com.

Base styles: laying the groundwork

Before you dive into writing modular styles you need to set up the environment. Every stylesheet begins with a set of generic rules which apply to the whole page and this is necessary with modular CSS. These rules are often called base rules, because they lay the base upon which the rest of your styles are built. This portion of the stylesheet isn’t modular, per se, but it lays the groundwork for the modular styles that follow.

Let’s create a new a page and stylesheet, and apply some base styles. Add listing 1 to the CSS. This is an example of some base styles.

Listing 1 Some base styles

  
 :root {
   box-sizing: border-box;                     ❶ 
 }
  
 *,
 *::before,
 *::after {
   box-sizing: inherit;                        ❶ 
 }
  
 body {
   font-family: Helvetica, Arial, sans-serif;  ❷ 
 }
  

❶   Box sizing

❷   Default font size for the page

Other base styles typically include link colors, heading styles and margins. By default, the <body> has a small margin, which you may wish to zero out. Depending on the project, you’ll want to apply styles for form fields, tables, and lists.

Tip I recommend a library called normalize.css. This is a small stylesheet that helps even out some discrepancies between the user agent stylesheets of various browsers. You can download it from https://necolas.github.io/normalize.css/. Add this before your stylesheet as part of your base styles.

Your base styles should be generic. Only add styles here that you want applied to most, or all, of the page. There should be no class names or ids in your selectors; only target elements by their tag type and the occasional pseudo-class. The idea is that these styles provide the global look you want, but are easy to override later when you need to.

Once your base styles are set on a project, they rarely change. They provide a stable foundation upon which you can build your modular CSS. After your base styles, the rest of your stylesheet consists mainly of modules.

Building a module

Let’s create a simple module. This is used for brief notification messages. Each module needs a unique name, and we call this one a “message.” We’ll give it a bit of color and a border to draw the user’s attention, as shown in figure 1.


Figure 1 A message module


The markup for this module is a single div with a “message” class (listing 2). Go ahead and add this to your page.

Listing 2 Markup for a message module

  
 <div class="message">
   Save successful
 </div>
  

The CSS for this is one ruleset. It targets the module by its class name. Then it defines a padding, border, border-radius, and the colors. Add listing 3 to your stylesheet, below the base styles.

Listing 3 The message module

  
 .message {        ❶ 
   padding: 0.8em 1.2em;
   border-radius: 0.2em;
   border: 1px solid #265559;
   color: #265559;
   background-color: #e0f0f2;
 }
  

❶   Target the message module by its class name

This may seem like nothing special at this point; you should be familiar with all of these properties. Let’s evaluate what makes this modular.

It’s important that the selector for this module consists only of the single class name. Nothing else in the selector restricts these styles to a certain place on the page. In contrast, using a selector like #sidebar .message means this module can only be used inside a #sidebar element.

Without this restriction, the module is reusable in any context. By adding this class to an element, you can reuse these styles to give user feedback on form input, provide noticeable help text, or draw attention to a legal disclaimer.

By reusing the same module, you produce a consistent user interface. Everywhere you use it looks the same. You won’t have a slightly different teal color in some places or a slightly larger padding in others.

I’ve worked on projects where the CSS wasn’t modular. In one, a series of similar buttons appeared throughout the app. There was a .save-form button and a .login-form button and a .toolbar .options button. The same code was repeated multiple times in the stylesheet, though they were imperfect copies of one another. Some had a slightly different padding or a brighter color of red. The intent was to have a consistent experience, but slow evolution over time introduced changes that didn’t propagate to every instance of that button.

The solution was to refactor it into a single reusable module that worked regardless of its location on the page. By creating a module, it ensured not only simpler code (less repetition), but also visual consistency. It looked more professional, less quickly thrown together. At a subconscious level, this helps users trust your app.

Variations of a module

Consistency is good, but sometimes you want to intentionally deviate from it. Our message module is nice, but we might need it to look different under certain circumstances. For instance, if we need to display an error message, perhaps it should be colored red rather than teal. Perhaps we want to distinguish between messages that are purely informational and those indicating a successful action, such as saving. We do this by defining modifiers.

Create a modifier by defining a new class name with the module’s name. For instance, an “error” modifier for the message module might be “message-error.” By including the module name, you clearly indicate that this class belongs with the message module. A popular convention is to use two hyphens to indicate a modifier: message--error.

Let’s create some modifiers for our module. Listing 4 defines three modifiers. Add this to your stylesheet.

Listing 4 Message module with modifier classes

  
 .message {             ❶ 
   padding: 0.8em 1.2em;
   border-radius: 0.2em;
   border: 1px solid #265559;
   color: #265559;
   background-color: #e0f0f2;
 }
  
 .message--success {   ❷ 
   color: #2f5926;
   border-color: #2f5926;
   background-color:  #cfe8c9;
 }
  
 .message--warning {   ❸ 
   color: #594826;
   border-color: #594826;
   background-color:  #e8dec9;
 }
  
 .message--error {     ❹ 
   color: #59262f;
   border-color: #59262f;
   background-color:  #e8c9cf;
 }
  

❶   Base message module

❷   “Success” modifier changes message to green

❸   “Warning” modifier changes message to yellow

❹   “Error” modifier changes message to red

The modifier styles don’t need to redefine the entire module. They only need to override the parts they change. In this case, this means changing the color of the text, border, and background.

To use a modifier, add both the main module class and the modifier class to an element (listing 5). This applies the module’s default styles, and then allows the modifier to selectively override them where needed.

Listing 5 An instance of the message module with error modifier applied

  
 <div class="message message--error"> ❶ 
   Invalid password
 </div>
  

❶   Add both classes to the element

Likewise, add the “success” or “warning” modifier when you need to use those versions. These modifiers change the colors of the module, but others could change the size or even the layout of a module.

Let’s create another module with some variants. We’ll make a button module with variants for large and small sizes, as well as some different color options (figure 2). This way, you can use color to add some visual meaning to the button. Green indicates a positive action, such as saving or submitting a form. Red indicates a warning, to help prevent the user from accidentally clicking a cancel button.


Figure 2 Buttons with various size and color modifiers applied


The styles for these buttons are shown in listing 6. This has the main button module, as well as four modifier classes: two size modifiers, and two color modifiers. Add these to your stylesheet.

Listing 6 Button module and modifiers

  
 .button {            ❶ 
   padding: 0.5em 0.8em;
   border: 1px solid #265559;
   border-radius: 0.2em;
   background-color: transparent;
   font-size: 1rem;
 }
  
 .button--success {    ❷ 
   border-color: #cfe8c9;
   color: #fff;
   background-color: #2f5926;
 }
  
 .button--danger {     ❸ 
   border-color: #e8c9c9;
   color: #fff;
   background-color: #A92323;
 }
  
 .button--small {      ❹ 
   font-size: 0.8rem;
 }
  
 .button--large {      ❺ 
   font-size: 1.2rem;
 }
  

❶   Basic button styles

❷   Green “success” color variant

❸   Red “danger” color variant

❹   Small variant

❺   Large variant

The size modifiers work by setting a smaller or larger font size. Changing the font size adjusts the element’s em-size, which in turn changes the padding and border radius without having to override their declared values.

Tip Always keep all the code for a module together in the same place. Your stylesheet will mostly consist of a series of modules, one after another.

With these in place, the author of the HTML has some options to choose from. They can add modifier classes to change the size based on the importance of the button or they can choose a color to suggest contextual meaning to the user. Listing 7 shows some HTML mixing and matching of modifiers to create various buttons. Add this anywhere in your page to see them at work.

Listing 7 Using modifiers to create various types of button

  
 <button class="button button--large">Read more</button>              ❶ 
 <button class="button button--success">Save</button>                 ❷ 
 <button class="button button--danger button—small">Cancel</button>   ❸ 
  

❶   Button module with “large” modifier

❷   Button module with “success” modifier

❸   Button module with “danger” and “small” modifier

The first button here is large. The second has the green “success” coloring. The third has two modifiers: one for color (“danger”) and one for size (“small”).

The double-hyphen syntax may seem a little odd. The benefit becomes more apparent when you start creating modules with longer names, such as nav-menu or pull-quote, or adding a modifier to these produces class names such as nav-menu--horizontal or pull-quote--dark.

The double-hyphen helps clarify, at a glance, which part of the class is the module name and which part is the modifier; nav-menu--horizontal indicates something different than nav--menu-horizontal. This can add clarity in projects with a lot of modules that have similar names. This notation has been popularized by a methodology called “BEM”.

Don’t write context-dependent selectors

Imagine you’re maintaining a website that has dropdown menus which are light colored. One day your boss tells you that the dropdown menu in the page header needs to be inverted to be dark with white text.

Without modular CSS, your first inclination is going to be to target that particular dropdown using a selector that looks something like this: .page-header .dropdown. Using that selector, you’d override the default colors applied by the “dropdown” class.

With modular CSS, this is strictly forbidden.

While using a descendant selector works now, this approach leads to many problems down the road. Let’s consider the ramifications.

First of all, you must decide where this code belongs. Should it go with the styles for “page-header” or those for “dropdown”? If you need to modify these styles later, will you remember where you placed them? After adding enough single-purpose rules like this, the stylesheet turns into a haphazard list of unrelated styles.

Second, it has incrementally increased the selector specificity. When situations arise where you want to make further changes, you’ll need to meet or exceed this specificity.

Third, you might need this dark dropdown in another context. The one you created is bound to the page-header. If you want another dark dropdown in a sidebar, you’ll need to add new selectors to the ruleset to make it match both scenarios, or duplicate the styles entirely.

Finally, it produces longer and longer selectors, which bind the CSS to a particular HTML structure. If you’ve a selector like #products-page .sidebar .social-media div:first-child h3, that ruleset is tightly coupled to a specific place in a specific page.

These issues are at the root of many frustrations developers have concerning CSS. The longer a stylesheet is used and maintained, the worse they become. Selector specificity continually ratchets higher as new styles are needed to override old ones. Before you know it, you’re writing a selector with two ids and five classes to target a checkbox. Rules become hard to find as individual elements are targeted by pieces of code in multiple disparate parts of the stylesheet. It becomes more and more difficult to understand the organization of the stylesheet and how it’s doing what it does to the page. Hard-to-understand code means bugs become more common. Selectors are long, which tightly couples the CSS to a particular HTML structure. Even the tiniest changes to the page can break a huge portion of its styling. Deleting old code becomes unsafe, because nobody really knows what it does and whether it’s still important. The stylesheet grows in length and the problems compound.

These are the problems that modular CSS seeks to prevent. Never use descendant selectors to alter a module based on its location in the page.

When you need a module to look or behave differently, create a modifier class that can be applied directly to the element. Instead of writing .page-header .dropdown, write .dropdown--dark.

This way, the module, and only the module, is in charge of its own appearance. No other module may reach into it to make changes. The dark dropdown isn’t bound to any deeply-nested structure in the HTML, and you can place it anywhere in the page where you need it.

Following this one rule is the best thing you can do to prevent your stylesheet from ever descending into the madness of unmaintainable code.

Modules with multiple elements

The two modules we’ve built this far—message and button—are nice and simple; they only consist of one element. But many modules you build will need more than that. You can’t build a dropdown menu or a modal with only one element.

Let’s build a more complex module. This is shown in figure 3.


Figure 3 Media module made with four elements

This consists of four elements. It has a div container that includes an image and a body. Inside the body is the title. As with our other modules, we’ll give the main container a class name matching the name of the module (media). For the image and the body, we’ll use the class names media__image and media__body. These begin with the module name, followed by a double-underscore, then the name of the sub element. This is another convention from BEM methodology. As with double-hyphen modifiers, it tells you at a glance what role the class name plays and what module it belongs to.

Following these naming conventions, the rules for a media module are shown in listing 8. Add these to your stylesheet.

Listing 8 Media module with sub elements

  
 .media {             ❶ 
   padding: 1.5em;
   background-color: #eee;
   border-radius: 0.5em;
 }
 .media::after {      ❷ 
   content: "";
   display: block;
   clear: both;
 }
  
 .media__image {      ❸ 
   float: left;
   margin-right: 1.5em;
 }
  
 .media__body {       ❸ 
   overflow: auto;
   margin-top: 0;
 }
  
 .media__body > h4 {  ❹ 
   margin-top: 0;
 }
  

❶   Main container

❷   Clearfix

❸   “image” and “body” sub elements

❹   The title within the body

You’ll notice we didn’t have to use many descendant selectors. The image is a child element of the media, and we could use the selector .media > .media__image. But that’s not necessary because the name of the module is already in the “media__image” class; it’s guaranteed to be unique.

I used a direct descendant combinator for the title. I could use the class “media__title” (or even “media__body__title” to fully indicate its position in the hierarchy), but I find this isn’t always necessary. In this case, I decided the <h4> tag is descriptive enough to indicate the title of the media module. This does preclude us from using different headings (<h3> or <h5>) for a media title. If, in your modules, you don’t like a restriction like that, use a class name to target the element instead.

The markup for this module’s shown in listing 9. Add this to your page.

Listing 9 Markup for a media module

  
 <div class="media">
   <img class="media__image" src="runner.png">  ❶ 
   <div class="media__body">                    ❷ 
     <h4>Strength</h4>                          ❸ 
     <p>
       Strength training is an important part of
       injury prevention. Focus on your core&mdash;
       especially your abs and glutes.
     </p>
   </div>
 </div>
  

❶   Image sub element

❷   Body sub element

❸   Title sub element

This is a versatile module. It works inside container of multiple sizes, growing naturally to fill their width. You can put multiple paragraphs inside the body. You can use it with larger or smaller images (though you might want to consider adding a max-width to the image to prevent it from crowding out the body).

You can also create variations. It’s trivial to make a version where the image floats right instead of left (figure 4).


Figure 4 Media module with “right” variant


A media--right variant does this work. We can add the variant class to the module’s main div (making it <div class="media media--right">). Then we can use that class to target the image and float it to the right. Add the modifier class to the element and add listing 10 to your stylesheet to see this version.

Listing 10 Define a “right” variant of the module

  
 .media--right > .media__image {  ❶ 
   float: right;
 }
  

❶   Target image sub element, but only when “right” modifier’s present

This rule overrides the media image’s original float: left. Because of the way floats work, you don’t need to re-order the elements in the HTML.

Avoid generic tag names in module selectors

In the media module, I used the selector .media__body > h4 to target the title element. I was able to do this because <h4> is an element that should only represent a minor heading. I also use this technique for modules with lists; I find it simpler to target menu items with .menu > li than it is to add a menu__item class to each and every item in a list. (Though, opinions vary on this issue.)

You should avoid targeting based on generic tag types such as div and span. A selector like .page-header > span is too broad. When you initially build the module, you might only be using a span there for one thing, but you can come back later and to add a second span for a different purpose. Adding a class to the spans later is difficult, because it involves hunting down every use of that module in your markup and making the change.

Composing modules into a larger structure

In his book Clean Code, Martin Fowler says, “The first rule of classes is that they should be small. The second rule of classes is that they should be smaller than that.” He was speaking of classes in Object-Oriented Programming at the time, but the principle also applies to modules in CSS.

Your modules should each be responsible for one thing. Our message module is responsible for making a message noticeable. Our media module is responsible for positioning an image beside some text. You should be able to concisely summarize its purpose. Some modules are for layout, and others are for stylistic purposes. When a module tries to do more than one thing, you should consider breaking it into smaller modules.

Let’s build a dropdown menu next. This is shown in figure 5.


Figure 5 Dropdown menu


Whenever you start on a module, ask yourself, “at a high level, what’s the module’s responsibility?” In this case, our first answer might be, “a button that visually toggles a dropdown menu and presents menu items stacked atop one another.”

It’s an apt description of what we need, but I have a rule of thumb: if I must use the word “and” in describing the responsibility, I might be describing multiple responsibilities. Does it toggle a menu, or does it present stacked menu items?

When you need to use the word “and” to describe a module’s responsibility, consider whether you’re potentially describing two (or more) responsibilities. You might not be—this isn’t a hard and fast rule, but if you are, you should define separate modules for each responsibility. This is an important principle of encapsulation called the Single Responsibility Principle. When possible, distribute multiple responsibilities to multiple modules. This keeps each module small, focused, and easier to understand.

Divide multiple responsibilities among modules

Let’s build our dropdown menu with two different modules. The first, which I’ll call “dropdown,” has a button responsible for controlling the visibility of a container. You could further break this down and say it’s responsible for revealing the container and hiding the container. You could also describe the button’s appearance and the small triangle that indicates the action. Describing in this detail requires the use of “and.” But these details are all subordinate to the primary responsibility; we’re in good shape.

The second module, which I’ll call a “menu”, is the list of stacked links. We’ll compose the full interface by placing a menu module inside the container of a dropdown module.

To get started, place the markup from listing 11 into your page. This consists of a dropdown module that contains a menu module. It also contains a minimal bit of JavaScript to add open and close functionality when the toggle is clicked.

Listing 11 Dropdown menu constructed from two modules

  
 <div class="dropdown">
   <button class="dropdown__toggle">Main Menu</button>  ❶ 
   <div class="dropdown__drawer">                       ❷ 
     <ul class="menu">                                  ❸ 
       <li><a href="/">Home</a></li>
       <li><a href="/coffees">Coffees</a></li>
       <li><a href="/brewers">Brewers</a></li>
       <li><a href="/specials">Specials</a></li>
       <li><a href="/about">About us</a></li>
     </ul>
   </div>
 </div>
  
 <script type="text/javascript">
 (function () {
   var toggle =
     document.querySelector('.dropdown__toggle');
   toggle.addEventListener('click', function (event) {  ❹ 
       event.preventDefault();
       var dropdown = event.target.parentNode;
       dropdown.classList.toggle('is-open');
     }
   );
 }());
 </script>
  

❶   Toggle button for the dropdown

❷   A “drawer” sub element to serve as the menu container

❸   A menu module placed inside the “drawer”

❹   When toggle button’s clicked, toggle “is-open” class

I’ve used the double-underscore notation here to indicate that the “toggle” and the “drawer” are sub elements of the dropdown module. Clicking the toggle reveals or hides the drawer. The JavaScript does this by adding or removing the is-open class on the dropdown’s main element.

The styles for the dropdown are shown in listing 12. Add this to your stylesheet. I’ve updated the class names to match the double-underscore notation. This gives us a functioning dropdown, though the menu inside it remains unstyled.

Listing 12 Dropdown module definition

  
 .dropdown {
   display: inline-block;
   position: relative;                           ❶ 
 }
  
 .dropdown__toggle {
   padding: 0.5em 2em 0.5em 1.5em;
   border: 1px solid #ccc;
   font-size: 1rem;
   background-color: #eee;
 }
  
 .dropdown__toggle::after {
   content: "";
   position: absolute;
   right: 1em;
   top: 1em;
   border: 0.3em solid;
   border-color: black transparent transparent;  ❷ 
 }
  
 .dropdown__drawer {
   display: none;                                ❸ 
   position: absolute;
   left: 0;
   top: 2.1em;
   min-width: 100%;
   background-color: #eee;
 }
  
 .dropdown.is-open .dropdown__toggle::after {
   top: 0.7em;
   border-color: transparent transparent black;  ❹ 
 }
 .dropdown.is-open .dropdown__drawer {
   display: block;                               ❸ 
 }
  

❶   Establish containing block for the absolutely positioned drawer

❷   Draw the triangle using borders

❸   Hide the drawer initially, then display it when the “is-open” class is present

❹   Invert the triangle while the dropdown’s open

This uses relative positioning on the main element to establish the containing block for the drawer, which is, in turn, absolutely positioned within. It provides some styles for the toggle button, including the triangle in the ::after pseudo-element. Lastly, it reveals the drawer and inverts the triangle when the is-open class is present.

This is about thirty-five lines of code. A handful of things are going on here, but it’s not too much; we can keep it all in our head while we work on this module. When, down the road, you come back and make changes to a module, you want it to be small enough that you can figure it out again reasonably quickly.

Using positioning in a module

This module is the first one we’ve built that uses positioning. Notice that it establishes its own containing block (position: relative on the main element). The absolutely positioned elements (the drawer and the ::after pseudo-element) are based on positions which are defined within the same module.

When at all possible, I try to keep related positioned elements within the same module. This way, the module doesn’t behave strangely if we place it inside another positioned container.

State classes

The “is-open” class has a special purpose in the dropdown module. It’s intended to be added to or removed from the module dynamically using JavaScript. It’s an example of a state class, because it indicates something about the current state of the module.

It’s a common convention to design all state classes to begin with “is-” or “has-”. This way, their purpose is readily apparent; they’re expected to change, and indicate something about the module’s current state. Some other examples of state classes could be “is-expanded”, “is-loading”, or “has-error.” The precise nature of what these do depends on the module where they’re used.

Group the code for state classes along with the rest of the code for the module. Any time you need to use JavaScript to dynamically change the appearance of a module, use a state class to trigger the change.

Preprocessors and modular CSS

  
 @import 'base';
 @import 'message';
 @import 'button';
 @import 'media';
 @import 'dropdown';
  

With the dropdown module working, we can focus our attention on the menu module. We don’t need to worry any longer about the opening and closing of the dropdown, as that’s already taken care of by the other module. The menu module applies the look and feel we need to the list of links. The styles for this are shown in listing 13. Add these to your stylesheet.

Listing 13 Menu module styles

  
 .menu {
   margin: 0;
   padding-left: 0;
   list-style-type: none;       ❶ 
   border: 1px solid #999;
 }
  
 .menu > li + li {
   border-top: 1px solid #999;  ❷ 
 }
  
 .menu > li > a {               ❸ 
   display: block;
   padding: 0.5em 1.5em;
   background-color: #eee;
   color: #369;
   text-decoration: none;
 }
  
 .menu > li > a:hover {         ❹ 
   background-color: #fff;
 }
  

❶   Override user agent styles to remove list bullets

❷   Add border between each link

❸   Style large clickable links

❹   Add highlight on hover

While each <li> is a sub element of the module, I don’t feel the need to add a double-underscore to each and every one. The direct descendant selector .menu > li is specific enough.

This module is completely standalone. It has no dependency upon the dropdown module. This keeps the code simpler, because you don’t have to understand one to make sense of the other.

It also enables more flexible reuse of these modules. You could create a different style of menu—whether a variant or a completely separate module—and use it inside of a dropdown should the need arise. You can also use this menu elsewhere, outside of the dropdown. You can’t often predict what your pages might need in the future, but with reusable modules, you leave the door open to mix and match new possibilities with a familiar, consistent look and feel.

Choosing module names

Choosing appropriate module names takes thought. You can, of course, throw in a temporary name while you develop one, but before you consider it complete, make sure you’ve given some attention to its name. Doing this well’s possibly the most difficult part of writing modular CSS.

Consider the media module from earlier (figure 6). In the example, we used it to display an image of a runner and running tip.


Figure 6 Media module with a running tip


 Imagine we haven’t yet named the module, but we know a page needs it. We could name it a “running-tip”. This is accurate, and, initially, it seems fitting. But consider other things we may want to do with these styles. What if we wanted to use the same UI element for something else? Following the theme of a running website, we may wish to use a series of these to list upcoming races. If we do that, “running-tip” is suddenly out of place.

We need to give the module a name which is meaningful no matter what context we might wish to use it.

You should avoid names that describe the visual appearance. Calling this a “gray-box-with-image” seems more versatile, but what if you decide later the background color should be light blue? Or you perform a complete redesign of the site? This name is no longer applicable, and you must change it and update everywhere it appears in the HTML.

Instead, you need to ask yourself what this module represents conceptually. This isn’t always an easy task. “Media” works well on this level; it supports some sort of image and text. It gives a strong impression, without tying the module to any one particular use or visual implementation.

A module should be versatile. Its name is ideally simple and memorable. As you design more pages on the site, you can reuse it for any number of things. You and other members of your team can adopt it into the language you use when speaking about the site: “Let’s use a media here,” or, “These tiles are too close together.”

This far, we’ve created a message, a media, a dropdown, and a menu. Some other examples of good module names include “panel”, “alert”, “collapsible-section”, and “form-control.” It helps if you’ve a general sense of the overall design of the site from the beginning. You might know, for example, that there are two unrelated UI elements that could be rightly called “tiles,” in which case you should take care to name them more precisely (perhaps “media-tile” and “headline-tile”).

Some people enforce the use of two words in the name of every module, and nothing is too generic; you never know when the need for a completely new “tile” module may arise. If your existing tile module is more precisely named, it can leave you a little more freedom in naming the new one without the two becoming conflated.

Naming modifier classes

You should apply similar principles when naming variant classes for your module. For instance, if you have a “button” module, don’t subclass red and blue variants with “button–red” and “button—blue.” The design of your site is likely to change in the future, and you don’t know whether these colors will change. Try to find more meaningful names like “button–danger” and “button—success.”

Modifiers with a more relative meaning like “large” or “small” aren’t perfect, but they can be acceptable. Nothing says you can’t change the size of a “button–large” during a redesign, as long as it remains larger than a regular “button,” but avoid overly precise modifiers like “button-20px.”

That’s all we’ve got for you on modular CSS. If you’re interested in really learning CSS, download the free first chapter of CSS in Depth for more and see this Slideshare presentation.