CleverCSS is a small markup language for CSS inspired by Python that can be used to build a style sheet in a clean and structured way. In many ways it's cleaner and more powerful than CSS2 is.
The most obvious difference to CSS is the syntax: it is indentation based and not flat. While this is obviously against the Python Zen, it's nonetheless a good idea for structural styles.
To get an idea of how CleverCSS works you can see a small example below. Note the indentation based syntax and how you can nest rules:
ul#comments, ol#comments: margin: 0 padding: 0 li: padding: 0.4em margin: 0.8em 0 0.8em h3: font-size: 1.2em p: padding: 0.3em p.meta: text-align: right color: #ddd
Of course you can do the very same in CSS, but because of its flat nature the code would look more verbose. The following piece of code is the CleverCSS output of the above file:
ul#comments, ol#comments { margin: 0; padding: 0; } ul#comments li, ol#comments li { padding: 0.4em; margin: 0.8em 0 0.8em; } ul#comments li h3, ol#comments li h3 { font-size: 1.2em; } ul#comments li p, ol#comments li p { padding: 0.3em; } ul#comments li p.meta, ol#comments li p.meta { text-align: right; color: #dddddd; }
But that's only a small example of what you can do with CleverCSS. Have a look at the following introduction to CleverCSS.
On the one hand you can easily convert an ordinary CSS file into a CleverCSS one by indenting it correctly and removing braces. On the other hand you have some small syntactic and semantic differences that result from having inline expressions in rules.
CleverCSS allows you to use a limited amount of expressions in the attributes. That means it has some limited understanding of the values it is dealing with. To keep things simple, CleverCSS does not implement all the rules defined in the recent CSS version, but most of the data types are supported:
Strings are basically everything that is not handled otherwise. If you want to enforce a value to be a string you can quote it. These are all examples of valid strings:
foo "foo and bar" =
Especially the last one might surprise you.
The syntax for selectors is the same as for CSS, but instead of using braces to group the attributes that belong to a particular selector, CleverCSS uses indentation. It's important not to forget the trailing colon that indicates a block:
list, of, selectors: list of attributes ...
Additionally you can nest rules in a block so that you don't have to write the selectors a second time:
#main: p: ...
Does exactly the same as:
#main p: ...
Per default, nested rulesets are joined with a whitespace, the normal CSS rule separator. Sometimes you want to use a greater than sign or any other rule separator. You can do so by using the ampersand sign:
body: & > div.header: padding: 3px
Basically the nested rule is moved one layer up and the ampersand is replaced with the parent rule:
body > div.header { padding: 3px; }
You can also use this to add pseudo-classes to links:
a: &:hover: color: red &:visited: color: blue
This would output a CSS like this:
a:hover { color: red; } a:visited { color: blue; }
Note: multiple occurrences of the ampersand symbol are replaced!
Attributes work exactly like in CSS, except of not being ended by semicolons. Additionally CleverCSS has a group operator (->) that allows grouping attributes with the same, dash delimited prefix. Example:
#main p: font-> family: Verdana, sans-serif size: 1.1em style: italic
This code will generate the following CSS:
#main p { font-family: Verdana, sans-serif; font-size: 1.1em; font-style: italic; }
CleverCSS allows you to define stylesheet-wide constants from both within your stylesheet, and the Python code if executed from a custom script. But constants defined in the stylesheet will always override constants supplied from the python code.
You can define constants at top level using the equals sign, and use them in attributes by prefixing it with a dollar sign:
background_color = #ccc #main: background-color: $background_color
One important thing is that constants don't work like Python variables. When a constant is assigned, CleverCSS will not evaluate it but store the expression. Thus you can reference variables in a variable definition that don't exist "yet":
foo = $bar bar = 42
If you somehow manage to create circular references (foo points to bar, which points back to foo), CleverCSS will give you a error message that points to the problematic variable.
If you have multiple expressions next to each other, delimited by nothing more than a whitespace character, you have created an implicitly concatenated expression. That means that once it's evaluated and converted to CSS, it will be delimited by a space character:
padding: $foo + 2 + 3 $foo - 2
Will result in (assuming $foo is 10):
padding: 15 8;
Concatenated expressions have a lower priority than lists, so this works too:
font-family: Verdana, Times New Roman, sans-serif
Which will result in the very same, just with a semicolon at the end.
CleverCSS has a limited understanding of the values it is dealing with. That allows it to perform some mathematical operations on it. CleverCSS recognizes the following operators: +, -, *, / and %. Additionally you can use parentheses to group and override the default operator priorities.
If all your operands are numbers the return value will be a number too, for all for those operators. If you want to calculate with numbers and values the return value will be a value. Calculating with only values is possible too but in that situation the units must be either the same or convertible. Keep in mind that 1cm * 1cm would result in 1qcm which is not a unit CSS provides and thus invalid.
If you're dealing with strings, you can use the plus operator to concatenate multiple strings. You can also multiply strings with numbers, see the examples below:
// calculations with numbers / values 42px + 2 -> 44px 10px * 2 -> 20px 1cm + 1mm -> 11mm (1 + 2) * 3 -> 9 // string concatenation foo + bar -> foobar "blub blah" + "baz" -> 'blub blahbaz'
You can also calculate with numbers:
#fff - #ccc -> #333333 cornflowerblue - coral -> #00169d
You can also add or subtract a number from it and it will do so for all three channels (red, green, blue):
crimson - 20 -> #c80028
All objects have methods you can call, depending on their type. To call a method on an object you just use a dot, the name of the method and parentheses around arguments. Also keep in mind that without the parentheses it's just a string:
foo.bar() // calls bar on foo without arguments foo.bar.baz() // calls baz on "foo.bar" without arguments blub.blah(1, 2) // calls blah on blub with two arguments 1 and 2
The following methods exists on the objects:
Additionally all objects and expressions have a .string() method that converts the object into a string, and a .type() method that returns the type of the object as string.
If you have implicitly concatenated expressions you can convert them into a list using the list method:
(1 2 3 4 5).list()
does the same as:
1, 2, 3, 4, 5
Colors in CleverCSS are special. Because CleverCSS recognizes over 100 color names, false positives are very likely. But most of the time you wouldn't notice that because colors are not converted into their hexadecimal equivalent if not forced (by adding a second number that alters the value). A second way to convert a number to the hexadecimal representation is calling the hex() method:
lavenderblush.hex() -> #fff0f5
The whole thing works differently for colors defined using the rgb() literal. Those are converted to hexadecimal representation right away:
rgb(255, 255, 255) -> #ffffff
If you want to use CleverCSS in your application, the following few steps help you getting started quickly.
If you have the easy_install utility installed, you can install CleverCSS with the following command:
sudo easy_install CleverCSS
(if you are on a Windows box, omit the sudo and make sure you are executing the command as system administrator)
If you don't have easy_install, you can download the most recent version of CleverCSS from the cheeseshop.
Using CleverCSS is straightforward. If you want to use it from within Python, you can just import clevercss and call the convert() function with the clevercss source code. If you want to provide defaults for variables you can pass it a dict of strings with valid CleverCSS expressions.
Here a small example:
import clevercss print clevercss.convert(''' body: background-color: $background_color ''', {'background_color: 'red.darken(10)'})
If you want to use it from the shell, you can use the clevercss.py script. For usage help use this command:
clevercss.py --help