How to Squeeze the Most out of LESS

How to Squeeze the Most out of LESS

Tutorial Details
    • Programs: lessphp, csspie
    • Difficulty: Easy
    • Estimated Completion Time: 1hr

During a sick day a few weeks ago, I got around to something I’ve been meaning to look at for about a year: LESS. If anything web technology is worth a look, I promise LESS is. In this article, we’ll look at the amazing power of LESS and its ability to streamline and improve your development process. We’ll cover rapid prototyping, building a lightweight grid system, and using CSS3 with LESS.


Getting Started: What We’ll Be Using

For this tutorial, I will be using the PHP LESS implementation by Leaf Corcoran. This implementation is only one of many and the principles discussed in this tutorial should apply to any LESS implementation. Other versions of LESS include the original Ruby version and a JavaScript implementation.

Start by downloading the latest version of LESS. After you extract the file, you should have a ‘lessphp’ folder. Inside you will find a file called ‘less.inc.php’: that’s the one we want. Take this file and place it in your site’s CSS folder.


Setting Up Your Master PHP Stylesheet

The way LESS PHP works is by parsing .less files and converting them to CSS, that the browsers can understand. LESS PHP can accomplish this task in several ways, but we are going to be using a simple PHP class method to parse the CSS; other methods are discussed in the LESS PHP documentation. All right, let’s write some code.

Create the file styles.php in your site’s CSS folder.

        <?php
        if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); 
        else ob_start();
    

The first line is merely a means to gzip the final “CSS” file, reducing its file size; this is always a good practice. You could also do this via an .htaccess file.

        $files = array(
            'styles.less'
        );
    

In this code we are setting up the paths to our .less files (we’ll add more later) and storing these paths in an array. The one thing about LESS PHP is that the parsing can take a while; it can take up to a few hundred miliseconds if you have 20K+ of .less file. It also uses server resources. If you are going to be using the PHP version, caching is a must. Let’s see one way that we could accomplish this.

        $time = mktime(0,0,0,21,5,1980);
        $cache = 'cache.css';

        foreach($files as $file) {
            $fileTime = filemtime($file);

            if($fileTime > $time) {
                $time = $fileTime;
            }
        }

        if(file_exists($cache)) {
            $cacheTime = filemtime($cache);
            if($cacheTime < $time) {
                $time = $cacheTime;
                $recache = true;
            } else {
                $recache = false;
            }
        } else {
            $recache = true;
        }
    

This code checks each of our .less files and gets the time each of them was last modified. This time is then compared to the modified time of the cache file, if it exists. If the cache file doesn't exist yet—or needs to be updated—we set $recache to true. Continuing on...

        if(!$recache && isset($_SERVER['If-Modified-Since']) && strtotime($_SERVER['If-Modified-Since']) >= $time){
            header("HTTP/1.0 304 Not Modified");
        } else {
            header('Content-type: text/css');
            header('Last-Modified: ' . gmdate("D, d M Y H:i:s",$time) . " GMT");

            if($recache) {
                require 'lessc.inc.php';
                $lc = new lessc();

                $css = '';

                foreach($files as $file){
                    $css .= file_get_contents($file);
                }

                $css = $lc->parse($css);
                file_put_contents($cache, $css);
                echo $css;
            } else {
                readfile($cache);
            }
        }
        ?>
    

If we don't need to recache and the client's browser has a copy of the file already, we compare the timestamp of the client's copy against the latest modified file's timestamp. If the client has the most up-to-date version, we send a 304 response and the browser doesn't need to download anything. If the client doesn't have a copy yet or has an outdated version, we set the header on our PHP file to be a CSS document and set the last-modified time to the time stamp of the most recently updated .less file.

If we need to create the cache file or update the cache file, we bring in the LESS PHP file. We require it as opposed to including it, because this portion of styles.php will not work without it. Next we loop through the files, assigning their contents to a single variable $css which is parsed by LESS PHP, saved to disc for future caching purposes (only one visitor to the site is needed to cache the file for everyone), and the parsed LESS is output as standard CSS. If the client needs a version of the file (an update or for the first time) and the cached CSS file is up to date, we simply serve that file up, resulting in a significant speed savings.


Using LESS

Before we go too far, we need to create the styles.less file we referenced in styles.php.

        @h1BG: #1D5A50;
        h1 {
            background: @h1BG;
            border-bottom: 1px solid @h1BG + #333;
            border-top: 1px solid @h1BG - #333;
            color: white;
            font-family: Helvetica, sans-serif;
            padding: 3px;
        }
    

For those unfamiliar with LESS, in this code we set a variable @h1BG and assigned it a dark green color. In the h1 rule, we made use of it three times: once we used the standard property, and the other two times we told LESS that we wanted the borders slightly lighter/darker than the background. LESS PHP performed the math on the hex values for us.

Now let's create a basic HTML document to make use of this new stylesheet.

        <!doctype html>
        <html lang="en">
            <head>
                <meta charset="utf-8">
                <title>My Less Demo</title>
                <link type="text/css" rel="stylesheet" href="css/styles.php">
            </head>
            <body>
                <h1>Sample Page Header</h1>
            </body>
        </html>
    

If everything went right, you should see something similar to the following image. This is a good time to mention that for LESS, PHP syntax and formatting is very important. If you don't space your variables quite right, your entire stylesheet can vanish due a parse error. In other words, make sure you test the new sheet before pushing changes to a live site.

example of the h1 tag with green background, lighter bottom border, darker top border

If you take a peek at the source of styles.php in your browser, you should see the following:

        h1 {
          background:#1d5a50;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:white;
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
    

Note that, not only is the variable appropriately applied, but the variable declaration doesn't appear in the final code. As a side note, LESS PHP condenses your CSS, but does not minify it.

Let's take things a little further now and see what else LESS can do. Make the following additions to your styles.less and HTML file (and while we're at it change @h1BG to @color4):

        @pageWidth: 1000px;
        @color1: #F0F0F0;
        @color2: #201A16;
        @color3: #3B3128;
        @color4: #1D5A50;

        #wrap {
            background: @color1;
            border: 2px solid @color2;
            margin: 0 auto;
            overflow: hidden;
            width: @pageWidth;
        }

        h1 {
            background: @color4;
            border-bottom: 1px solid @color4 + #333;
            border-top: 1px solid @color4 - #333;
            color: white;
            font-family: Helvetica, sans-serif;
            padding: 3px;
        }

        h2 {
            color: #A1915F;
        }

        #content, #skyscraper {
            float: left;
        }

        #content {
            border-right: 1px solid @color1 - #111;
            width: @pageWidth * .75;

            h2 {
                background: @color2;
            }

            p {
                background: #FFF;
            }
        }

        #skyscraper {
            width: @pageWidth * .25;

            h2 {
                background: @color3;
            }
        }
    
        <body>
            <div id="wrap">
                <h1>Sample Page Header</h1>
                <div id="content">
                    <h2>My Content</h2>
                    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                </div>
                <div id="skyscraper">
                    <h2>Be the first to advertise!</h2>
                </div>
            </div>
        </body>
    

Firstly, those of you who are not familiar with LESS may be confused by the rules within rules concept, a.k.a. nested rules. What it means is you don't have to type #content h2 {...}, #content a {...} anymore. It also lets you structure your CSS better so you can clearly see the CSS inheritance chain.

For those of you coding along, you've noticed a few problems. The 1px border on #content is causing our ad section to drop below. This is the same problem you would get if you had defined the widths as 75% and 25%. As many of you know, margin, borders, and padding can wreak havoc with floated, percent-based layouts. So let's fix some of that; it would be nice if the content wasn't so bunched up. Make the following change to styles.less:

        @contentRightBorder: 1px;
        @contentLRPadding: 15px;

        #content {
            border-right: @contentRightBorder solid @color1 - #111;
            padding: 0 @contentLRPadding 5px @contentLRPadding;
            width: (@pageWidth * .75) - @contentRightBorder - (2 * @contentLRPadding);

    
float problem before and after

Mixins

As you can already tell, I'm not a designer (though the color scheme isn't a bad one *wink*). However, if I was, I would want the headers on the site to have similar characteristics. Let's do it the LESS way. Add the following to styles.less:

        .header(@headingBackground: @color4; @headingFontColor: #FFF;) {
            background: @headingBackground;
            border-bottom: 1px solid @color4 + #333;
            border-top: 1px solid @color4 - #333;
            color: @headingFontColor;
            font-family: Helvetica, sans-serif;
            padding: 3px;
        }
    

That is called a mixin; think of it like a CSS function. We can apply it to our headers. Make the following changes:

        h1 {
            .header();
        }

        #content {
            h2 {
                .header(@color2; #A1915F;);
            }
        }

        #skyscraper {
            h2 {
                .header(@color3; #A1915F);
            }
        }

    

Let's take a look at just the header's CSS output to see if we can learn anything about LESS.

        .header {
          background:#1d5a50;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#ffffff;
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
        h1 {
          background:#1d5a50;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#ffffff;
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
        #content h2 {
          background:#201a16;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#a1915f;
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
        #skyscraper h2 {
          background:#3b3128;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#a1915f;
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
    

You can end up with a lot of duplicate code if you are not careful.

This is the main downside with LESS from what I can see: you can end up with a lot of duplicate code, if you are not careful. Be sure to consider what code you insert -- especially in mixins. In the code output we have a class .header that is not used, and multiple properties that are unnecessarily duplicated. Remember, when working with LESS, you are working with both it and CSS, so CSS best practices still apply. A better way to write this would be:

        h1, h2, h3 {
            font-family: Helvetica, sans-serif;
            padding: 3px;
        }

        @header(@headingBackground: @color4; @headingFontColor: #FFF;) {
            background: @headingBackground;
            border-bottom: 1px solid @color4 + #333;
            border-top: 1px solid @color4 - #333;
            color: @headingFontColor;
        }

        h1 {
            @header();
        }

        #content {
            h2 {
                @header(@color2; #A1915F;);
            }
        }

        #skyscraper {
            h2 {
                @header(@color3; #A1915F);
            }
        }
    

If we look at the code output now, we should see that the properties that should be grouped, are. The unique properties only show up in their respective rules and we don't have an unnecessary rule, .header, appearing in our css.

        h1, h2, h3 {
          font-family:Helvetica, sans-serif;
          padding:3px;
        }
        h1 {
          background:#1d5a50;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#ffffff;
        }
        #content h2 {
          background:#201a16;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#a1915f;
        }
        #skyscraper h2 {
          background:#3b3128;
          border-bottom:1px solid #508d83;
          border-top:1px solid #00271d;
          color:#a1915f;
        }
    

Unnecessarily Nesting Selectors

Another thing to be careful about is unnecessarily nesting selectors. If your CSS doesn't need to be that specific to work, don't nest it; it can be its own separate rule. LESS is here to help you write CSS, not to bloat your stylesheet. Don't use it to bring the DOM to your stylesheet; it's bad enough where it is. You don't want to end up with rules like #main .menu_items #center .menuTable table tr td.itemMoveDown a:hover {...}. For a reference point, take a look at the following:

        #wrapper {
            background: blue;

            #content {
                color: pink;

                .about {
                    float: left;

                    p {
                        span {
                            font-weight: bold;

                            a {
                                font-family: Aurabesh, sans-serif;
                            }
                        }

                        a {
                            font-family: Verdana, sans-serif;
                        }
                    }
                }
            }
        }

        /* (among other rules) results in: */

        #wrapper #content .about p span a {
            font-family: Aurabesh, sans-serif;
        }

        /* (depending on the DOM), better could be: */

        #wrapper {
            background: blue;
        }

        #content {
            color: pink;
        }

        .about {
            float: left;

            span {
                font-weight: bold;

                a {
                    font-family: Aurabesh, sans-serif;
                }

            a {
                font-family: Verdana, sans-serif;
            }
        }

    

Don't use less to bring the DOM to your stylesheet, it's bad enough where it is.

Above, if in your site #content is always inside #wrapper, you don't need to specify #contents within #wrapper, and so on. From before, if your document has tds that aren't within rows or tables, you have other problems. Again, before you nest, make sure it is saving you time and is necessary. As a general rule of thumb, never nest inside of body or your main div.

Ok, back to our example. So you've just shown the site to the customer. It was too wide for his smartphone, so he would like his site to be 800px wide instead. Oh, and he wants his colors to be a light blue and a dark blue, and the green should be an orange. Assuming he wants to keep the same proportions, how many lines do we have to change for the new layout and theme? Just four:

        @pageWidth: 800px;
        @color2: #9CDCF8;
        @color3: #0E0E7A;
        @color4: #F89500;
    

In the old days, with a larger site, this could mean digging through dozens of CSS files, redoing width calculations and updating multiple colors throughout. With LESS, it is trivial. Later we'll explore how you could take this concept even further.

Takeaways

  • LESS's syntax is similar to CSS.
  • LESS can do math on colors and units of measurement.
  • LESS variables can be used in multiple places in your CSS.
  • LESS can duplicate code, so use the same judgement you would with CSS.
  • LESS makes adjusting an entire site's CSS trivial.

A Flexible, Semantic, and Lightweight Grid

I don't know how many of you have worked with some of the popular CSS grid systems around, so let me introduce you to a few problems.

        <div id="wrap" class="w16">
            <div id="content" class="w12">
                <h2 class="g12">My Content</h2>
                <p class="g4">Sample text</p>
                <p class="g4">More sample text</p>
                <p class="g4">And some more sample text</p>
            </div>
            <div id="skyscraper" class="w4">
                <h2 class="g4">Still waiting for some ads!</h2>
                <p class="g4">Space is available</p>
            </div>
        </div>
    

This code hyperbole has a point: frameworks can cause gross code. Our markup has developed a serious case of 'classitis', not to mention that none of the classes are semantic. The CSS isn't too much better:

        g1, g2, g3 ... {
            display: inline;
            float: left;
            margin: 0 10px;
        }
        wrap2, wrap3 ... {
            margin: 0;
        }
        g1 { width: XXpx; }
        g2 { width: XXpx; }
        ...
        wrap2 { width: XXpx; }
        wrap3 { width: XXpx; }
        ...
        wrap12 g2, wrap12 g3 ... {
            width: XXpx;
        }
        ...
        alpha, omega, push, pull...
    

It ends up being dozens upon dozens of lines...minified. Most grid systems also suffer from a problem we encountered before. What if I want to add a border to an element, or some padding? Up until now, if you were working in one of these systems, you either had to add an extra div inside your "grid div" which had the border and padding, or you had to overwrite your grid rule saying #content { width: 699px; } because it has a border and some padding. We also run into a pretty bad problem if the client changes the site width, as this CSS has been tailor made to a specific content width and column count.

Flexible Grid with LESS

Ready to build a semantic, flexible grid system...in fourteen lines of code? Using only the knowledge we've already learned? Introducing grid.less:

        @unit: @pageWidth / 24;
        @gm: 10px;
        @g(@u: 20; @margin: @gm; @marginTop: 0; @marginBottom: 0;) {
            @gpadding: @gpadding + 0;
            @gborder: @gborder + 0;
            display: inline;
            float: left;
            margin: @marginTop @margin @marginBottom @margin;
            width: (@u * @unit) - ((@margin * 2) + @gpadding + @gborder);
        }
        @shift(@pu: -20){
            left: @pu * @unit;
            position: relative;
        }
        @newRow {
            clear: left;
        }
    

Ok, so it was seventeen lines, but I don't want to count the closing brackets. Let's step through the code. First, we are defining a LESS variable, called unit. Each unit is 1/24th of the page width. Feel free to pick any number you are comfortable with. I chose 24 because both it and its half (12) can be divided nicely by 2, 3, and 4. Shortly, we'll find that it doesn't matter what number you put here, grid.less can handle anything you throw at it. One thing to note however: Webkit browsers would like you to pick a number of columns that is divisible by your site width, or else they may lose one or two pixels if you put a bunch of small grid units on a line. Chrome and Safari don't like percent-based layouts either if the percent ends up with partial pixels. Firefox and IE (surprisingly) don't care: they handle the difference by adding in the extra pixels throughout the elements, a pixel here and a pixel there.

On the second line, @gm stands for grid margin; on the next, @g stands for grid unit. Both are short to make it easier to type when applying, but having short names won't reduce your file size at all, because LESS variables and @-prefixed mixins don't get output to the final CSS file when the LESS files are parsed. You don't have to advertise your grid system in your CSS any longer since the grid magically disappears. Thanks LESS!

Back to the code. In the @g mixin, the first parameter is what unit the element is: 2, 4.8, 6, 12, etc. Wait...4.8? Sure; you wanted five same-sized boxes filling a row on the page, didn't you? 24/5.

The second parameter is the default margin we have between our page elements; it takes the value defined by @gm. Want them closer? @gm: 5px. Further? @gm: 10px or @gm: 12px. LESS can do it.

Looking at the code once more, you may notice we are lacking a wrapping element that most grid systems have. Or are we? Apply @g(12; 0;) to a rule. Done.

We also have the option to pass margin-top and margin-bottom into our grid function as the third and fourth parameters. This is nice for two reasons. First, it allows us to utilize the margin shorthand code; and second, we only have to manage the margins in one place, the mixin call.

Inside the mixin, we are pulling a slight trick. With LESS PHP the @gpadding and @gborder, which are used to do our width calculation, are always 0 unless they are defined in the CSS/LESS rule before we apply the @g mixin. In other versions of LESS, you may need to engineer a different reset such as passing it in as a parameter into the mixin.

@shift is used primarily to aid in SEO purposes. Generally, it is good practice to put your main content as early in the document as you can for search engines to give it a good weight. Sometimes, the designs we are given indicate that other content—such as a sidebar or advertisement—comes first. With shift, we can maintain good markup and still achieve our desired design. @shift can accept either positive or negative units. @newRow is merely a convenient reminder; it isn't really needed, as you can easily type clear: left on your own. If you do, we're back to those 14 lines I was hoping for earlier.

Our Grid in Use

Enough talk, it's time to see an example so we can wrap our heads around all of this. Let's start the code fresh. In styles.php we will now have 3 less files: settings.less, grid.less, and styles.less. Settings.less will get our color scheme variables, the heading code, and the site width. Don't forget to wipe styles.less so we can work with some new markup. Let's also make movie5.html.

Your file array in styles.php should look like the following:

$files = array(
    'settings.less',
    'grid.less',
    'styles.less'
);

The markup for movies5.html:

        <div id="page">
            <h1>My Movies</h1>
            <ul id="site-navigation">
                <li><a href="#">Movie 1</a></li>
                <li><a href="#">Movie 2</a></li>
                <li><a href="#">Movie 3</a></li>
                <li><a href="#">Movie 4</a></li>
                <li class="selected"><a href="#">Movie 5</a></li>
                <li><a href="#">Movie 6</a></li>
            </ul>
            <div id="movie">
                <h2 id="movie-title">Movie 5</h2>
                <div id="dvd-cover">
                    <img alt="movie poster">
                </div>
                <p id="short-description">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
                <div id="characters">
                    <div class="character">
                        <h3>Farmer</h3>
                        <img alt="feeling cold">
                        <p>About this character...</p>
                    </div>
                    <div class="character">
                        <h3>Gunslinger</h3>
                        <img alt="nice tent">
                        <p>About this character...</p>
                    </div>
                    <div class="character">
                        <h3>Princess</h3>
                        <img alt="fiery temper">
                        <p>About this character...</p>
                    </div>
                    <div class="character">
                        <h3>Sorcerer</h3>
                        <img alt="out of breath">
                        <p>About this character...</p>
                    </div>
                    <div class="character">
                        <h3>Frog</h3>
                        <img alt="swamp country">
                        <p>About this character...</p>
                    </div>
                    <div class="character">
                        <h3>Trusty Dog</h3>
                        <img alt="walking carpet">
                        <p>About this character...</p>
                    </div>
                </div>
            </div>
            <div id="main-ad" class="ad">Ad space available</div>
            <div id="secondary-ad" class="ad">Advertise here</div>
        </div>
    

Our new stylesheet for styles.less:

        #page {
            background: @color1;
            border: 1px solid @color3;
            overflow: hidden;
            margin: 0 auto;
            padding: @gm 0;
            width: @pageWidth;
        }

        h1 {
            @gpadding: 6;
            @g(6);
            @header();
        }

        #site-navigation {
            padding: 0;

            @g(18; 0;);

            li {
                background: @color2;
                padding: @gm / 2;
                @gpadding: @gm;
                @g(3; @gm; @gm;);

                &.selected {
                    background: @color4;
                }
            }
            a {
                color: #FFF;
                text-decoration: none;
            }
        }

        @midBlockHeight: 468px;

        #movie {
            @shift(3);
            @g(18; 0; @gm;);
            @newRow;
            min-height: @midBlockHeight;

            h2 {
                @gpadding: 6;
                @g(18; @gm; 0; @gm;);
                @header();
            }
        }

        #short-description {
            background: @color1 + #111;
            padding: @gm / 2;
            @gpadding: @gm;
            @g(12);
        }

        #dvd-cover {
            background: @color2;
            padding: @gm;
            @gpadding: @gm * 2;
            @g(6);

            img {
                background: #FFF;
                display: block;
                height: 100px;
                width: 100%;
            }
        }

        #characters {
            border-top: 1px solid @color1 - #222;
            @g(18; 0; @gm;);
        }

        .character {
            background: @color1 - #111;
            padding: 5px;
            @gpadding: 10px;
            @g(6; @gm; @gm;);

            h3 {
                margin: 0 0 5px;
                @header();
            }

            img {
                background: #FFF;
                display: block;
                float: left;
                margin-right: @gm;
                height: 50px;
                width: 50px;
            }
        }

        .ad {
            border: 1px solid @color2;
            height: @midBlockHeight;
            @gborder: 2;
            @g(3; @gm; @gm;);
        }

        #main-ad {
            @shift(-18);
        }

    

Assuming copy-and-paste worked, you should end up with something close to this:

example grid layout

A few notes on the previous LESS code. If you take a moment to study it, you will notice multiple times that I used the @g mixin to control vertical height, as well as the regular grid specification of the number of columns an element takes up. When defining top and bottom margin, if the element was not a wrapping element, I always passed in @gm as the second parameter to the mixin. I did this instead of entering the value that @gm was. The reason for this is that it only leaves one place if we decide we want to adjust the horizontal spacing between grid elements.

Also of note: whenever you define border or padding, you need to set @gborder or @gpadding to the sum of the respective horizontal units. Be sure to remember that a rule like padding: 5px; means 10px of total padding. Lastly you may have noticed an & in the code. With LESS PHP this is a joiner and results in li.selected. I could have just as easily moved .selected out of the li rule but still within the #site-navigation rule to achieve the same effect (it is actually 2 characters smaller in the CSS if you do).

It may not be THE perfect grid system, but I definitely think it can be with a little more work. It allows for semantic markup, avoids classitis, and can result in potentially a much smaller CSS footprint, since you only output the code you actually need. If you have any suggestions, please let me know by using the comments below.

I would be ungrateful if I didn't offer some special thanks to Kyle Blomquist, with whom I tossed around a few ideas.

Takeaways

  • Mixins can be used to define more complex systems. Figure out a problem that can be solved with math and create your mixin to put idea to browser.

Cross-browser CSS3

What's a tutorial these days without CSS3? LESS can make it easier on designers since they don't have to remember the cross-browser syntax differences. Create css3.less and add it to styles.php. We'll start with something basic, like a nice linear gradient.

        @linearGradient(@color1: #000000; @color2: #FFFFFF;) {
            background: -moz-linear-gradient(@color1, @color2);
            background: -webkit-gradient(linear, left top, left bottom, from(@color1), to(@color2));
            filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2);
            -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2)"; */
            -moz-background-clip: padding;      /* Firefox 1.0-3.6 */
            -webkit-background-clip: padding-box;  /* Safari, Chrome */
            background-clip: padding-box;  /* Firefox 4.0+, Opera */
        }
    

Well, if you haven't done it much, you'll soon realize that CSS3 rules are implemented somewhat differently when it comes to Firefox, Webkit, or not at all when it comes to IE pre-9. As a result, it limits LESS...slightly. For example, Firefox allows you to specify the degrees a gradient travels, but Webkit is limited to top left bottom left type definition. IE only has a filter with two types: vertical and horizontal. As a result, if we want another direction, we have to make another LESS mixin.

        @linearGradientH(@color1: #000000; @color2: #FFFFFF;) {
            background: -moz-linear-gradient(0deg,@color1, @color2);
            background: -webkit-gradient(linear, left top, right top, from(@color1), to(@color2));
            filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2, GradientType=1);
            -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2, GradientType=1)";
            -moz-background-clip: padding;      /* Firefox 1.0-3.6 */
            -webkit-background-clip: padding-box;  /* Safari, Chrome */
            background-clip: padding-box;  /* Firefox 4.0+, Opera */
        }
    

We can avoid a little of the duplication if we move the clipping properties to their own mixin.

        @backgroundClip {
            -moz-background-clip: padding;      /* Firefox 1.0-3.6 */
            -webkit-background-clip: padding-box;  /* Safari, Chrome */
            background-clip: padding-box;  /* Firefox 4.0+, Opera */
        }

        @linearGradient(@color1: #000000; @color2: #FFFFFF;) {
            background: -moz-linear-gradient(@color1, @color2);
            background: -webkit-gradient(linear, left top, left bottom, from(@color1), to(@color2));
            filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2);
            -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=@color1, endColorstr=@color2)"; */
            @backgroundClip;
        }
    

Still not great, and now we have two rules, but gradients should be working. So what else can we do with filters so IE can play too? Drop shadows? While we can attempt a few things using the other filters Microsoft provided, such as blur and shadow, most attempts don't match up well with the CSS3 implementations in modern browsers. Frankly, most attempts end up looking pretty awful or require extra markup. Gradients are by far the best looking. There are also some things that can't be done with filters such as rounded corners. I don't know about you, but I would like to use more properties than just gradients.

CSS Pie

Thankfully, I found a nice project out there called CSS3 Pie. This Progressive IE Enhancement tool uses behaviors, a.k.a. what Microsoft was hoping would be reusable JavaScript snippits, to achieve many of the CSS3 effects. If you do want to go the filter route (since PIE relies on JavaScript being enabled), let us know if you fare better than I did using the comments section below.

We'll start by downloading the latest copy of PIE from the site. The file we need is PIE.htc; place it in your CSS directory. CSS3 PIE allows us to make use of linear gradients, rounded corners, and box shadows. Since we are a little more free now, let's see what we can come up with:

        @linearGradient(@color1: #000000; @color2: #FFFFFF; @lgd: 90deg; @wkd1: left top; @wkd2: left bottom;) {
            background: -moz-linear-gradient(@lgd, @color1, @color2);
            background: -webkit-gradient(linear, @wkd1, @wkd2, from(@color1), to(@color2));

            *position: relative;
            *z-index: 1;
            *zoom: 1;
            -pie-background: linear-gradient(@lgd, @color2, @color1);

            -moz-background-clip: padding;      /* Firefox 1.0-3.6 */
            -webkit-background-clip: padding-box;  /* Safari, Chrome */
            background-clip: padding-box;  /* Firefox 4.0+, Opera */
        }
    

We ended up with one linearGradient mixin after all. Note that PIE requires position relative and has-layout because it is drawing a VML element behind our original html element. If you have some absolutely-positioned elements, you may need to be careful and re-define this property for IE.

        @borderRadius(@radius: 5px;) {
            -moz-border-radius: @radius;
            -webkit-border-radius: @radius;
            border-radius: @radius;
            *position: relative;
            *z-index: 1;
            *zoom: 1;
            behavior: url(PIE.htc);
        }

        @borderRadiusSpecific(@rtl: 0; @rtr: 0; @rbr: 0; @rbl: 0;) {
            -moz-border-radius-topleft: @rtl;
            -moz-border-radius-topright: @rtr;
            -moz-border-radius-bottomright: @rbr;
            -moz-border-radius-bottomleft: @rbl;

            -webkit-border-top-left-radius: @rtl;
            -webkit-border-top-right-radius: @rtr;
            -webkit-border-bottom-right-radius: @rbr;
            -webkit-border-bottom-left-radius: @rbl;

            border-top-left-radius: @rtl;
            border-top-right-radius: @rtr;
            border-bottom-right-radius: @rbr;
            border-bottom-left-radius: @rbl;
        }
    

Border radius is pretty straightforward; note however, that if we only want to round a portion of the element or have variable rounding, IE won't be able to since the VML is a rounded rectangle with a specific radius.

        @boxShadow(@horizontalOffset: 5px; @verticalOffset: 5px; @blurRadius: 8px; @shadowColor: #555; @spreadRadius: 0px; @inset: ;) {
            -moz-box-shadow: @inset @horizontalOffset @verticalOffset @blurRadius @spreadRadius @shadowColor;
            -webkit-box-shadow: @inset @horizontalOffset @verticalOffset @blurRadius @spreadRadius @shadowColor;

            box-shadow: @inset @horizontalOffset @verticalOffset @blurRadius @spreadRadius @shadowColor;
            *position: relative;
            *z-index: 1;
            *zoom: 1;
            behavior: url(PIE.htc);
        }
    

While I included some extra properties such as spreadRadius and inset here, CSS3 PIE doesn't yet support them. So, if IE is important to you, hold off on those for now.

        @textShadow(@color: #555; @horizontalOffset: 2px; @verticalOffset: 2px; @blur: 3px;) {
            -moz-text-shadow: @color @horizontalOffset @verticalOffset @blur;
            -webkit-text-shadow: @color @horizontalOffset @verticalOffset @blur;
            /*
                filter: progid:DXImageTransform.Microsoft.dropshadow(OffX=@horizontalOffset, OffY=verticalOffset, Color='@color', Positive='true');
                -ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=@horizontalOffset, OffY=verticalOffset, Color='@color', Positive='true')";
                *zoom: 1;
            */

            text-shadow: @color @horizontalOffset @verticalOffset @blur;
        }
    

While IE does have a drop shadow filter, it doesn't work reliably. Text shadows, if subtle, don't cause that big of a difference when it comes to page appearance, so being a little less cross-browser friendly here doesn't hurt too much.

Time for a quick example. Make styles.css3 and add it to your files array in styles.php.

        #page {
            @boxShadow(0; 0; 20px; #777);
            @linearGradient(@color1 - #222; #FFF;);
            @borderRadius(10px;);
        }

        #dvd-cover {
            @boxShadow(3px; 3px; 6px; #555;);
            @borderRadius(15px;);
        }

        #site-navigation li {
            @borderRadius(5px;);
        }

        #short-description {
            @boxShadow(0; 0; 5px; #777);
            @linearGradient(#FFF; @color4; 45deg; left bottom; right top;);
        }
    

Can you spot which is IE? Sadly, there is a clue, but it's a non-css one, so I guess that is OK.

Firefox, IE 8, and Chrome with css3 applied

RGBA

All right, one last CSS3 property; let's see if we can do RGBA.

        @rgba(@red: 0; @green: 0; @blue: 0; @alpha: .8; @iehex: "#99000000";) {
            background:transparent;
            background: rgba(@red, @green, @blue, @alpha);
            filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=@iehex,endColorstr=@iehex);
            -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr={@iehex},endColorstr={@iehex})";
            zoom: 1;
        }
    

Well, it's definitely not the prettiest function, but it works. For cool browsers, simply pass in the first four properties like normal. If LESS PHP could do if statements, IE wouldn't require any special parameters, but no such luck. The long-looking hex is made up of two parts. The first two positions set the alpha, 00 for completely transparent, FF for no transparency. The last six positions is for the hex equivalent of the rgb. You may have to do a little math, but it works (make sure the long hex is in quotes). Also, in IE, you can't have rounded corners and RGBA, at least with this implementation. If you do try, RGBA will take precedence.


Getting the Most...Continue to Innovate

A few ideas for where you can go from here:

  • Make your stylesheet accept several $_GET parameters and set your @color1, @color2 ... variables, or even page width with these parameters.
  • In styles.php set up some color schemes. Makes it easy for you to change themes quickly to get that perfect combination for a client.
  • Make a JavaScript theme-switcher based on the same idea.
  • Take the variables even further using mixins. Have a menu? Prepare for both horizontal and vertical using two mixins. Switch using parameters.
  • Skin your favorite applications/frameworks—such as WordPress, Magento, Drupal, CakePHP, etc—using LESS. It makes things a lot easier if the site isn't confined to a single application and you need your app to match someone's HTML page and its existing color scheme.

I've only been playing with LESS for a few weeks and these are the ideas I've come up with so far. What are yours? Please share them with the community below.


You Also Might Like

Tags: LESS
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.red-team-design.com Red

    Very comprehensive article, thanks, and indeed, LESS worths a try!

  • http://www.skinbox.net/ Sébastien Penet

    Good article. What about Sass? I would love an article comparing the two solutions.

  • http://www.venture-ware.com/kevin/ Kevin

    LESS is sweet. This makes me want to implement it more in projects. =D Good job!

  • http://www.how-to-asp.net Ryan

    LESS rocks, if only CSS had some of the capabilities. Great article very comprehensive, thanks!

  • http://laroouse.com esranull

    very very nice work thanks a lot

  • http://www.redstage.com/magento Magento Development

    Great tutorial. Using less space does indeed add a cleaner look. I will give this a try today.

  • http://www.midaym.com midaym

    referring to css3 gradient implementations you can specify complex gradients in both firefox and safari. Safari is not limited take the follwing example

    background: -moz-linear-gradient(top , #333333, #333333 3px, #000000 3px, #333333 405px, #CCCCCC 405px, #CCCCCC 411px, #FFFFFF 411px, #CCCCCC 99.7%, #aaaaaa 99.7%, #aaaaaa 100%);

    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#333333), color-stop(.3%,#333333), color-stop(.3%,#000000), color-stop(33%,#333333), color-stop(33%,#CCCCCC), color-stop(33.3%,#CCCCCC), color-stop(33.3%,#FFFFFF), color-stop(99.7%,#CCCCCC), color-stop(99.7%,#AAAAAA), color-stop(100%,#AAAAAA));

    both of these display the same complex gradient in firefox and safari. Firefox does have better and more precise control over the iterations, but at least safari gives you some control and with some trial and error and finesse can give you the same results unlike IE which just gives 1 single color transition.

  • http://www.hambrook.co.nz Hambrook

    Very nice tutorial.

    On a side note though, noticed you used

    $files = array(
    $base_path.DS.’css’.DS.’settings.less’,
    $base_path.DS.’css’.DS.’grid.less’,
    $base_path.DS.’css’.DS.’styles.less’
    );

    I assume DS is a constant for directory separator? In PHP you can always use “/” as the separator, and it’ll still work on Windows servers where the separator is normally “\”

    • Matthew Thornton
      Author

      $base_path and DS were some elements of production code that snuck in there. The tutorial has been updated.

  • http://www.jsxtech.com Jaspal Singh

    Nice article on LESS, specially I like the integration with PHP.
    Thanks for sharing.

  • Kyle Blomquist

    @Matt: Awesome Article, man. It’s even better all Styled up. You should keep doing this writing thing, it seems to suit you well.

    @Sebastian: From what I’ve seen/dealt with (mostly LESS, some SASS as of late), there are a couple things I’ve noticed:
    1: LESSPHP is a great implementation of Ruby’s LESS for PHP, and is easy to instally and manipulate without having to fall back to the command line to do so.
    2: It seems that currently The Most Recognized instance of SASS in PHP is PHamlP, That being said, SASS does offer a lot of built in functionality, but at a slight cost

    Unzipped Download of LESSPHP: 7 items, totalling 89.6 KB
    Unzipped Download of PHamlP: 342 items, totalling 935.8 KB

    @Hambrook: The Project that caused the LESS Brainstorming session in the first place involved CakePHP, thus the DS. Nonetheless, your assumption is 100% correct, Directory Separator it is.

  • http://mixmo-anime.blogspot.com kankuro

    for me i will stake in css…. but it’s a good idea to learn with less… thanks a lot for posting, all article here is great and big help for everyone :D

  • http://www.movieviews.be Meuh

    Very nice article !

    Thanks :-)

  • http://blog.netisme.com Netisme

    Excellent article to better familiarize with LESS. It can be really practice !

  • http://www.createinside.com Morten Najbjerg

    If You use Drupal You might want to look into http://drupal.org/project/less. A great module for automatically process LESS files when working with Drupal templates. Makes it so much easier to work with LESS in your Drupal templates
    It of course has the usual LESS advantage that ordinary CSS files will still be working.

  • Anderson Juhasc

    My file styles.php is throwling this:

    Fatal error: Uncaught exception ‘Exception’ with message ‘parse error: failed at `@h1BG: #1D5A50;
    ` line: 1′ in C:\wamp\www\LessPHP\css\lessc.inc.php:1233
    Stack trace:
    #0 C:\wamp\www\LessPHP\css\lessc.inc.php(1221): lessc->throwParseError()
    #1 C:\wamp\www\LessPHP\css\styles.php(55): lessc->parse(‘???@h1BG: #1D5A…’)
    #2 {main}
    thrown in C:\wamp\www\LessPHP\css\lessc.inc.php on line 1233

    Removing @h1BG working fine…

    When I use as below, works fine:

    h1 {
    @h1BG: #1D5A50;
    background: @h1BG;
    border-bottom: 1px solid @h1BG + #333;
    border-top: 1px solid @h1BG – #333;
    color: white;
    font-family: Helvetica, sans-serif;
    padding: 3px;
    }

    Thanks in advance!

    • Kyle Blomquist

      @Anderson:
      My first inclination is that your file format is a Windows format instead of UNIX,
      (The reason being: #1 C:\wamp\www\LessPHP\css\styles.php(55): lessc->parse(‘??? <<<——– Those) )
      Although I'm not 100% why taking out/moving the variable would change that. If you've made sure that you're saving your files in a Unix format, and that you aren't using a BOM (Byte-order marker)

      If this doesn't work, you could send me a copy of your styles.php @ kblomquist.2010@gmail.com, and I can have a look

      • Anderson Juhasc

        Thanks @Kyle,

        I had just change my .php files to utf8 without BOM, but not my .less.

        Now it works.

  • http://www.shiftedwork.de/blog/ Daniel S

    I dont like “CSS Meta Languages” like SASS / LESS etc. For our german readers, i recommend an article on my blog about the downsides of LESS: http://www.shiftedwork.de/blog/2010/09/09/uber-den-unsinn-von-css-frameworks/

    • http://www.jc-designs.net/blog Jeremy Carlson

      Hi Daniel…any chance you have an english version of your site? I translated using Google, and I got the idea, but there were some words I didn’t understand, and a couple of sentences that were hard to figure out. Anyway, it did a good enough job.

      I can’t talk for LESS, but Sass has an addon for Firefox called FireSass.
      https://addons.mozilla.org/en-US/firefox/addon/103988/

      Yes Sass requires Ruby, but its not like you are programming with it. You just compile it when you make changes, and if you do something like ‘watch’, it does it automatically when you make a change to your sass file.

      Sass also has a new syntax you can use called SCSS, which follows CSS syntax more closely. Those who use CSS should have no problem using SCSS.

      I will give you the point in getting the environment set up is a bitch, but once I started really understanding how to use mixins, variables and nested elements, my development time is now speeding up.

      I get your point of view, I’m just arguing the other side.

  • http://www.beperceived.com Chris Schmitz

    Awesome article! I really like your solutions for handling some of these common CSS issues. Thanks for sharing!

  • David Nitzsche-Bell

    I just discovered LESS yesterday and am eager to try this tutorial, but I’m failing at the first ‘milestone’.

    I have the initial index.php, styles.less, styles.php and less.inc.php in place, and I get “Sample Page Header” writ large, but with zero styling. No error messages in the browser and the only message in my log file is about the lack of a missing favorite icon.

    I made sure the files were UTF, no BOM. I cleaned up the snippets that I copied-and-pasted so that I have spaces and tabs. It seems all good, but……no joy.

    Any other suggestions?

    • David Nitzsche-Bell

      Figured it out. Two problems, which I discovered using Safari’s “Inspect Element” on the header text which was displayed.

      1. My version of PHP was throwing a Warning due to the mktime () statement missing a timezone element. I simply added a date_default_timezone_set(“Europe/Zurich”) and that warning was history.

      2. I had to change the permissions on the directory to allow the script to create a file in the css directory.

      Problem solved for me. Now, on with the tutorial!

      • Matthew Thornton
        Author

        I have never gotten the timezone error while using mktime in this file…interesting find. Poking around php.net I did find this statement:

        “Every call to a date/time function will generate a E_NOTICE if the time zone is not valid, and/or a E_STRICT or E_WARNING message if using the system settings or the TZ environment variable.”

        Most systems I work with are PHP 5.2+. I am curious as to when this is required (it seems like it may always be a “best practice”). If there any PHP gurus out there, your comments would be appreciated, since I have a long ways to go before I reach that status.

        I did forget to mention that the directory needed to be writeable in the tutorial. Nice catch and thanks for pointing it out.

    • David Nitzsche-Bell

      Figured it out. Two problems, which I discovered using Safari’s “Inspect Element” on the header text which was displayed.

      1. My version of PHP was throwing a Warning due to the mktime () statement missing a timezone element. I simply added a date_default_timezone_set(“Europe/Zurich”) and that warning was history.

      2. I had to change the permissions on the directory to allow the script to create a file in the css directory.

      Problem solved for me. Now, on with the tutorial!

      (P. S. I realize that I mistyped “lessc.inc.php” in the previous message.)

  • http://www.jc-designs.net/blog Jeremy Carlson

    Nice article. I’ve only used the LESS.js, and while I think it is ok, I much prefer Sass over LESS. Specifically using Compass with it because it comes with pre-made mixins for the CSS3 properties. I don’t have to make my own, because it is already there. Does LESS have something like Compass for it? Oh, and nice mention of PIE. I freakin love that thing, although there are some issues (don’t even bother including the behavior on a div with a png background – IE doesn’t play well with that). Otherwise it is awesome.

    • Matthew Thornton
      Author

      I have yet to find something like Compass for LESS. I work with a framework the vast majority of my day, so I’ve ended up building up my own mixin library, some of which was shared above. Because of this, I haven’t looked too hard, if anyone knows of one, please do share.

      PIE is great, but definitely not without it’s bugs/limitations. While it works with most use cases it doesn’t work with the body tag, form elements, or elements with png backgrounds (and possibly more). However, the system continues to evolve and improve, it’s definitely a project to keep an eye on.

    • http://www.danmasq.com Dan Masq

      Please help contribute your Less mixins to LessLib ( https://github.com/dancrew32/lesslib ) . Let’s at least get a nice library of cross-browser/cross-vendor methods/mixins going. Thanks!

  • http://www.chillysheep.co.uk James Baldwin

    This is fantastic! Not sure what rock I’ve been under but this is the first I have heard of LESS, and is something I have always longed for in CSS, maths and variables!

  • http://www.craigonthe.net Craig

    I know this is a bit old, but I’ve been using LESS for a while now within Dreamweaver and it did get confusing without the code coloring, but I’ve just managed to sort this out.

    If you’re having the same problem, then read this article;
    http://kb2.adobe.com/cps/164/tn_16410.html

  • http://www.webbrands.nl Robbert

    Thanks for this article! Really helpful. I love Less, it will be an important part of the WYSIWYG cms framework that I am working on :)

  • http://veterinaren.nu Malm

    Thanks again for another great article!

  • http://www.pixelpalast.net pixelpalast

    hey,
    i just tried to calculate an elm-width by using less but it seems to be tricky…

    @boxTextPadding: 2.2%;

    .box .text {
    padding: @boxTextPadding;
    }
    .six-four .text {
    width: 60% – (@boxTextPadding * 2);
    }
    /* output:
    .six-four .text { width: 59.956%; }
    */

    seems like less cant handle such a 2-unit calculation?

  • http://godeldesign.com.au David Meister

    This article makes the comment that we should avoid nesting selectors in our LESS file because it results in a “bloated” stylesheet, but is this still an issue when gzipping the CSS output?

    As I understand it, the gzip algorithm is highly optimized for finding repetition in a file and leveraging that to compress.

    In other words, compressing a 50 character random string in gzip would likely result in a larger file than a much longer repetitive string like “aaaaaaaa”.

    I believe this is why my SQL dumps are something like 90% smaller after I gzip, because the SQL syntax is very repetitive.

    This means that the output provided by LESS for nested selectors should actually gzip very efficiently, possibly even better than un-nested CSS.

    Since the nesting improves readability of your CSS files dramatically so I’d personally recommend that developers nest as much as makes sense to them to keep their files neat rather than try to artificially split things up in an overly holistic attempt to decrease file-size bloat.

    Obviously just make sure that your server is actually gzipping the files that it sends, but this is usually just “best practice” anyway..

    • http://notoriouswebmaster.com Alfred Ayache

      @David Meister:

      Yes gzip is very efficient at compressing. But you have to remember that your pages will be requested from all kinds of devices, and ungzipping requires resources on the browser side. We’re talking space (memory) and time. Many devices will have very little memory (as little as 512M, total), and also are considerably slower than the development machines we use on a daily basis.

      So, by all means gzip; but start with as lean a file as possible.

      I’ve just attended DrupalCon Denver and there were a couple of sessions which dealt with exactly these issues. Happily, all the DrupalCon sessions are now available online for free:

      http://denver2012.drupal.org/content/front-end-performance-improvements
      http://denver2012.drupal.org/program/sessions/using-sass-compass-drupal-theming

  • Paul

    For anyone else using Windows 7, UTF-8 without BOM, and not knowing how to convert to UNIX format:

    Install Notepad++
    Open styles.php and styles.less
    Edit > EOL Conversion > UNIX

    Before I did this I was getting the error below when viewing styles.php

    ———————-8<———————

    Fatal error: Uncaught exception ‘Exception’ with message ‘parse error: failed at `@h1BG: #1D5A50;
    ` line: 1′ in C:\xampp\htdocs\mbz\css\lessc.inc.php:1233
    Stack trace:
    #0 C:\xampp\htdocs\mbz\css\lessc.inc.php(1221): lessc->throwParseError()
    #1 C:\xampp\htdocs\mbz\css\styles.php(63): lessc->parse(‘???@h1BG: #1D5A…’)
    #2 {main}
    thrown in C:\xampp\htdocs\mbz\css\lessc.inc.php on line 1233
    ———————-8<———————

  • http://www.techgarten.com piggyslasher

    Brilliant!

  • zEver

    Regarding “it is actually 2 characters smaller in the CSS if you do” and other moments when the author seems to care about the actual byte-footprint of CSS files… please…

    We’re in 21st century, there are megabytes of images on every other website. Optimizing CSS for size ito cut out 2kB is really the least of our worries and a waste of time and focus.

    It actually takes longer to initiate the download of another file than to download few dozen kB, so if you’d really want to optimize you’d arrange all less to be generated into a single css file.

    Still, less is more about simplifying human work and minimizing code-time than saving 20ms of file transfer time.

    Good article overall. Cheers :>