How I fell in love with CSScaffolding

Have you ever had that helplessness feeling while scrolling through veeeery long stylesheets, trying to find one selector? Sure – tabbing helps a lot but it’s not as good as using proper nesting. I’ve seen few solutions giving you that functionality but it was Anthony Short’s CSScaffold I decided to try out, mainly due its mixins support. I’m not going to go into details on how it actually works (if you’re interested in it make sure you visit project homepage) but instead I’ll show you real examples on how I used it on this site. As mentioned few lines above – the first useful feature is selector nesting. Except for regular ancestor-descendant relationship it also support states, multiple classes and all pseudo elements and selectors you want to use. It may be just me but it makes reading my CSS much faster. If you need a proof, here it is:

 #myUL{ float : left; + dim(700 px, 2 em); + res; + clear; li{ list-style : none; list-style-image : none; float : left; a{ color : !I; &:hover{ color : ! A; } } &.current-cat a{ color : ! CURR; } } > li:first-child > a:first-child{ padding : 0.4em 0.67em 0.4em 0.3em; } } 

Genius, isn’t it? I’m sure you are wondering what all those +name; and !name; expressions do, right? That’s the main reason I love CSScaffold so much – ability to create your own inline function-like blocks and constants you can call from anywhere in your style sheet. So, for example, instead of having:

 #div1{ margin : 0; padding : 0; border : 0; color : #fff; background : transparent url(sprites.png) no-repeat -20px -100px; width : 100px; height : 200px; position : relative; overflow : hidden; } #div99{ margin : 0; padding : 0; color : #fff; background : transparent url(sprites.png) no-repeat -200px -180px; width : 600px !important; height : 40px !important; } #div99 span{ color : #7f0101; } #div99 span.alt{ color : #dadada; } 

you define your constants and mixins somewhere on the beginning and just call them later:

 @constants{ INACTIVE : #fff; ACTIVE : #7f0101; ALT : #dadada; SPRITE : transparent url(sprites.png) no-repeat; } =clear(){ position:relative; overflow : hidden; } /* set element dimensions */ =dim(!width = 0, !height = 0, !imp = ''){ height : !height !imp; width : !width !imp; } /* there's already built in 'reset' mixin, */ /* that's why i'm using 'res' instead */ =res(!m = 0, !p = 0, !b = 0){ @if (!m !== false) { margin : !m; } @if (!p !== false) { padding : !p; } @if (!b !== false) { border : !b; } } /* USAGE */ /* ------- */ #div1{ color : !INACTIVE; background : !SPRITE -20px -100px; +dim(100 px, 200 px); +res; +clear; } #div99{ color : !INACTIVE; background : !SPRITE -200px -180px; +res(0, 0, false); +dim(600 px, 40 px, !important); span{ color : !ACTIVE; /* '&' represents _self - in this case 'span' */ &.alt{ color : !ALT; } } } 

As you can see you can supply each mixin with extra parameters, define their default values and – another amazing feature – use simple @if(condition){}@else{} conditionals within.

But don’t think it ends up here – you can also perform math calculations! In fact everything eclosed by #[] will be parsed as raw PHP! I found it very useful for figuring out background positions of social bookmarks icons in my sprite png. Imagine two 10×3 grids of same-sized icons grouped somewhere in your sprite container. I’m not saying it’s difficult to manually enter correct positions but why bother if you can simply use CSScaffold instead?

 @constants{ /* startx, starty, w, h */ SOCIALS : -661,-157,29,29; } /* ----------- / col - column number / row - row number / startx - top left (first) icon's x value [px] / starty - top left (first) icon's y value [px] / w - icon width / h - icon height */ =bpos(!col=0, !row=0, !startx=0, !starty=0, !w=10, !h=10){ background-position:#[!startx - !col * !w]px #[!starty - !row * !h ]px !important; } #icon-mini-facebook{ +bpos(1, 1) /* renders out background-position:-10px -10px !important; */ } #icon-large-facebook{ +bpos(1, 1, !SOCIALS); /* renders out background-position:-690px -186px !important; */ } 

I’m using actual names as IDs but if you don’t really care about semantics you could (wait for it… wait for iiiitttt….) run a loop! (:

 =bpos(!i=0, !perrow=10, !startx=0, !starty=0, !w=10, !h=10){ background-position:#[!startx - (!i - floor(!i/!perrow)*!perrow) * !w]px #[!starty - floor(!i/!perrow) * !h ]px !important; } @for !i from 0 to 29{ .icon-mini-!i { +bpos(!i); } } 

If that’s still not enough for you, you can build your own PHP class extension, which could be useful for generating styles based on date, user agent, DB value or simply running more complicated calculations e.g. rendering Julia set fractal as table cells(; Those custom modules can be then called like this:

 div{ myfunction : (whatever,suits,you); myotherfunction : it is all RegEx; } 

It also has tons of pre-built mixins, plug-ins and modules for all you CSS maniacs out there. You can use it for cross-browser CSS 2.1-3 styling or even grid creation!

 /* example taken from project's website */ @grid{ column-width : 60; column-count : 12; left-gutter-width : 10; right-gutter-width : 10; baseline : 18; } #id{ +columns(4); } 

If that hasn’t convinced you how amazing CSScaffold is I’m not sure what will?(:

UPDATE:Since nothing is perfect (maybe except for strawberries in whipped cream;P) I wasn’t too surprised to find a bit of annoying thing in CSScaffold. Whether you like it or not – it likes to complain about white-space. It’s OK to use tabs or spaces for proper CSS, but if you start adding it to mixin calls for example it die in pain. Fortunately thanks to built-in Firebug console error reporting (finally someone thought about other devs!) you can quickly track it down. I’m sure it will be fixed in the future but for the time being you may want to try modifying csscaffoldsystemcoreCSS.php and replace function find_selectors_with_property in line 294 with this:

 public static function find_selectors_with_property($property, $value = " />.*?" />, $css = " />" />){ if($css == '') $css =&self::$css; if(preg_match_all('/([^{}]*)\s*\{\s*[^}]*('.$property.'\s*\:\s*('. $value .')\s*\;).*?\s*\}/sx', $css, $match)){ return $match; } else { return array(); } } 

It’s not heavilty tested workaround but so far it’s been doing the trick for me.

  • Naresh

    Good Article