CSS Server-side Pre-processor

Update CSS-SSPP has been retired in favor of the newer, extensible CSS Cacheer.

Last week while digging around an old /tmp/ directory I came across an abandoned project from late 2005. Inspired by CSS-SSC and pre-processing CSS I had been playing around with the idea of nested selectors.

What do I mean by nested selectors? HTML markup consists of nested elements:

<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
</ul>

To apply a style to the nested list-item we write a style definition with flattened selectors:

ul
{
    list-style: none;
}

ul li
{
    font-size: 0.9em;
}

What if our CSS more closely matched the structure of our HTML?

ul
{
    list-style: none;

    li
    {
        font-size: 0.9em;
    }
}

The benefits in this simplified example might not be immediately apparent.

Most CMSes use highly modularized markup. A 1:1 relationship to markup and styles would simplify navigating and sharing the CSS written for those modules (especially when collaborating in a team environment).

Two years later this still seems like a useful idea so on the flight back from An Event Apart Seattle I revisited it and mixed in a few other ideas.

Constants

In addition to nested selectors, server-side constants are back with a slightly different syntax. Constants can be defined two ways. Individually:

@server constant constantName: constantValue;

or en masse:

@server constants
{
    constantName1: constantValue;
    constantName2: constantValue;
    constantName3: constantValue;
}

Constant values are retrieved the same way regardless of how they are defined.

a { color: constantName; }

will output:

a { color: constantValue; }

Individually defined constants will be overridden by constants defined en masse. Constant names may only contain alpha-numerics; constant values, anything but a semi-colon.

Variables

Variables work the same way as constants except their values can also be passed in via the query string. Variable names begin with a dollar sign. All variables must be pre-defined with a default.

Set individually:

@server variable $variableName: defaultVariableValue;

or en masse:

@server variables
{
    $variableName1: defaultVariableValue;
    $variableName2: defaultVariableValue;
    $variableName3: defaultVariableValue;
}

Variable values are retrieved the same way regardless of how they are defined.

body { background-color: $variableName; }

will output:

body { background-color: defaultVariableValue; }

if the variable does not appear in the query string. But add the variable name/value pair to the query string (without the dollar sign) like so:

sample.css?variableName=variableValue

and the previous example will output:

body { background-color: variableValue; }

Variable names may only contain alpha-numerics and must start with a dollar sign, variable values anything but a semi-colon. Don’t forget to encode values included in the query string (# should be %23 in particular).

When variables are present in the query string caching is not used. The cache is deleted and recreated on every request. I may revisit the caching mechanism in the future to address this inefficiency.

Import

Additional stylesheets can be imported using:

@server import url(stylesheetName.css);

The url value can be un-, single- or double-quoted but cannot contain a closing parenthesis. Imported styles can include nested selectors, constants, variables and bases.

Bases and Based-on

Similar to constants, bases allow you to define many property/value pairs and include them in any style definition using the based-on property.

Defining a base:

@server base baseName
{
    property: value;
    property: value;
    property: value;
    property: value;
}

Basing another style on a base:

a { based-on: baseName; }

would result in the following output:

a
{
    property: value;
    property: value;
    property: value;
    property: value;
}

In the current version of the Server-side Pre-processor bases cannot contain nested selectors.

Caching and Compression

A processed copy is cached in the /cache/ directory. Comments and extraneous whitespace are stripped during processing. All nested selectors are flattened and grouped so that browsers can understand them.

Inline CSS hacks may cease to function. We’re all using conditional comments anyways, right?

Changes to imported CSS files are not detected by the caching mechanism —doing so would require a “shallow” reprocessing of the file—but you can force a recache by adding ?recache to the parent CSS file.

Usage

The CSS Server-side Pre-processor requires PHP, Apache and mod_rewrite. Simply download the sspp-v002.zip archive and unzip. The archive contains one directory and four files:

  • .htaccess
  • cache/
    • .htaccess
    • cacheer.php
  • cache.php

Add the contents of the archive to your existing style directory. Change the permissions of the /cache/ directory to 777. Then have at it.

The CSS Server-side Pre-processor is offered as-is, as always. I’ve built in catches to prevent processing non-css files and files above the style directory but the internets is a clever place. Use at your own risk.

How Nested Selectors Work

Briefly, after importing and applying constants and variables, the nested selectors are transformed into a CSSML that looks something like:

<?xml version="1.0" ?>
<css>
    <rule selector="ul">
        <property name="list-style" value="none" />
        <property name="margin" value="0" />
        <property name="padding" value="0" />
        <rule selector="li">
            <property name="margin" value="0" />
            <property name="padding" value="0" />
        </rule>
    </rule>
    <rule selector="a">
        <property name="color" value="#AB6666" />
        <property name="text-decoration" value="none" />
        <rule selector=":hover">
            <property name="color" value="#710101" />
        </rule>
    </rule>
</css>

That XML is then parsed into a DOM and transformed into standard CSS. It isn’t pretty but it gets the job done.

(As you may have noticed in the example above, pseudo-selectors like :hover can be nested inside of the element they refer to. This only applies to pseudo-selectors, not different classes of the same element.)

Updates

v004 adds support for nested child and adjacent selectors. The following:

h1
{
    font-size: 2.0em;
    + p
    {
        margin-top: 0;
    }
}

generates:

h1 
{
    font-size: 2.0em;
}

h1 + p 
{
    margin-top: 0;
}

The current version of CSS Server-side Pre-processor has been downloaded 1804 times.

Previous
Web Fonts on the Horizon
Next
Sweet Helvetica Calendar
Author
Shaun Inman
Posted
June 27th, 2007 at 11:12 pm
Categories
CSS
Design
PHP
Web
CSS-SSC
Comments
039 (Now closed)

039 Comments

001

Nice, nice. Looks like fun stuff to play with. It would be extra-sweet if it used whitespace to discern nesting, a la Python. You know, like:

ul {
    property: value;
    property: value;
    }

    li {
        property: value;
        property: value;
    }

It would make the syntax a bit closer to valid CSS…

Definitely cool stuff, man!

Author
Jeff Croft
Posted
Jun 27th, 2007 11:28 pm
002

This looks great! I hope to play around with it tomorrow.

Thanks for another handy script.

Author
Ben Cochran
Posted
Jun 28th, 2007 12:19 am
003

This is awesome. The idea definitely sounded cool when you mentioned it at AEA - I had no idea it supported variables too. Will CSS-SSPP support variable operations like basic math and boolean evaluation?

I’m currently cooking up the next version of my site and I’ll absolutely be using this. Much much better than writing out general styles that have a mile-long selector for a dozen or so elements.

Author
Rob Goodlatte
Posted
Jun 28th, 2007 12:48 am
004

@Jeff: I’d have to disagree. Making it more Python-like would just make it more Python-like. Valid CSS syntax ignores whitespace. Nothing about the Python alternative says “nesting” when you’re coming from an HTML/CSS/JavaScript/PHP point-of-view.

@Rob: I have no plans to add logic to CSS-SSPP but that doesn’t mean someone else can’t take a stab at it.

Author
Shaun Inman
Posted
Jun 28th, 2007 1:16 am
005

I’d love to take a stab at adding a few new features to it. May I modify and re-distribute with attribution back to this post?

Also, how will the end result look in terms of cascades and inheritance? Do you roll up all of the selectors which are based on the same base and write one big general rule like:

#foo, #bar { general styles here}
#foo {specific styles}
#bar {specific styles}

(foo and bar share a base)

or do you simply deposit the base CSS into each selector, like:

#foo {
general styles here;
specific styles;
}
#bar {
general styles here;
specific styles;
}

I agree on the nesting syntax badness. I see based-on behaving similarly to a class in OOP that extends a super class, and it doesn’t make sense to write out strange nested CSS. If it was nested it would make it difficult to use a base more than once.

Sorry for the flurry of comments - this thing looks really cool.

Author
Rob Goodlatte
Posted
Jun 28th, 2007 1:46 am
006

Very cool, Shaun. Now I need to let this idea steep for a bit and see how I might use it somewhere.

I love Jeff’s Python-esque idea too, probably ‘cuz I love Python. :) While I see the point on it being just Python-like, it also prevents nesting a statement inside another so it seems like it’d still be valid CSS even without the server-side processing (albeit without the intended effect, so not much good I suppose).

Anyway, thanks for digging this back up and sharing it!

Author
Dave Lowe
Posted
Jun 28th, 2007 3:10 am
007

Have you seen SASS? It’s a very similar idea implemented for Ruby. In SASS for example, you’d say:

!main_color = #00ff00

#main
  :color = !main_color
  :p
    :background-color = !main_color
    :color #000000

to get:

#main {
  color: #00ff00; }
  #main p {
    background-color: #00ff00;
    color: #000000; }

Etc.

Author
Carl
Posted
Jun 28th, 2007 4:24 am
008

Brilliant. I was working on something like this a while back in Python (very similar to the already-mentioned SASS), but it became not worth the trouble. This is awesome though.

Author
Avinash
Posted
Jun 28th, 2007 7:11 am
009

Hmm. Definitely looks interesting and worth checking out. In the back of my mind I can’t shake the thought that it is convoluting the process of css. I mean, I like the use of PHP to parse and handle - but I just feel like there is too much of a crossover.

I have used PHP to write CSS sheets in the past (not on the fly, but write/cache them). But it seems like there still needs to be a clean separation of the two. Why try to blend them and create new syntax/structures for CSS?

I don’t think its bad - it just gives me mixed feelings. ha.

Author
Nate Klaiber
Posted
Jun 28th, 2007 8:32 am
010

Really interesting stuff, Shaun. I might have to play around with this a bit later.

The one thing that leapt out at me, though, is your initial example:

ul
{
    list-style: none;

    li
    {
        font-size: 0.9em;
    }
}

Just from a visual standpoint, that implies some sort of scoping: that the font-size property is limited to the parent ul, which of course isn’t how the cascade would work. I’m not sure how you’d fix that, mind you, but I do think there’s some sort of disconnect between the preprocessor code and how the CSS will actually function.

That’s just my first reaction after my quick read of your post. Like I said, nice work—can’t wait to kick the tires.

Author
Ethan
Posted
Jun 28th, 2007 9:02 am
011

And by “the cascade,” I meant “inheritance.” I fail at typing before caffeine.

Author
Ethan
Posted
Jun 28th, 2007 9:05 am
012

Fair enough, Shaun. I was just saying that if you used the whitespace to determine the nesting, you’d have less unfamiliar syntax, which to me makes it feel more like writing regular CSS (admittedly, I often indent my CSS like that, anyway).

But yes, I’m sure that it appeals to me (and Dave) in part because we like Python. :)

Author
Jeff Croft
Posted
Jun 28th, 2007 10:15 am
013

Wow, awesome idea, Shaun. Ethan beat me to the question, though; I’m also curious to see how inheritance would work here.

For the sake of argument though, doesn’t making CSS server side push it more towards a programming language, which kinda defeats the theory of CSS? (To be fair, this has great practical benefit; I’m just questioning it on a conceptual level.)

Author
Dan Mall
Posted
Jun 28th, 2007 10:17 am
014

This is a great concept that I’ve considered handling a few different ways, all of which were geared toward making CSS a bit more dynamic in nature and more manageable.

For those who are skeptical about this implementation, another concept is to put PHP statements right in your .CSS document and tell PHP to parse it.

I haven’t tested for page-load impacts but it seems like it would be minimal. The advantage being that you get dynamic (logic based) widths, heights, colors, font-sizes, etc.

Look forward to seeing how this progresses.

Author
DSW@TNM
Posted
Jun 28th, 2007 10:24 am
015

@Rob: You’re free to modify and re-distribute. The base is inserted into each selector. Creating a comma delimited selector that contains the base properties would be an inheritance nightmare because you don’t know if or where any of the descendent styles might override a property in the base.

@Python-lovers: I don’t see the benefit of the selectors looking like valid CSS when they are not. ul li is not the same as just li which as a single selector would also affect ol li. Think of SSPP as an extension of CSS, not a syntactic rewrite and you’ll get along just fine. ;)

@Nate: Fair enough. You don’t have to use SSPP or even all of its features. But at the very least, @server import is useful for cutting down on the number of http requests created by the standard CSS @import.

@Ethan: The property/value pairs defined within nested selector have no impact on the properties that are output for the parent or subsequently nested selectors. SSPP just unnests those selectors and prefixes the actual selector with the appropriate descendent selector based on the original nesting.

@Dan: Variables don’t a programming language make. SSPP is just an experiment, a proof of concept. I’ll let the tubes argue about the value of getting chocolate in our peanut-butter.

Author
Shaun Inman
Posted
Jun 28th, 2007 10:58 am
016

The property/value pairs defined within nested selector have no impact on the properties that are output for the parent or subsequently nested selectors. SSPP just unnests those selectors and prefixes the actual selector with the appropriate descendent selector based on the original nesting.

Oh, I get that. I was just wondering about the divide between the structure of the “nested selectors,” and how the stylesheet’s actually going to function once it’s transformed. Just a conceptual question, not a practical one.

Also, have you thought about how this could be extended to other selectors (child, adjacent, sibling, etc.)?

Author
Ethan
Posted
Jun 28th, 2007 11:23 am
017

Variables don’t a programming language make.

True that. I just worry that the addition of non-literal values (i.e. variables) convolutes the simplicity of CSS.

SSPP is just an experiment, a proof of concept.

Don’t get me wrong; I definitely see the value in it and plan to start using it immediately. I’ve been waiting for something like this for a while. In a practical production environment, it’s a godsend. I’m just curious to hear what the “fundamentalists” think about it.

I’ll let the tubes argue about the value of getting chocolate in our peanut-butter.

The Reese’s project has already proven the success of that amalgam. No discussion necessary.

Author
Dan Mall
Posted
Jun 28th, 2007 11:30 am
018

@Ethan: v004 adds support for child and adjacent selectors. I assumed support was already included but the original selector regex didn’t allow for selectors beginning with the necessary characters (> and + respectively).

Author
Shaun Inman
Posted
Jun 28th, 2007 11:48 am
019

Why try to blend them and create new syntax/structures for CSS?

I agree with Nate. Other than limiting the server calls (and the pure geeking out factor), I just don’t see the point. What am I missing here?

Author
Scott
Posted
Jun 28th, 2007 11:53 am
020

Okay, Shaun….

Now I’m going to play devil’s advocate. I already told you I thought this was cool, so do know I’m just arguing for the sake of arguing now, and not because I think there’s actually some flaw in your approach. Here goes…

If this is not necessarily supposed to feel like writing regular CSS, then what’s the advantage of it over simply using a programming language (PHP, Ruby, Python, whatever) to generate CSS on the fly? The later would be more robust and give you more flexibility, right?

To me, the beauty of what you’ve done is the fact that it all basically feels like writing CSS. You’ve added a few bits here and there, but for the most part, the syntax is just like writing regular CSS. The one place that that falls down, at least to me, is the enclosing set of brackets needed to do the nesting. Doing that requires a shift in the way I think about writing CSS, probably breaks syntax coloring in my text editor, and just generally makes me feel like I’m not writing CSS at all. And, I think Carl’s right — it does imply some scoping that doesn’t really exist, which is a bit weird.

To summarize — what I love it that is basically feels like writing CSS, but gives me some of the power of a programming language. The whitespace suggestion was just an idea to further facilitate that.

Again, I’m not bagging on this — I criticize because I care! I like the concepts a lot. I just want writing CSS to feel as much like writing CSS as it can, I guess. :)

Author
Jeff Croft
Posted
Jun 28th, 2007 12:01 pm
021

We’re just going to have to agree to disagree—I say “tomayto” you say “tomahto.” Indenting feels like nesting to you because of your experience with Python. Nesting (within curly brackets) feels like nesting to me because of my experience with PHP/JavaScript. To me, indenting just doesn’t suggest a nested relationship between the two selectors.

To me, the current syntax feels like writing CSS with the added ability of physically nesting selectors.

As for the question of scope, is the way nesting currently works similar to another programming construct that implies scope? I don’t understand why a property defined outside a nested selector implies that the property would also be applied inside the nested selector.

Author
Shaun Inman
Posted
Jun 28th, 2007 12:26 pm
022

That’s cool, Shaun. :)

Re: Scope:

with unordered_list {
    font_size = 10
    for list_item in unordered_list {
        (font_size still equals 10, right?)
    }
}

ul {
    font-size: 10px;
    li {
        (does font size still equal 10px?)
    }
}
Author
Jeff Croft
Posted
Jun 28th, 2007 12:39 pm
023

Ah, see, I have never encountered the with construct before. I understand the confusion now. SSPP is not a programming language, just slap on those contextual blinders and know that nesting is essentially just shorthand for descendent selectors. That’s it. There is no inheritance other than the normal CSS inheritance.

In your example, font-size does equal 10px but because of normal CSS inheritance, it is not hardcoded into the generated ul li output.

Author
Shaun Inman
Posted
Jun 28th, 2007 1:07 pm
024

regarding the question of mixing CSS and PHP…

could the same questions be asked of mixing HTML and PHP? it seems that our collective idea that CSS is not something to be output using logic may be misguided, hindering progress with what we do with CSS.

not that some are not doing this, but it’s really something I haven’t thought deeply about, and there seems to be a lack of development of these types of ideas. why not Smarty for CSS (or does that already exist?)

Author
dan c.
Posted
Jun 28th, 2007 1:08 pm
025

Yep, I second SASS. And if you are looking at SASS - then you might be also interested in HAML, which does the same for html.

Check them out - and forget about complex/broken css and html for ever. http://haml.hamptoncatlin.com

Author
evgeny
Posted
Jun 28th, 2007 1:10 pm
026

@dan c. — very good point. HTML, like CSS, is meant to be very simplistic but I think we’ve all gotten so used to embedding other languages into HTML that no one bats an eye anymore.

People could argue all day long about the importance of separating style from content, display from logic, etc.

Personally, I kinda like the idea of a little intermingling as long as it’s done with productivity in mind. There’s nothing wrong with trying to make CSS smarter if it helps you work faster.

Author
DSW@TNM
Posted
Jun 28th, 2007 1:23 pm
027

In your example, font-size does equal 10px but because of normal CSS inheritance, it is not hardcoded into the generated ul li output.

Actually, it probably equals 10px, but it depends on what selectors were set before it. For example, it wouldn’t equals 10px if there was a:

 * li { font-size: 12px !important; }

before it. :)

Author
Jeff Croft
Posted
Jun 28th, 2007 2:41 pm
028

I think that it is a personal preference thing. For instance, I think using SMARTY for templates is stupid - why not just use the variables you need? It’s trying to dumb down the process - while adding an unnecessary layer in the middle.

Look at frameworks today (not sure about Django). Rails, CakePHP, Symfony, etc all simply let you use declared vars from your controllers. They don’t add an extra layer of tags for you to have to learn when you could have just as easily called the variable/construct from whichever language.

I guess that is my feeling here. Its like its adding another layer to CSS - instead of just using CSS yourself.

Is it that much harder to type ul li? I guess I just fail to see the overall benefits of it all. Yes, you can use whatever language you want to do compression, caching - but im just not sure why these two (PHP/CSS) need to be mixed as such.

Again, personal opinion.

Author
Nate Klaiber
Posted
Jun 28th, 2007 3:15 pm
029

Nate, FYI — Django has a template language that uses the variables from the controllers, but doesn’t allow pure Python. That’s the default setup, but Django is totally modular, so if you prefer to do something else (like use a different template language that allows full Python), you’re free to.

Author
Jeff Croft
Posted
Jun 28th, 2007 3:28 pm
030

@Nate

Is it that much harder to type ul li? I guess I just fail to see the overall benefits of it all.

I think that might be the case. Shaun’s method isn’t to saving typing. It allows values to be dynamic. In a production environment where things need to change constantly, a variable that’s easily updated is a dream as opposed to searching for and replacing values within a CSS file.

Author
Dan Mall
Posted
Jun 28th, 2007 3:45 pm
031

@Dan I understand what you are saying. I am not comparing it to not using something dynamic, I am comparing it to just using PHP/CSS to build your sheets and cache. The creating variables and another pseudo language for CSS is what doesn’t make sense to me so much.

@Jeff Thats cool. I guess I just haven’t seen templates that are true abstraction templates and are good performance wise. The whole point of being modular is the ease of being able to switch to something else. For databases, thats what ActiveRecord or another data mapper does - it allows you to control your business logic independent of the underlying data storage (MySQL, Postgres, Oracle, etc). I haven’t seen a templating language that does this. So if I switch between languages (such as PHP, Ruby, Python) - the template will still work fine. Maybe I just haven’t found the right one I guess. So is Django’s templating somewhat like Smarty for PHP?

Author
Nate Klaiber
Posted
Jun 28th, 2007 4:10 pm
032

after thinking about it some more, I’m not sure that CSS lends itself to using variables for different things. or at least it’s strange enough that it doesn’t quite make sense.

a site uses a certain shade of blue based on the company’s colors. if you use a variable, what is that variable? lightBlue? secondaryCorporateColor? within the template, or whatever we’re calling the stylesheet with the variables, this doesn’t seem to add much value.

or, it only adds value when you need to change it, but only if you can figure out a variable naming scheme that makes sense.

that said, there are always specific situations where variables in stylesheets make a lot of sense. any other ideas on when it would be really useful?

otherwise, would well structured and code stylesheets would seem to take care of most of the advantages of variables?

Author
dan c.
Posted
Jun 28th, 2007 5:09 pm
033

Sorry, the Rails weenies beat you to the punch: http://blog.airbladesoftware.com/2006/1 … p-your-css

Author
bascule
Posted
Jun 29th, 2007 2:32 am
034

So is Django’s templating somewhat like Smarty for PHP?

Syntactically, it’s similar (it uses the {{ }} notation for variables like Smarty), but it’s much much more robust. It supports basic programming constructs like for loops and if statements, and provides a really simple API for apple template tags if what you need isn’t there (the tags are written in pure Python, so while the template language doesn’t allow Python, you do still have the ability to write a new tag, using the full power of Python). It also has a really, really nice inheritance system that keeps it very DRY.

Django’s template language is written as a totally abstracted module. You can use Django with or without it, and you can use Django’s template language with other frameworks/CMSes/languages/whatever.

Author
Jeff Croft
Posted
Jun 29th, 2007 12:12 pm
035

Hi Shaun,

Great update! I’ve found that the code tends to break when trying to process reset scripts, especially those that use content: “”;. There’s quite a simple fix, when you do the transformation into xml replace the " with ” and all will be well.

$xml = preg_replace(‘/([-a-z]+)\s:\s([^;}{]+)(?:;)/ie’, “””, $xml); // Transform properties $xml = str_replace(‘"’, ‘”’, $xml); $xml = preg_replace(‘/^(\s)([+>#:.a-z][^{]+){/me’, “’$1’,’>’,’$2’))).’">’”, $xml); // Transform selectors

I’ve got an addition that adds browser selectors that I can post up later that might interest some people.

Author
PhillS
Posted
Jun 29th, 2007 1:03 pm
036

I’ve always been interested in CSS selectors, it feels natural, probably just because of HTML.

Perhaps parts of this will one day become part of the CSS spec as an alternative notation format.

What I really like is that CSS-SSPP compliments well Jeff’s work with CSS Framework’s.

@Shaun Is there any intention to put CSS-SSPP up on Google Code. It could also do with a more interesting name.

Author
Keri Henare
Posted
Jun 29th, 2007 1:27 pm
037

Hi Shaun,

Great information, nice! It allows values to be dynamic. I kinda like the idea of a little intermingling as long as it’s done with productivity in mind.

thanks.

Author
Hag
Posted
Jun 29th, 2007 3:36 pm
038

Wow, that’s actually pretty cool Shaun. Will definitely play around with this!

Cheers!

Author
Frederick Townes
Posted
Jun 30th, 2007 4:34 am
039

Very cool! Here about your site in Japanese! http://youmos.com/news/css_server_side_pre_processor Thanks!

Author
youmos
Posted
Jul 2nd, 2007 4:04 am