Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

January 21 2014

19:50

Working With LESS and the Chrome DevTools

This is a complete tutorial to using LESS with Chrome’s DevTools. If you’ve already used Sass with Chrome’s DevTools, you’ll most likely already be familiar with the concepts introduced here.

The Tl;dr

  • LESS has very recently added support for Source Maps, so this is new and exciting!
  • DevTools mapping means you can view LESS styles for all your relevant CSS.
  • Edit LESS source files within DevTools and have them save to disk.
  • Source Map adoption is improving with Sass, CoffeeScript, UglifyJS2 and more.

Introduction

Not too long ago, the Chrome DevTools added a number of IDE-like features (and continues to do so), one of which is the ability to understand the mapping between a compiled file and its corresponding source file. This is made possible thanks to Source Maps.

image_0-2

What This Tutorial Will Cover

  • How to generate Source Maps from LESS files.
  • Debugging LESS code through the DevTools.
  • Authoring LESS code in the DevTools and seeing changes immediately via Workspaces and Grunt.

Everything mentioned here is available in Chrome Canary.


Configuring LESS for Source Maps

First thing’s first, install the latest (1.5.1 at the time of this writing) version of LESS through NPM (Source Maps arrived in 1.5.0):

$ npm install -g less
$ lessc -v
lessc 1.5.1 (LESS Compiler) [JavaScript]
image_1

At this point, you can run the LESS compiler in your terminal using the lessc command.

image_2

Create a new LESS file, for demonstration purposes, it’ll be kept short and simple.

@color: #4D926F;
#header {
  color: @color;
}

To turn the LESS file into a CSS file, it’s a simple case of running:

lessc header.less header.css
image_3

We now need a Source Map file. Create it with the -source-map flag.

lessc --source-map=header.map header.less header.css

Using the LESS code shown above, running this command produces a Source Map file with the following contents:

{"version":3,"file":"header.css","sources":["header.less"],"names":[],"mappings":"AAEQ;EACP,cAAA"}

Using DevTools to Map to LESS Source Files

In a world without Source Maps, DevTools would display styles originating from the compiled CSS. Line numbering would not be useful due to a mismatch between compiled CSS and the source CSS. With Source Maps, when inspecting a DOM node on the page, DevTools will automatically show the styles originating from the LESS source file.

Viewing a web page which references the previously mentioned header.css is now inspectable in a more meaningful way.

image_4

While holding Command (Ctrl on Windows), click any property, value or selector to jump to the line of code in the corresponding LESS source file within the Sources Panel.


Authoring Workflow With DevTools & LESS

Viewing LESS code in the DevTools is certainly useful, but integrating an authoring workflow can speed up your iteration cycle. The next step is to tell DevTools how the resources on a web page map to files on a file system. Enter: Workspaces.

Note: Workspaces are suitable for many projects, not just those using CSS preprocessors.

Workspaces

You might already be familiar with the Sources panel from an editing perspective. The general idea is that you have a file navigator in the sidebar where each file is typically a stylesheet, script or HTML resource that the web page has loaded.

image_6

Clicking on a resource displays the contents in the main panel, you may notice the similarity this has with the Resources panel, however there is at least one major difference: the Sources panel contains a live editor. Changes you make to stylesheets are applied to the page instantly and changes you make to scripts are injected back into the V8 engine and evaluated immediately. Not only does this work for remotely hosted files, but also for local ones with the added benefit of persisting your changes to a file.

Note: To make use of Workspaces, the following steps are only required once per project.

Step 1.

Open up a local webpage and add its corresponding folder on your file system to the workspace by Right-Clicking in the Sources panel sidebar and selecting Add folder to Workspace.

image_7

Step 2.

Allow DevTools access to the folder you’ve just added.

image_8

Step 3.

Your newly added folder will appear in the sidebar navigation.

image_9

Right-click on a file within a network resourced folder in the Sources Panel (make sure it has an obvious mapping to a file on your file system) and select Map to File System Resource.

image_10

Step 4.

The first suggestion provided by DevTools is the correct one. It has noticed that the file on my file system (/Users/.../bootstrap.css) has the same name as a network resource file (http://localhost/.../bootstrap.css). Verify the mapping by selecting the correct resource.

image_11

DevTools now understands the mapping between filesystem resources and network resources. When you Cmd/Ctrl-Click a selector from the Styles pane and end in the Sources Panel, you’re now being shown your actual LESS source file. You can edit a file in the Sources panel and those changes will persist to disk when you Command/Control+S.

We’ve come all this way, so let’s complete this workflow by using a Grunt watch task to watch for changes made to the LESS files and then automatically compile our CSS and make a corresponding Source Map file.

Using Grunt to Watch & Compile LESS

With Workspaces set up, configure Grunt (or another tool of your choice) to watch for changes to LESS source files and compile a new CSS file (with a Source Map). DevTools will pick up this change automatically and apply any new styles to the page.

Note: Enable the Auto-reload generated CSS flag in the Settings panel to use this workflow.

image_12

Here is an outline of the automated steps which will occur:

  1. You save a change to a LESS file via DevTools.
  2. A watch task monitors LESS files for changes and then runs a LESS task.
  3. The LESS task compiles a new CSS file plus a Source Map file.
  4. DevTools injects the new CSS file onto the current page without a page refresh.

Here’s a simplified Gruntfile:

module.exports = function(grunt) {
    'use strict';

    require('matchdep').filterDev('grunt-!(cli)').forEach(grunt.loadNpmTasks);

    grunt.initConfig({
        less: {
            dev: {
                options: {
                    sourceMap: true,
                    sourceMapFilename: 'bootstrap.map'
                },
                files: {
                    'less/bootstrap.css': 'less/bootstrap.less'
                }
            }
        },
        watch: {
            all: {
                files: ['less/**/*.less'],
                tasks: ['less'],
            }
        }
    });

    grunt.registerTask('default', ['less', 'watch']);
};

Note: The code snippet above comes from the demo repository.

After an npm install, running grunt in your terminal should show a watch task running.

image_13

DevTools already has write access to your development folder (through Workspaces). Cmd/Ctrl+S your changes in the Sources Panel to have DevTools overwrite the source LESS file with your new change, Grunt compiles a new CSS file which DevTools pulls in and applies to the page.


Conclusion

  • During development and debugging, looking at your source file (rather than the compiled file) will almost always be more useful to you.
  • For DevTools to understand source file mappings, it needs to be compatible with the Source Map v3 proposal which is up to the compilation tool to implement.
  • Tools adopting Source Maps are improving, we have Sass, Compass, LESS, autoprefixer, UglifyJS2, CoffeeScript and more. There are grunt-contrib-* tasks for most of these tools (Sass, Compass, LESS, autoprefixr, UglifyJS2, CoffeeScript) which tie in nicely with a livereload workflow.
  • Viewing LESS files will work out of the box with DevTools. To actually edit files, try out Workspaces which gives you the ability to persist changes to disk.

Further Reading

Source Maps

LESS

Chrome DevTools

January 08 2014

11:00

DevDocs: The Ultimate Work of Reference for Web Developers


  

Thibault Courouble is back. The philosopher and front-end developer from France created yet another useful web service for developers. His new project DevDocs has the potential to become the ultimate work of reference for anybody building web apps. DevDocs integrates a plethora of different documentations and equips them with a spanned search function. This is a very good idea…

October 15 2013

06:30

One-Stop Shop: PHP-Tool Munee Cares for All your Website’s Assets


  

Cody Lundquist, Australian with a Swedish sounding name, created a free asset-management based on PHP 5.3. Its feature-set is astounding, yet demands a special preliminary treatment of the websites, it’s supposed to be working on. Munee is able to manage any kind of possible asset, be it images or other files, JavaScript, CSS, LESS, SCSS or even CoffeeScript.

March 22 2011

01:03

Mastering Sass: Lesson 1


After numerous requests, we’re launching a 3-part quick tip video mini-series on mastering Sass. To begin, in this introductory eight-minute screencast, I’ll teach you how to install Sass, and then how to get started with the beginning functionality and options.


In the next lesson, we’ll take things a step further, and dig into mixins, Math operations, and add-ons! Stay tuned!

January 18 2011

03:00

Quick Tip: Never Type a Vendor Prefix Again


You know the drill quite well. Want to give some section of your website rounded corners with CSS3? Then you’ll require nothing short of three vendor prefixes: webkit, moz, and the W3C recommended form. Isn’t that a huge waste of time — not to mention screen space? What if, instead, we could use a class file? Well, we can! I’ll show you how today.


The Key

If we use a tool like LESS or SASS, we can create our own class files quite easily. Have no idea what I’m talking about? Well, first, review this quick tip. It’ll teach you exactly how to get up and running with Less.


Classes File

Next, we need to create a core classes file that will be used in every project. Feel free to store this file anywhere you wish, though, in the video above, I use our popular (and exclusive) Structurer app.

We’ll do the first one together, but be sure to review the screencast for more details.

.border-radius( @radius: 3px ) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}

In terms of naming conventions, I’ve found that it’s smartest to use the officially recommended name for your class name — in this case, “border-radius.” To declare variables with Less, we preface them with an @ symbol. In this case, we’re setting a default value of 3px, though, should we need to override that value in our project, it’s a cinch!

#someElement {
   .border-radius(10px);
}

Some Examples

At this point, simply rinse and repeat for each property that requires multiple vendor prefixes. Here’s a handful to get you started:

Box Shadow

.box-shadow(
	@x : 2px,
	@y : 2px,
	@blur : 5px,
	@spread : 0,
	@color : rgba(0,0,0,.6)
) {
	-webkit-box-shadow: @x @y @blur @spread @color;
	   -moz-box-shadow: @x @y @blur @spread @color;
			box-shadow: @x @y @blur @spread @color;
}

Transition

.transition(
	@what : all,
	@length : 1s,
	@easing : ease-in-out
) {
	-webkit-transition: @what @length @easing;
	   -moz-transition: @what @length @easing;
	     -o-transition: @what @length @easing;
		  	transition: @what @length @easing;
}

Box

.box(
	@orient : horizontal,
	@pack : center,
	@align : center
) {
	display: -webkit-box;
	   display: -moz-box;
	        display: box;

	-webkit-box-orient: @orient;
	   -moz-box-orient: @orient;
	   		box-orient: @orient;

	-webkit-box-pack: @pack;
	   -moz-box-pack: @pack;
	        box-pack: @pack;		

	-webkit-box-align: @align;
	   -moz-box-align: @align;
			box-align: @align;
}

Flex

.flex( @val : 1 ) {
	-webkit-box-flex: @val;
	   -moz-box-flex: @val;
	        box-flex: @val;
}

Conclusion

I’d love to hear your thoughts on this. If you like the idea, let’s turbo-charge this stylesheet.

December 06 2010

12:41

Using the LESS CSS Preprocessor for Smarter Style Sheets

Advertisement in Using the LESS CSS Preprocessor for Smarter Style Sheets
 in Using the LESS CSS Preprocessor for Smarter Style Sheets  in Using the LESS CSS Preprocessor for Smarter Style Sheets  in Using the LESS CSS Preprocessor for Smarter Style Sheets

As a Web designer you’re undoubtedly familiar with CSS, the style sheet language used to format markup on Web pages. CSS itself is extremely simple, consisting of rule sets and declaration blocks—what to style, how to style it—and it does pretty much everything you want, right? Well, not quite.

You see, while the simple design of CSS makes it very accessible to beginners, it also poses limitations on what you can do with it. These limitations, like the inability to set variables or to perform operations, mean that we inevitably end up repeating the same pieces of styling in different places. Not good for following best practices—in this case, sticking to DRY (don’t repeat yourself) for less code and easier maintenance.

Enter the CSS preprocessor. In simple terms, CSS preprocessing is a method of extending the feature set of CSS by first writing the style sheets in a new extended language, then compiling the code to vanilla CSS so that it can be read by Web browsers. Several CSS preprocessors are available today, most notably Sass and LESS.

Less-css in Using the LESS CSS Preprocessor for Smarter Style Sheets

What’s the difference? Sass was designed to both simplify and extend CSS, so things like curly braces were removed from the syntax. LESS was designed to be as close to CSS as possible, so the syntax is identical to your current CSS code. This means you can use it right away with your existing code. Recently, Sass also introduced a CSS-like syntax called SCSS (Sassy CSS) to make migrating easier.

If It Ain’t Broke…?

By now you might be thinking, “So what? Why should I care about these things, and how exactly will they make my life as a Web designer easier?” I’ll get to that in a moment, and I promise it will be worth your time. First, let me clarify the focus of this article.

In this tutorial, I’ll be using LESS to demonstrate how CSS preprocessing can help you code CSS faster. But that doesn’t mean you must use LESS. It’s my tool of choice, but you may find that Sass fits your workflow better, so I suggest giving them both a shot. I’ll talk a bit more about their differences at the end of the article.

I’ll start off by explaining how LESS works and how to install it. After, I’ll list a set of problems that large CSS files pose, one by one, and exactly how you can use LESS to solve them.

Let’s go!

Installing It

There are two parts to any CSS preprocessor: the language and the compiler. The language itself is what you’ll be writing. LESS looks just like CSS, except for a bunch of extra features. The compiler is what turns that LESS code into standard CSS that a Web browser can read and process.

Many different compilers are actually available for LESS, each programmed in a different language. There’s a Ruby Gem, a PHP version, a .NET version, an OS X app and one written in JavaScript. Some of these are platform-specific, like the OS X app. For this tutorial, I recommend the JavaScript version (less.js) because it’s the easiest to get started with.

Using the JavaScript compiler is extremely easy. Simply include the script in your HTML code, and then it will process LESS live as the page loads. We can then include our LESS file just as we would a standard style sheet. Here’s the code to put between the <head> tags of your mark-up:

<link rel="stylesheet/less" href="/stylesheets/main.less" type="text/css" />
<script src="http://lesscss.googlecode.com/files/less-1.0.30.min.js"></script>

Note that I’m referencing the less.js script directly from the Google Code server. With this method, you don’t even have to download the script to use it. The style sheet link goes above the script to ensure it gets loaded and is ready for the preprocessor. Also, make sure that the href value points to the location of your .less file.

That’s it. We can now begin writing LESS code in our .less file. Let’s go ahead and see how LESS makes working with CSS easier.

1. Cleaner Structure With Nesting

In CSS, we write out every rule set separately, which often leads to long selectors that repeat the same stuff over and over. Here’s a typical example:

#header {}
#header #nav {}
#header #nav ul {}
#header #nav ul li {}
#header #nav ul li a {}

LESS allows us to nest rule sets inside other rule sets, as a way to show hierarchy. Let’s rewrite the above example with nesting:

# header {
  #nav {
    ul {
      li {
        a {}
      }
    }
  }
}

I’ve omitted the content from the selectors for simplicity, but you can see how the structure of the code quickly changes. Now you don’t have to repeat selectors over and over again; simply nest the relevant rule set inside another to indicate the hierarchy. It’s also a great way to keep code organized because it groups related items together visually.

Also, if you want to give pseudo-classes this nesting structure, you can do so with the & symbol. Pseudo-classes are things such as :hover, :active and :visited. Your code would look as follows:

a {
  &:hover {}
  &:active {}
  &:visited {}
}

2. Variables For Faster Maintenance

We usually apply a palette of colors across an entire website. Any given color could be used for multiple items and so would be repeated throughout the CSS code. To change the color, you’d have to do a “Find and replace.”

But that’s not quite it. You could also isolate those values into separate rule sets; but with this method, the rule sets would keep growing as you add more colors across the website, leading to bloated selectors. Here’s what I’m talking about:

#header, #sidebar .heading, #sidebar h2, #footer h3, .aside h3 { color: red; }

To make a simple color change, we’re faced with long selectors, all dedicated to that one color. It’s not pretty. LESS allows us to specify variables in one place—such as for brand colors, border lengths, side margins and so on—and then reuse the variables elsewhere in the style sheet. The value of the variable remains stored in one place, though, so making a change is as simple as changing that one line. Variables start with an @ and are written like this:

@brand-color: #4455EE;

#header { background-color: @brand-color; }
#footer { color: @brand-color; }
h3 { color: @brand-color; }

In LESS, variables also have scope, so you could use variables with the same name in various places; when they’re called, the compiler would check for the variable locally first (i.e. is there anything with that name where the declaration is currently nested?), and then move up the hierarchy until it finds it. For example, the following code:

@great-color: #4455EE;

#header {
  @great-color: #EE3322;
  color: @great-color;
}

…compiles to:

#header { color: #EE3322; }

3. Reusing Whole Classes

Variables are great, but we often reuse more than single values. A good example is code that’s different for every browser, like the CSS3 property border-radius. We have to write at least three declarations just to specify it:

-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;

If you use a lot of CSS3, then this sort of repeating code adds up quickly. LESS solves this by allowing us to reuse whole classes simply by referencing them in our rule sets. For example, let’s create a new class for the above border-radius and reuse it in another rule set:

.rounded-corners {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}
#login-box {
  .rounded-corners;
}

Now #login-box will inherit the properties of the rounded-corners class. But what if we want more control over the size of the corners? No problem. We can pass along variables to the “mixin” (these reusable classes are called mixins) to get a more specific outcome. First, we rewrite the original mixin to add the variable we want to manipulate:

.rounded(@radius: 5px) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}

Now we’ve replaced the values for a variable, and we’ve specified the default value inside the parentheses. To give mixins multiple values, you’ll just need to separate them with a comma. Now, if we want our #login-box to have a border radius of three pixels instead of five, we do this:

#login-box {
  .rounded-corners(3px);
}

4. Operations

Variables let us specify things such as common palettes of colors, but what about relative design elements, like text that’s just a bit lighter than the background, or an inner border that’s one pixel thicker than the outer border?

Rather than add more variables, we can perform operations on existing values with LESS. For example, we can make colors lighter or darker or add values to borders and margins. And when we change the value that these operations depend on, they update accordingly. Take the following:

@base-margin: 25px;
#header { top-margin: @base-margin + 10px; }

This gives the #header element a top margin of 35 pixels. You can, of course, also multiply, divide and subtract, and perform operations on colors like #888 / 4 and #EEE + #111.

5. Namespaces and Accessors

What if you want to group variables or mixins into separate bundles? You can do this by nesting them inside a rule set with an id, like #defaults. Mixins can also be grouped in this way:

#defaults {
  @heading-color: #EE3322;
  .bordered { border: solid 1px #EEE; }
}

Then, to call a variable and a mixin from that particular group, we do this:

h1 {
  color: #defaults[@heading-color];
  #defaults > .bordered;
}

We can even access values of other properties in a given rule set directly, even if they’re not variables. So, to give the sidebar heading the same color as your main h1 heading, you’d write:

h1 { color: red; }

.sidebar_heading { color: h1['color']; }

There’s not much difference between variables and accessors, so use whichever you prefer. Accessors probably make more sense if you will be using the value only once. Variable names can add semantic meaning to the style sheet, so they make more sense when you look at them at a later date.
A couple more things to mention: You can use two slashes, //, for single-line comments. And you can import other LESS files, just as in CSS, with @import:

@import 'typography';
@import 'layout';

To Conclude

I hope by now you’ve got a pretty good idea why CSS preprocessors exist, and how they can make your work easier. The JavaScript version of the LESS compiler, less.js, is of course just one way to use LESS. It’s probably the easiest to get started with, but it also has some downsides, the biggest one being that the compiling takes place live. This isn’t a problem on modern browsers with fast JavaScript engines, but it might work slower on older browsers. Note that less.js actually caches the CSS once it’s processed, so the CSS isn’t regenerated for each user.

To use the generated CSS instead of LESS in your markup, you can compile your files using the various other compilers. If you’re on OS X, I suggest trying out the LESS App, a desktop app that watches your LESS files for changes as you work and automatically compiles them into CSS files when you update them. The Ruby Gem has the same watcher functionality but is trickier to install if you’re not familiar with Ruby (see the official website for details on that). There are also PHP and .NET versions.

Finally, LESS isn’t your only option for a CSS preprocessor. The other popular choice is Sass, but there are still more options to check out, such as xCSS. The advantage of LESS is that it uses existing CSS syntax, so getting started is just a matter of renaming your .css file to .less. This might be a disadvantage if you dislike the CSS syntax and curly braces, in which case Sass would probably be a better choice. There is also the Compass framework available for Sass, which is worth checking out if you go with Sass.

(al) (sp)


© Dmitry Fadeyev for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: CSS, less

Tags: Coding CSS less

October 28 2010

16:37

How to Squeeze the Most out of LESS


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(
            $base_path.DS.'css'.DS.'settings.less',
            $base_path.DS.'css'.DS.'grid.less',
            $base_path.DS.'css'.DS.'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

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
Get rid of the ads (sfw)

Don't be the product, buy the product!

Schweinderl