Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with:

Using The RequireJS Build / Optimizer To Concatenate Modularized CSS Files

By Ben Nadel on
Tags: HTML / CSS

A little while back, I started looking at RequireJS as away to organize and modularize my JavaScript code. And, while I am still getting my feet wet in modular JavaScript web application development, I can tell you that I have really enjoyed using RequireJS - and, that I plan to continue to integrate it into my development process. The asynchronous loading and the on-demand loading of JavaScript modules are nice feature of RequireJS; but the real "ah ha!" moment for me came with the ability to organize my JavaScript code into small(er) cohesive files. In my reading, I noticed that the RequireJS optimizer - r.js - also works with CSS (Cascading Style Sheets) files. As such, I wanted to see if RequireJS could afford the same kind of benefits in the world of CSS that it provided in the world of JavaScript.

The functionality of the RequireJS optimizer as it applies to CSS is rather simple. As stated on the RequireJS website, the optimizer works as such:

Optimizes CSS by inlining CSS files referenced by @import and removing comments.

It doesn't do any syntax-based optimization or minifacation - it simply removes comments and inlines files that have been linked using the @import command. This may not seem like much; but, given the fact that my "ah ha!" moment in the JavaScript domain came with the ability to organize my files, it would seem that this is exactly the kind of functionality that I would need for my CSS.

To experiment with the RequireJS optimizer for CSS, I created a trivial HTML page that linked to a CSS file that, itself, linked to two other CSS files:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Using RequireJS To Optimize CSS Files</title>
  •  
  • <!-- Link the main stylesheet. -->
  • <link rel="stylesheet" type="text/css" href="./main.css"></link>
  • </head>
  • <body>
  •  
  • <!-- BEGIN: Site Container. -->
  • <div class="l-container">
  •  
  •  
  • <div class="l-header">
  •  
  • <div class="logo">
  • The Blog Of Ben Nadel
  • </div>
  •  
  • </div>
  •  
  • <div class="l-body">
  •  
  • <h1>
  • Using RequireJS To Optimize CSS Files
  • </h1>
  •  
  • <p>
  • This is an exploration of the use of the RequireJS
  • compiler / optimizer (r.js) as a means to concatenate
  • and optimize CSS files.
  • </p>
  •  
  • <p>
  • So far, I really like RequireJS as a way to organize
  • and then package JavaScript modules. It might be a
  • nice, simply way to package CSS as well.
  • </p>
  •  
  • </div>
  •  
  • <div class="l-footer">
  •  
  • <p class="copyright">
  • Copyright &copy; 2012. Ben Nadel.
  • </p>
  •  
  • </div>
  •  
  •  
  • </div>
  • <!-- END: Site Container. -->
  •  
  • </body>
  • </html>

Notice that some of the class names are prefixed with, "l-". As part of the exploration, I thought I might start trying to use some SMACSS (Scalable and Modular Architecture for CSS) methodologies (which use "l-" to define layout definitions); as such, I created a "Base" CSS file and a "Layout" CSS file. The "Modules" CSS for the page is defined in the main CSS that is loaded:

main.css - Our Page Modules

  • /* Base styles. */
  • @import url( "./base.css" );
  •  
  • /* Layout styles. */
  • @import url( "./layout.css" );
  •  
  •  
  • /* Modules for this section. */
  •  
  • div.logo {
  • background-color: #333333 ;
  • color: #FFFFFF ;
  • font-size: 11px ;
  • padding: 5px 0px 5px 0px ;
  • text-align: center ;
  • text-transform: uppercase ;
  • width: 155px ;
  • }
  •  
  • p.copyright {
  • color: #999999 ;
  • font-size: 11px ;
  • margin: 0px 0px 0px 0px ;
  • }

As you can see, our modules CSS file links to the Base and Layout files using the @import command. The RequireJS optimizer will inline these two additional files so that they won't incur the cost of two additional HTTP requests.

You have to invoke the node.js-based RequireJS optimizer from the command line. But, rather than doing that manually, I figured I would create a Bash script that would encapsulate the "build" of my application:

build - Bash Script For Invoking RequireJS Optimizer

  • ## Optimize the CSS file. Creates "main-built.css" file.
  •  
  • node ../r.js -o cssIn=main.css out=main-built.css

When I run the above build script in my CSS directory, the RequireJS optimizer creates "main-built.css" which is a concatenated version of all the required CSS files:

main-built.css - Our Concatenated CSS File

  • body {
  • background-color: #FFFFFF ;
  • font-family: "lucida grande", helvetica, arial, verdana ;
  • font-size: 14px ;
  • margin: 30px 20px 30px 20px ;
  • padding: 0px 0px 0px 0px ;
  • }
  • h1 {
  • font-size: 150% ;
  • }
  •  
  • p {
  • line-height: 1.5em ;
  • }
  • div.l-container {
  • background-color: #F0F0F0 ;
  • -moz-border-radius: 5px 5px 5px 5px ;
  • border-radius: 5px 5px 5px 5px ;
  • margin: 0px auto 0px auto ;
  • padding: 20px 20px 20px 20px ;
  • width: 450px ;
  • }
  •  
  • div.l-header {
  • height: 50px ;
  • position: relative ;
  • }
  • div.l-body {
  • padding: 0px 0px 20px 0px ;
  • }
  • div.l-footer {
  • border-top: 1px dotted #CCCCCC ;
  • height: 30px ;
  • padding: 20px 0px 0px 0px ;
  • position: relative ;
  • }
  • div.logo {
  • background-color: #333333 ;
  • color: #FFFFFF ;
  • font-size: 11px ;
  • padding: 5px 0px 5px 0px ;
  • text-align: center ;
  • text-transform: uppercase ;
  • width: 155px ;
  • }
  • p.copyright {
  • color: #999999 ;
  • font-size: 11px ;
  • margin: 0px 0px 0px 0px ;
  • }

As you can see, the RequireJS optimizer doesn't do anything fancy with CSS (the way it obfuscates and compacts JavaScript code); rather, it simply inlines the CSS of the linked files.

As new as I am to the concept of Modular JavaScript architecture, I'm even less experienced when it comes to good CSS organization. That said, I think the RequireJS optimizer for CSS gives me some really fun stuff to play with. Going from one monolithic CSS file to many smaller, cohesive files, however, is going to be a long journey of exploration and understanding.



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Now that you are on your way to becoming a bash expert it would look like a good exercice to a build a script that does exactly that.

(tips : cat filename1 >> filename2 appends the content of filename1 into filename2,
grep and egrep are used to find lines that match a regex. You can use -o to capture only the part that matches the regex instead of the whole line.)

Reply to this Comment

@Guillaume,

Trying to write this in a Bash script would definitely be awesome! I'll put that on my list of things to do. I know that people talk about grep like it's the holy grail :) I do love me some regular expressions, of course!

Reply to this Comment

I used coldfusion to join my CSS and Javascript for example:

<cfapplication name="style_values" sessionmanagement="Yes" setclientcookies="Yes"><cfinclude template="/include/session.cfm" /><cfprocessingdirective suppresswhitespace="yes" pageEncoding="utf-8"><cfsetting enablecfoutputonly="true"><cfsetting showdebugoutput=false><cfcontent type="text/css; charset=UTF-8" reset="true"><cfsavecontent variable="variables.pagecontent"><cfoutput>
html
{
min-width:#style_values.pagewidth#px;
}
<cfinclude template="head.cfm" />
<cfinclude template="navigation.cfm" />
<cfinclude template="content.cfm" />
<cfinclude template="footer.cfm" />
<cfinclude template="classes.cfm" />
h2
{
font-family:#style_values.font.primary.face#;
color:###style_values.textcolor#;
font-size:#style_values.font.h2.size#px;
}
<cfcontent type="text/html" variable="#tobinary(tobase64(RemoveBlankLines(variables.pagecontent)))#" />

Reply to this Comment

Woops the last line should be <cfcontent type="text/css" variable="#tobinary(tobase64(RemoveBlankLines(variables.pagecontent)))#" />

And I didn't mention that I call this as a CSS file.

Reply to this Comment

@Ben For larger applications, having CSS directly correspond to small templates allows for modular CSS management. Getting this to work practically with builds can be tricky.

I've put together one solution along these lines supporting CSS loading and builds through the r.js optimizer as another dependency. Thought you may be interested to check it out.

https://github.com/guybedford/require-css

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.