supercharge your css code with m4
one of the biggest problems is the lack of constants. how many times have you wanted to code something like this? light_grey = #CCC. instead you are forced to repeat #CCC in your css. this quickly creates difficult-to-maintain and difficult-to-read code.
an elegant solution to the problem is to use a general purpose preprocessor like m4. m4 gives you a full range of preprocessing capability, from simple constants to sophisticated macros.
traditional css
consider the following example css:
.codeblock code { font:95% monospace; color: #444;}
div.codeblock {
padding: 10px;
border: 1px solid #888;
}below, we add constants: mid_grey, dark_grey and std_padding.
the same css with m4
.codeblock code { font:95% monospace; color: dark_grey;}
div.codeblock {
padding: std_padding;
border: 1px solid mid_grey;
}trying it it out
if you'd like to give this a try, m4 is usually available as a standard package e.g. on debian style linux flavors do:# apt-get install m4 m4-docexample.css
changequote(^,^)dnl change quotes to something safe
changecom(^/*^, ^*/^)dnl change comments to css style
define(dark_grey, ^#444^)dnl define a dark grey color
define(mid_grey, ^#888^)dnl define a middle grey color
define(std_padding, ^10px^)dnl define the standard padding
.codeblock code { font:95% monospace; color: dark_grey;}
div.codeblock {
padding: std_padding;
border: 1px solid mid_grey;
}$ m4 example.css.codeblock code { font:95% monospace; color: #444;}
div.codeblock {
padding: 10px;
border: 1px solid #888;
}-
dnltells m4 to "discard to next line" i.e. ignore everything after it. useful for comments. - i use
changequoteandchangecomto change quoting and commenting characters to be more css compliant than the defaults.
using include statements
in practice, you'll often want to use your definitions in several css files. to do this, place your definitions into an external file. in our example, we split our code into two files,definitions.m4 and example.css as follows:
definitions.m4
define(dark_grey, ^#444^)dnl define a dark grey color
define(mid_grey, ^#888^)dnl define a middle grey color
define(std_padding, ^10px^)dnl define the standard marginexample.css
changequote(^,^)dnl change quotes to something safe
changecom(^/*^, ^*/^)dnl change comments to css style
include(^definitions.m4^)dnl include the definitions file
.codeblock code {font:95% monospace; color: dark_grey;}
div.codeblock {
padding: std_padding;
border: 1px solid mid_grey;
}note: my choice of filenames and extensions (definitions.m4, example.css) is arbitrary.
once you've split the files, you can run the preprocessor as before:
$ m4 example.cssfurther thoughts
this article describes a tiny subset of the power of the m4 language. for more information, take a look at the gnu manual.one thing that i don't discuss here is integrating a preprocessor into your development / build environment. more on that later.
tech blog
- john's blog
- 7933 reads









This seems overly complex,
This seems overly complex, not to mention that (as noted) css is built to alleviate the need to do this sort of thing.
As it stands, the reason for using this would be to solve this issue:
div.codeblock { padding: std_padding;}div.otherblock { padding: std_padding;}
div.yetanotherblock { padding: std_padding;}
in so that you can have the same padding througout without needing to change several instances. CSS simply allows you to do this:
div.codeblock, div.otherblock, div.yetanotherblock { padding: 5px; }And you've accomplished the same thing. Obviously, coding like the second example is a bit more difficult and requires more planning, but you end up with optimized, faster loading (smaller file) CSS than if you're simply doing (what ends up amounting to) 'find and replace' in the css.
Perhaps m4 has more benefit to it than that -- why why not php then?
jeff, seasons greetings and
jeff, seasons greetings and thanks for your comments. while i agree with your points:
and agree that neither of these two things require a preprocessor.
i think you've missed my two central points i.e.
In reading back I may have
In reading back I may have come across on the terse side, unintentionally I assure you. I don't browse the internet looking to pick fights :)
Your points are valid, even if I can't justify the extra effort needed for this myself. And, should I find the need, my preference would probably lay within doing this via PHP and not "yet another scripting language" :)
jeff, agreed. the links that
jeff, agreed.
the links that dennison post below offer an interesting alternative for those using php. this has the advantage, as you point out, of not introducing another language. it also doesn't require an extra build step.
it's worth noting that m4 isn't a scripting langage, but rather a simple preprocessor. preprocessors are typically used to complement languages, rather than offer a competing language, e.g. the relationship between CPP and the C/C++ languages familiar to a lot of programmers.
the preprocessor approach has the advantage of not introducing any run-time overhead, and being language and platform independent.
thanks again for bringing up the php idea and to dennison for the links.
I agree, this can be done so
I agree, this can be done so easily in PHP which is also a widely supported scripting language, so you will have no problems with hosting. Check out the following links: http://sperling.com/examples/pcss/ and http://www.digital-web.com/articles/generating_dynamic_css_with_php/
Maybe it's because I haven't
Maybe it's because I haven't seen enough of what m4 can do, but it just seems like extra work that CSS already does. If I had a stylesheet that I thought was hard to read or update, I'd rearrange things so that colors and padding, for example, would be specified in as few places as possible. I like the fact that you can have more than one, completely unrelated selector on a rule.
Cool article, but now I've
Cool article, but now I've got evil ideas in my head about hacking a templateing system into drupal_build_css_cache.
I didn't, but now I do.
I didn't, but now I do. Interesting...