Less CSS
by Arne Hassel
CSS is powerful in its own rights, but when it comes to large, complex websites filled with elements that doesn’t necessarily share styles easily, the styling quickly becomes messy and hard to navigate. Conventions, frameworks and guidelines help structure the code, and tools such as Firebug helps the process. But my eyes still get soar when scanning through code-snippets such as:
#header { ... }
#header .menu { ... }
#header .menu ul { ... }
#header .menu ul li { ... }
#header .login { ... }
#header .login ul { ... }
I like my html to be semantically good structured (or as good as it can get when keeping certain obstacles in mind *cough*IE6*snirk*). That means not overloading it with classes that doesn’t add meaning (such as clearfix, which I use in all of my projects). CSS doesn’t have a good way of reusing this code within the stylesheet, and this is a shame.
And then there’s the classic need for variables. When trying out different color-schemes in a design, it’s a pain if you have to update a color-code multiple places in the stylesheet. Even more fun if they’re scattered throughout the document. And what if you the color-scheme to front different colors, each related to a base-color?
LESS to the rescue!
LESS provides a solution to all of these problems. Mixins, Nested Rules, Variables and Operations are the features fronted by the developers, Alexis Sellier and Dmitry Fadeyev. I’m especially fond of the two former, which allow me to write code such as:
.clearfix { /* rules for clearfix-hack */ }
.horizontal { .clearfix; width: 100%; }
.horizontal_items { display: inline; float: left; }
.horizontal_links { display: block; }
.vertical { .horizontal; }
.vertical_items { display: block; float: none; }
.vertical_links { .horizontal_links; }
#header {
ul {
.horizontal;
li {
.horizontal_items;
a {
.horizontal_links;
}
ul {
.vertical;
display: none;
position: absolute;
li {
.vertical_items;
a {
.vertical_links;
}
}
}
}
li:hover,
li.hover {
ul {
display: block;
}
}
}
}
When matched with markup such as:
<div id="header">
<ul>
<li>
<a>item 1</a>
<ul>
<li>
<a>subitem 1a</a>
</li>
<li>
<a>subitem 1b</a>
</li>
</ul>
<li>
<li>
<a> item 2</a>
</li>
</ul>
</div>
It’s displayed as a horizontal menu, with vertical submenus. And it works in IE6 too (only need some minor JavaScript to mimic :hover, since IE6 only supports :hover for a-elements).
When reusing style in this matter, it’s much more simpler when it comes to refactoring (which I’m considering for clearfix after reading this blog-entry (via cjohansen [norwegian])). This is especially important when dealing with CSS that aren’t standardized in all browsers yet, which are implemented with browser prefixes. Come the day when a browser vendor changes its implementation of a property, you can easily change your usage of it.
My usage of LESS
Currently I’ve tried the ported versions of LESS for .NET and PHP (as a plugin for WordPress). I can vouche for both these, altough they have slightly different implementation (RTFM).
If you wish to learn and use LESS, I can recommend this article on Nettuts. Otherwise, I would recommend you to read the documentation provided with the different projects.
Shortcomings
Although LESS is a joy to use, I do have some problems. For example, consider the code written when using modernizr (a JavaScript-library that enables feature detection of CSS3):
.rounded_corners (@radius: 5px) {
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
border-radius: @radius;
}
#header {
.button {
/* CSS that all browsers supports */
}
}
.borderradius #header .button {
rounded_corners;
}
This may seem but a slight irritation, but consider this example if #header parented style for 20+ sub-elements. Add the possibility that I wanted to use other CSS3-properties. I have no answer to how this should be solved, but my 2 cents would be the possibility to write code such as:
#header {
.button {
/* CSS that all browsers supports */
[.borderradius] {
rounded_corners;
}
}
}
This would equal the meaning in the former snippet, but its superior in elegance (at least in my view).
I find that mixins and nested rules are great concepts by themselves, but I miss that they can’t be combined (at least not in the versions I’ve tried). Take the example below:
.horizontal { .clearfix; width: 100%; }
.horizontal_items { display: inline; float: left; }
.horizontal_links { display: block; }
This would have been so much better if it could’ve been written
.horizontal {
.clearfix;
width: 100%;
li {
display: inline;
float: left;
a {
display: block;
}
}
}
(Even better, I would’ve used the E > F-selector, but alas, that isn’t supported by IE6)
That was my intention, after all. Now the code for a horizontal menu would be:
#a_horizontal_menu {
.horizontal;
}
Instead of:
#a_horizontal_menu {
.horizontal;
li {
.horizontal_items;
a {
.horizontal_links;
}
}
}
It would be nice to not be required to construct the latter code.
Finally, it would be nice to drop the curly brackets, so that the syntax is similar to Python or Sass.
http://sass-lang.com
@Tobias: Although I would liked a little more than a single url (which I myself include in the post), I did read more of the documentation, and found a reference to parent selector referencing (with the &-symbol). Very interesting.
I also stumbled upon Compass, which seems really interesting. I see that it has a project to enable it for Django, so it might be interesting in our next project, Aurora.
After reading up on parent selector referencing, I understand now that is it not what I suspected it to be. To bad=(
To test my understanding:
a { &:hover { /* something */ } }Would become
a:hover { /* something */ }i don’t know if this option existed in sass when you posted your comment but with the parent selector in sass you can solve your problem like this
a {
&:hover {
/* something */
}
.another }
would become
a:hover {
/* something */
}
.another a {
/* something else */
}
if that was added to less then it should help
Thanks for the comments ^_^
I haven’t tried sass so much, but I work with Less Css for .NET quite much, and I imagined I’ve tried the parent-selector postfix before, and it didn’t work. Will try next time though =)
I tried post-& with Less Css for .NET today at work, and didn’t manage to make it work.
Nevertheless, it doesn’t solve my problem, since it only refers to the parent element. I want to insert selectors before the parent-element, e.g.:
a { [p] { something; } }
becomes
p a { something }
I don’t know if this is intuitive, but it would enable me to combine modernizr and less css more nicely, since it would build upon the notion of nesting.
i wasn’t clear – they aren’t supported in less (see https://github.com/cloudhead/less.js/issues/127). i was just showing you that there was more to parent selectors in sass than you had realized. the last line of my poorly formatted post was: “if that was added to less then it should help”
[...] jobb, som har inkludert opplæring i konvensjonene våre for markup og semantikk, samt vår bruk av LESS for å håndtere [...]
Hi, great write up.
I opened an issue on github for the Modernizr “conditional selector” problem:
https://github.com/cloudhead/less/issues#issue/172
I hope that [selector] syntax can be implemented.
Have you come up with a better workaround?
Can’t say that I have =(
Would be nice if the [selector]-syntax was implemented, but I’m uncertain if it’s the best choice. I’m not certain if it takes all existing functionalities into consideration, and it may cause some unwanted loopholes.
That said, I tried some “experimentation” with it, and it seems to work fine:
.class1 { /*something 1*/ [.class2.class3] { /*something 2*/ [.class4] { /*something 3*/ } &[.class5] { /*something 4*/ } } /*something 5*/ }Translates to:
.class1 { /*something 1*/ /*something 5*/ } .class2.class3 .class1 { /*something 2*/ } .class4 .class2.class3 .class1 { /*something 3*/ } .class2.class3.class5 .class1 { /*something 4*/ }The experiments may not be exhaustive, but I think it’s safe to try ^_^