Documentation - lessphp v0.1.6

This documentation is specific to the php version of LESS, lessphp. lessphp is a superset of LESS classic. Everything you can do in LESS classic will work in lessphp but there are additional features unique to the php version.

Getting Started

Download the latest version of lessphp here.

The Language


lessphp is a data description language built on top of CSS. The two major components of the language are blocks and property-value pairs. A block is a scope for a collection of property-value pairs.

Blocks and properties have special characteristics depending on how they are named.

It is important to realize that a block's state does not change over time. When a block is defined, all of its properties are constant. The best way to demonstrate this is to look at the following LESS snippet:

body {
    color: @val; 
    @val: blue;
}

Because the state of the block is not changing over time, but constant after its creation, the color property is printed with the value blue.

Abstract Properties (Variables)

Abstract properties are defined with a name starting with @. These types of properties are special in two ways: first, they are not included in the output of the compiler. Second, they can be easily accessed in the values of other properties just by writing their name. If a property is referenced but can not be found, a blank string is returned.

As a LESS programmer, it means that you can define a collection of hidden values that can be referenced in other locations.

@mycolor: #fff;
body {
    color: @mycolor; 
}
pre {
    color: @mycolor;
}

Also take note that you can define abstract properties in the global scope.

Property Values & Expressions

All properties have at least one value. The value is a list of expressions separated by spaces or commas. An expression is any CSS value with optional mathematical operators applied to it. The operators only function with number and color value types.

Operations on units will keep the unit of the rightmost value, unless it is unit-less, then then leftmost unit will be kept for the result. See the following examples below.

body {
    color: #001 + #abc;        // evaulates to #aabbdd:
    width: 3430px + 22;        // evaluates to 3452px;
    margin: (1.5em / 2) + 2px; // evaluates to 2.85px;
    margin: 20 + 2px;          // evaluates to 22px;
}

It is important to notice that in the example above the output will print the margin property twice. A single property name can hold more than one value; older values are not overwritten.

Nested Blocks

Blocks can be nested inside of each other in order to achieve the same effect as listing out the path of identifiers in CSS. This can help to increase organization of your LESS code and reduce the amount of repeated tag names you have to type.

body {
    a {
        color: green
        :hover {
            color: blue;
        }
    }
}

Mixins & Namespace Access

Any block can be "mixed" into the current block. This means that all properties and blocks in the target block are brought into the current block. It is possible to achieve the same effect with just CSS and HTML, but there are some additional features discussed below that make it worthwhile to utilize LESS-style mixing.

The syntax is as follows:

.myclass {
    @fonts: Helvetica, Arial;
    margin: 1.0em;	
    line-spacing: 150%;

    a {
        background-color: black;
    }
}

pre {
    .myclass;
    font-family: @fonts; // uses the mixed in variable
}

div.notice {
    .myclass;
}

If you want to mix in a specific block within another block you can use the > namespace operator. Additionally you can pull out specific values of properties from blocks using the [ ] operator.

// using .myclass from above
li {
    .myclass > a; // just mix in properties from 'a' tag in .myclass
    fonts: .myclass[@fonts];
    padding: .myclass['margin'];
}

Abstract Blocks

Abstract blocks are like any other blocks, but their names start with a @. Like abstract properties, they are not included in the compiler's output. This allows you to utilize mixins without adding any unused blocks to the output. You can also use an abstract class to define a package of invisible, but extractable blocks and properties.

@mypackage {
    .coolColors {
        color: pink;
        background-color: green;
    }

    .hotColors {
        color: red;
        background-color: orange;
    }
}

p {
    @mypackage > .coolColors;
}

div {
    @mypackage; // inserts both classes into this block 
}

It is possible to give an abstract block the same name as an abstract property; their names will not collide. Block names and property names exist in different spaces.

Mixin Arguments

All blocks have the option of taking argument lists, and the arguments can have default values.

.myclass(@width: 200px;@radius) {
    border-radius: @radius;
    width: @width
}

@color(@color:red) { color: @color; } // this is valid

.first {
    .myclass(300px; 2em);
    @color(blue):
}

.second {
    .myclass(;4px); // blank argument takes default value
}

Import Statement

If you have multiple LESS files, you can combine them into a single CSS file during compilation using the @import directive. LESS import uses the same syntax as CSS import. If it can find the file specified then it will pull it into the compiler in place of the statement. If the file can't be found, the statement is printed to the output. The following are all valid:

@import "file";
@import 'file.less';
@import url("file");
@import url('file');
@import url(file); 

Note that if it fails to find a file it will append .less to the filename and try again. This means @import 'somefile' and @import 'somefile.less' will both import the file somefile.less.

String Mixins

It is possible to access the value of an abstract property from a string using { } operators.

@image_folder: darktheme;
.header {
    background-image: url(/images/{@image_folder}/header.png);
}

The { } syntax will also work in any string value type, which is any text wrapped in single or double quotes

Miscellaneous

As mentioned before, all properties hold constant data. This includes abstract values. While it may be convenient to think of them as variables, they don't have the ability to vary. For convenience, some tricks were implemented to make self referencing properties evaluate in order as if they had changing state. Consider the following statement:

@what: 1;
body { 
    @what: @what + 1;
    @what: @what + 2;
    .class {
        @what: @what + 1;
		width: @what;
    }
}

#something {
    @what: 200;
	body > .class;	
}

In the output, body .class has width set to 5, and #something has width set to 201. It appears from that result that the property @what is being incremented. But, as mentioned above, the name @what stores a series of unchanging values. The values use delayed evaluation, so each value holds an equation.

What this means is that the values of the properties don't change while the block is parsed, only additional property-value pairs are added to the block's definition. When the block's is compiled into CSS, the equations and property references are solved using the data in the scope. Technically, it is ambiguous what value to use for referencing a variable, because the single name can store multiple values.

The approach taken in lessphp is to use the most recent value. This gives the appearance that the block is parsed line by line. In order to prevent infinite loops when a variable references itself, a single value in the set of all values for a given name can only be used once in the chain of dereferencing.

The PHP Interface


There are a few ways to interface with the compiler. The easiest is to have it compile a LESS file when the page is requested. The static function less::ccompile, checked compile, will compile the inputed LESS file only when it is newer than the output file.

require 'lessc.inc.php';

try {
    lessc::ccompile('input.less', 'out.css');
} catch (exception $ex) {
    exit('lessc fatal error:<br />'.$ex->getMessage());
}

Note that all failures with lessc are reported through exceptions. If you need more control then you can make your own instance of lessc.

require 'lessc.inc.php';

$less = new lessc('path/to/style.less');
file_put_contents('path/to/style.css', $less->parse());

In addition to loading from a file, you can also parse from a string like so:

require 'lessc.inc.php';

$less = new lessc();
$style = '<style type="text/css">'.
    $less->parse('.block { padding: 3 + 4px }').
    '</style>';

Import Directoy

When using the @import directive, the compiler searches for files in the $importDir public property of lessc. If the compiler is loaded with a filename (either in the constructor or using ccompile) it will extract the directory and set that as the import directory




http://leafo.net/lessphp - Last updated August 6th 2009