by

Quick Tips for CSS (that scales) for a CMS

It’s not that hard to write CSS. The basics of how the language works can be learned in 15 minutes. Most of the major properties and techniques for using them can be learned in a few days.  You can learn how to build static websites within a few weeks —and there’s scores of books and blogs to help you out along the way.

But you know what’s missing? How CSS should work with a Content Management System (CMS). You know what else is missing? How your CSS should scale for a CMS.  You can find a hundred blog posts on cool stuff you can do with transforms but maybe less than ten on how CSS should work when you know you’re writing for a CMS. Here’s some quick tips that front-end developer should follow, and a Tridion architect or CMS implementer should look for, before you start your project:

 

Have a documented front-end architecture

I think the ITCSS structure is darned-near perfect for organizing CSS files for a CMS. It maps very well to what a front-end workflow should look like and it organizes content along the lines that a backend-developer would probably organize his views.

The SMACSS architecture also works pretty well. That architecture works especially well if you have many sites that need to be “themed”. I’ve used a SMACSS-ish setup in quite a few Tridion implementations and it’s worked out quite nicely when it came time to launch a new site where the only thing we needed to change was the skin.

Whatever architecture you use, you should know what it is, and have it documented. And you’ll know it’s an architecture when it tells you:

  • How files are organized
  • How to classify different features
  • How to name things (in the code, and files themselves
  • How to make things ready for the next phase of development

Questions to Ask

If you are the front-end developer, you should have these answers. If you’re the architect, you should ask these of your front-end developers.

  • When a new feature is created, will it be easy to find in the codebase?
  • Can you identify easily which compontent templates (views) go with which components?
  • Is there an easy way to make this site work if the brand changes?

Have a known and documented class naming convention

I am a big fan of the BEM methodology and I think it’s perfect for the CMS. If the CMS is Tridion, you can map Block, Element, and Modifier to specific items that Tridion stores and outputs.

But it doesn’t matter whether you use BEM, some variation of it, or something else like SMACSS or OOCSS. The Front-end developers should know:

  • What naming convention we’re using
  • How to name things
  • When names change

And this pattern should at least be obvious and recognizable-enough that a back-end developer knows how to predict where the class names go.

Questions to ask

  • Are the CSS classes predictable?
  • Could a backend developer (or whoever makes the component templates) easily see how the markup maps to the schema?

Keep the CSS detached from the markup

This is a big one, and it’s very easy to miss in a few different ways. The big idea is that styles are not dependent upon markup. What does ” styles are not dependent upon markup,” mean? Well, let’s look at one example:

 <header class="header">
 <div class="wrapper">
   <img class="headerImage" src="" />
    <div class="contentWrapper">
      <h1 class="title">This is a great page!</h1>
      <h2 class="subtitle">;You'll like what's on it </h2>
    </div>
  </div>
</header>

This markup is innocent enough. But let’s look at how the CSS could be:

 .header {
  width: 100%;
  background: #333;
 }
 .header .wrapper {
   padding: 5% 0;
 }

 .header .wrapper .headerImage {
   width: 100%;
 }

.header .wrapper .contentWrapper .title {
  font-size: 4em;
}

.header .wrapper .contentWrapper .title + .subtitle {
  font-size: 2em;
}

That, right there, is markup dependence. Each style is dependent upon being inside an element with a corresponding classname. Imagine that you, as the back-end developer, need to add a “wrapper” for some content (this is common when implementing Tridion’s Experience Manager (XPM / Site edit). If you add a wrapper, or heck, remove a wrapper, the styles fall apart.

Not only that, what if you want that title style somewhere else? Like not in the header. It’s bad-news-bears for your component template.

How does markup dependence happen?

Front-end developers these days use CSS preprocessors to help them write code. Whether that preprocessor is Sass, Less, or Stylus, they all provide this feature called “nesting”. What that means is that the front-end developer didn’t write that code. Most likely, he wrote something like this:

 .header{
  width: 100%;
  background: #333;

  .wrapper {
   padding: 5% 0;

   .headerImage {
     width: 100%;
   }
   .contentWrapper {

     .title {
       font-size: 4em;
      
      + .subtitle {
       font-size: 2em;
      }
     } 
   }
  }
 }

When you look at that, it doesn’t seem so bad, does it? It’s easy to read, and it does a good job illustrating to the CSS author the shape of the markup.  Little does the CSS author know that the decision to write pre-processed CSS that illustrates the markup has created a markup dependence that has produced fragile code.

Brand new front-end code should not rely on many classes to work. The golden rule on my front-end team is one class for one task. Brand new markup should get its styles from just one class.

Another way that markup dependence happens is when the front-end developer styles on element names rather than class names:

.header {
  width: 100%;
  background: #333;

  div.wrapper {
   padding: 5% 0;
  }
  
  img {
   width: 100%;
  }
  h1 {
     font-size: 4em;
  }
  h2 {
    font-size: 2em;
  }
}


This is kind of markup dependence is equally bad. Unlike the previous example where the styles assume order of markup, this assumes kind of markup. In this case, styles will break whenever HTML elements are changed out. Big companies especially value their SEO. If an SEO agency comes in and evaluates markup and decides that more or different semantic HTML is needed, this results in broken styles.

Questions to Ask

  • Are you using a CSS preprocessor?
  • Do you have rules / guidelines for how deep you’re allowed to nest?
  • If existing HTML elements change, will styles have to be revisited?
  • Can the markup be used in other places on the site?

Keep Layout Detached from Skin (and Brand)

I’m not talking about “theme” here. Theme is probably the subject of a new post entirely. When I say “Skin”, I’m talking about those CSS properties that make Content A completely different on Website A vs Website B (Brand), while only looking kinda different on Page A vs Page B (Skin). Typically, we wrap Brand and Skin in these properties:

  • Font style: font-family, font-weight, text-decoration
  • Color: Text color, link color, background colors
  • Borders: width, color, styles
  • Background: images, colors, transparency

Compare this to things that are traditionally “layout”; they determine how the browser shapes and forms things on the page:

  • Text sizing: font-size, line-height, indentation
  • Dimensions: height, width
  • Spacing: margin, padding
  • Position and Paint: position, z-index, top / right / bottom / left
  • Display and visibility

Intertwined concerns aren’t good

Layout and Brand/Skin are very different things, but how does the typical front-end developer typically write his typical code? A bit like this:

.article__heading {
 color: #c0fefe; // skin
 font-family: 'Amazing Font'; //brand
 font-weight: 300; //brand
 font-size: 2em; // skin or layout
 line-height: 1.618; // skin or layout
 padding: 0 .5rem; // layout
 margin: -1rem 0 0 0; // layout
 width: 400px; //layout
 position: relative; //layout
 top: 1rem; // layout
 border-bottom: 5px solid #fff; //skin
}

Brand/Skin and layout are very much intertwined. This doesn’t seem bad starting off. But once things start getting reused in other areas of the site, the front end developer must start overwriting styles. We end up with stuff like this:


.someContainer .article__heading {
 color: #c0ffee; //skin change
 font-weight: 400; // skin change
 font-size: 3em; // becomes a skin
 line-height: 1.5; // becomes a skin
}

This one-off over-writes eventually turns into something like this:

.someClassOnHTMLElement .someContainer .article__heading {
  color: #baddab; // another skin change
  font-weight: 700; //another skin change
  border-bottom: none; // another skin change
}

What you may notice is that the vast majority of these “overwrites” are related to a small set of properties, mostly centered around the look and feel. As we go along, we increase markup dependence in order to accomplish our goal. We didn’t start with fragile code, but we end up with it.

Start with separated concerns

What would be way more helpful is if we started off by recognizing the various concerns of our CSS by separating them:

/*LAYOUT + DEFAULT SKIN*/
.article__heading {
 font-size: 2em; // layout
 line-height: 1.618; //layout
 padding: 0 .5rem; // layout
 margin: -1rem 0 0 0; // layout
 width: 400px; // layout 
 position: relative; // layout
 top: 1rem; //layout 
}

 /*DEFAULT BRAND + SKIN */
.article__heading {
 color: #c0fefe; // skin
 font-family: 'Amazing Font'; // brand
 font-weight: 300; // skin
 border-bottom: 5px solid #fff; //skin

}

/*NEW BRANDS/SKINS */
.article__heading--moreAmazing {
 color: #c0ffee;
 font-weight: 400;
 font-size: 3em; 
 line-height: 1.5;
}

.article__heading--mostAmazing {
  color: #baddab;
  font-weight: 700; 
  border-bottom: none;
}

Using the BEM syntax, along with some organizational practices, we create one CSS selector that establishes layout and some default skin. But, we start off believing that font-size and line-height fit into a “layout” bucket. So we keep those separate from our default skin.

Then, we create a new ruleset, whose only job it is to provide brand and default skin. We separate it for three reasons:

  • Readability: Just easier to see all of the similar things in their own place
  • Wrappability: If we wanted to isolate the default brand settings to one area of the site, we can easily wrap them in a parent selector
  • Extensability: If instead of a default class that implicitly applies brand, we want one that explicitely does so, we can change the classname to .article__heading--default

That separate ruleset just for skin means that if we discover later that we’re over-writing those default font-size or line-height properties too much, we can easily move them out of “layout” and into some ruleset that explicitely applies our styles; we’d rather move existing code somewhere better, rather than add new code.

So as our code grows, and we get new views, we add new “skins/brands” with different rulesets. We move small chunks to better homes. All the while, we’re making absolute minimal changes to markup:

<h1 class="article__heading" />
<h1 class="article__heading article__heading--mostAmazing />
<h1 class="article__heading article__heading--moreAmazing/>

We’ve separated Brand from layout,and done so in such a way that if one of these variations needs a layout change associated with it, we can do so without bloating CSS specificity.

Questions to Ask

  • Do you have a way to easily change only look and feel for content?
  • If I have to use Component A on Page B, will there be any unexpected consequences?
  • If I need to create a new template really quick, do you have a baseline of the markup that I can use?

In conclusion

This isn’t the end of the “quick tips”. There are many more. I think the But if you’re looking for an easy checklist to make sure that the CSS is ready to scale for a CMS, ask yourself and your front-end developers these questions:

  • Do you know how we’ll add new features to the codebase?
  • Can you identify easily which views go with a particular kind of content?
  • Is there an easy way to make this site work if the brand changes?
  • Are your CSS classes predictable?
  • Will a backend developer know how the markup maps to the content model without asking you first?
  • Are you using a CSS preprocessor?
  • Do you have rules / guidelines for acceptable markup-dependence
  • If existing HTML elements change after you write the code, will you need to update your CSS?
  • Can the markup be used in other places on the site
  • If I have to use a view on a different page, will you need to come back and fix things?
  • Do I have a baseline version of a given template that I can work from?

Tell me what you think