Introduction to LESS : an easier way to create CSS stylesheets

In web pages, HTML elements are used to represents the content of the page, while CSS styles sets the look and feel of those elements. CSS styles works with pairs of property/value that define for example a size, a border or a color. In most cases CSS stylesheet files are created to define selectors (http://www.w3.org/TR/css3-selectors/) containing the property or group of properties that applies to the HTML elements corresponding to the selectors.  It is not recommended to apply styles directly to HTML elements since in that case they cannot be reused.

For a large web application, managing all the CSS stylesheets containing the styles for the application can get messy quickly, since only the group of properties is reusable, not the individual values of the properties.

LESS is tool that was created to help with code reuse in CSS. LESS is a CSS preprocessor: it adds new syntax on top of the existing CSS syntax. The LESS file is then used to generate valid CSS stylesheets that is used in the web page. I like to summarise it as adding variables to CSS, even if it’s more complex than that.

LESS features overview

Here is a quick overview of the most interesting features of LESS :

  • Variables : variables can be declared anywhere in a stylesheet to reuse the value anywhere in the file. Modifying the variable will then update all the places where the variable is used, which is a huge gain over the old save-and-replace. Variables can also be combined and variables containing numerical values like measurements in pixels and colors can be added, subtracted, multiplied and divided together or with constant values. Here is an example of how to use a variable :
    @large-border-size: 20px;
    @small-border-size: @large-border-size / 2;
    @small-border: @small-border-size solid black;
    
    #Container
    {
    border: @small-border;
    padding: @small-border-size;
    }
  • Mixins : mixins are a way to reuse a chunk of CSS property/value pairs in any CSS selectors. You can add any number of properties to the mixins and they can take any number of parameters. Often, they are used to group properties with vendor-specific prefixes to avoid repeating them everywhere, making your LESS file easier to read. Here is a mixin for the property user-select that indicate if the content can be selected by the user and all its vendor-specific prefixes :
    /*Mixin for user-select property*/
    
    .user-select(@select-type)
    {
    -moz-user-select: @select-type;
    -ms-user-select: @select-type;
     -o-user-select: @select-type;
    -webkit-user-select: @select-type;
            /*Property without prefix is always last to override the other if it is supported by the browser */
    user-select: @select-type;  
    }
    
    /*Using the user-select mixin*/
    #Container
    {
    background-color: black;
    .user-select(none);
    }
  • Importing: To reuse selectors, mixins or variables in multiples LESS stylesheets, you can import a LESS file in another LESS file. When a file is imported, variables and mixins of that file will be directly accessible in the stylesheet importing it. This a great feature to build a list of color or mixin that can be easily reused in any stylesheet of the application. On the other hand, I usually avoid importing files containing many selectors that way since all the selectors from the imported files will be added to the stylesheet importing it when the CSS file is generated. This can cause unnecessary duplication of styles if you’re not careful. Also, if the same CSS styles are included in different stylesheets, you will lose the benefit of browser caching to improve the page loading style and reduce the load on your server. In that case, you should simply add the additional CSS files to the web page. To import a file in LESS, simply use the import directive, for example :
    @import "colors.less"
  • Functions : Many functions are included in LESS to manipulate colors and numbers in your stylesheet. That was, you can avoid hardcoding the result of simple operations on variables of your stylesheet. For example, if you want to use a color somewhere and reuse the same color elsewhere, but it always needs to be 50% lighter, you can use the following style. If you need to adjust the base color later on, the lighter color will be updated automatically.
    @standard-background-color: #001ED5;
    
    .StandardBackground
    {
    color: @standard-background-color;
    .user-select(none);
    }
    
    .LightBackground
    {
    background-color: lighten(@standard-background-color, 50%);
    .user-select(none);
    }

Starting to use LESS

Any valid CSS file is a valid LESS file, so you can start right now with your existing projects in any language. Also, since the output of LESS files is CSS, LESS is already compatible with all browsers. There are many alternative to integrate LESS to your workflow, here are a few examples :

  • Official LESS release : LESS.js is the official version of LESS. You can use it to generate CSS files from your LESS file in the browser, which is good for test but too slow for production websites. A better option is to use to generate your CSS files on your server with Node.js, and serve only those CSS files to the client.
  • .LESS (dotless) : .LESS is a port of LESS.js which can be used in any ASP.NET project. It will generate the CSS files from the LESS files in your project and serve only the CSS files to the client, and can be integrated with the bundling and minification libraries in System.Optimization. Also Visual Studio 2012 Service Pack 3 supports LESS files : it has syntax highlighting, autocomplete and CSS file preview built in.
  • LESS compilers : There are tools in many languages to compile LESS files to CSS files. That way, you can integrate the LESS compilation to your build process, or run the compiler manually to generate the CSS files needed for your project and put those files into production.

.LESS Web.config/DotlessConfiguration options

Many options of the .LESS CSS parser can be set directly from the Web.config file, but many of them are not clearly described. Here is my attempt to document them :

lessSource

Sets the name of the file reader class to use (must implement the dotless.Core.Input.IFileReader interface). Default value is dotless.Core.Input.FileReader.

minifyOutput

Indicates if the CSS produced by the .LESS parser should be minified afterwards. You may wish to minify the files for performance reasons, but if you already use the System.Web.Optimization framework for minification you can leave it off.  Default value is false.

debug

Sets the debug mode that prints comments in the console output. Default value is false.

cacheEnabled

Indicates if the CSS generated from the LESS file should be cached for 7 days by the web browser by setting the HTTP headers, otherwise the CSS file will always be reloaded by the browser. Default value is true.

web

Indicates if .LESS is running in a web application or from the command line. Depending on the rest of the configuration and the custom logger or file reader you may have used, you web application may work correctly even if the web mode is off. Default value is false.

mapPathsToWeb

When .LESS is running as a web application, indicates if the paths should be mapped to the location of the website. Otherwise, the paths are relative to to the current directory to allow files outside the web directory structure. Default value is true.

sessionMode

Dotless does not need the session but it may be enabled with this option to use the session in plugins. The possible values are Enabled, QueryParam (see next section) and Disabled, and the default value is Disabled.

sessionQueryParamName

When the sessionMode is QueryParam, a parameter must be added to the query string so the session can be used. The name of the parameter can be specified using this option, and the default value is sstate.

logger

Sets the name of the logger to use to log parsing errors (must implement the dotless.Core.Loggers.ILogger interface). It does not work with the Web.config as of .LESS version 1.3.1, but it can be set manually from the DotlessConfiguration object. Default value is null, but two loggers are available : the dotless.Core.Loggers.ConsoleLogger that logs to the Visual Studio console output and the dotless.Core.Loggers.DiagnosticsLogger that logs to the trace listeners used by the current application.

logLevel

Sets the level at which the parser errors are logged. The possible values are Info, Debug, Warn and Error, and the default value is Error. Please note that no logger is set by default.

optimization

.LESS optimizes the parsing of the .LESS file by separating it into chunks and parsing each chunk instead of the whole file at once. If the value is 0, the operation is not optimized, and if the value is larger than 0 the optimization is used. Default value is 1.

plugins

Contains the list of .LESS plugins used by the application. Plugins are used to add new functions to .LESS and are created as classes implementing the IFunctionPlugin interface.By default, no plugins are added. To add a plugin :

<dotless>
  <plugin name="PluginClassName" assembly="PluginAssemblyName" />
</dotless>

disableUrlRewriting

Indicates if the urls in the imported files should be adjusted depending on the location of the LESS file importing it. Default value is false.

inlineCssFiles

Indicates that when the file imported by the @import directive is a CSS file,  the content of the files should be put in directly in output without trying to parse it as a LESS file instead of keeping the import directive. Default value is false.

importAllFilesAsLess

Indicates if all imported files should be processed as LESS files even if they end with the .css extension, otherwise only the .less files are processed as LESS. Default value is false.

handleWebCompression

Indicates if .LESS should handle the compression of the response according to the Accept-Encoding header of the request, otherwise it is not compressed and may be compressed by setting IIS options (the same response should not be compressed twice,). The options gzip, deflate and identity are supported for the Accept-Encoding header. The default value is true and the default encoding used is gzip if no compatible compression method is found in the header.

disableParameters

Indicates if the parameters for the query string should be ignored by .LESS, or if the parameters should be defined as a variable inside the LESS file requested by the ParameterDecorator. For example, if parameters are enabled, style.less?param=value will be added as @param: value; in the LESS file (the value should be URL encoded). Default value is false.

disableVariableRedefines

Indicates that variables being redefined should be disabled, so less will search from the bottom to the top of the file. This is used to make .LESS behave like Less.js when handling variables. Default value is false.

keepFirstSpecialComment

Indicates that the first comment starting by /** in the LESS file should be kept even after minification. Default value is false.

 

If you need to use options that do not work from the Web.config, the Less.Parse method can take a DotlessConfiguration object as a parameter. In my case, I already use System.Web.Optimization for minification and bundling of the CSS files, so I created my own bundle transformation class that implements the IBundleTransform interface and calls the parser.