The dynamic stylesheet language.

LESSは変数ミックスイン演算、そして関数のような動的な処理をCSSに追加拡張できます。 クライアントサイド(IE6+、Webkit、Firefox)、またnode.jsRhinoを利用してサーバーサイドでも動作します。

バージョン 1.3.1

LESSを書いてみよう:

@base: #f938ab;

.box-shadow(@style, @c) when (iscolor(@c)) {
  box-shadow:         @style @c;
  -webkit-box-shadow: @style @c;
  -moz-box-shadow:    @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box { 
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }
}

less.jsをスタイルに追加する:

<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

変数

変数は広範囲で利用している値を1ヶ所で定義することができ、その値をスタイルシート内で再利用することができます。 これにより全体の変更を1行のコードの編集で行うことなうことができます。

// LESS

@color: #4D926F;

#header {
  color: @color;
}
h2 {
  color: @color;
}
/* コンパイル後のCSS */

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

ミックスイン

ミックスインはクラス名をプロパティの一部のように記述することで、そのクラス内で設定したすべてのプロパティをほかのクラスに埋め込むことができます。
編集と同じような機能をクラスでも利用できるということです。
またミックスインは下記の例のように関数と同じく引数を設定できます。

// LESS

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

#header {
  .rounded-corners;
}
#footer {
  .rounded-corners(10px);
}
/* コンパイル後のCSS */

#header {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  -ms-border-radius: 5px;
  -o-border-radius: 5px;
  border-radius: 5px;
}
#footer {
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  -ms-border-radius: 10px;
  -o-border-radius: 10px;
  border-radius: 10px;
}

入れ子ルール

LESSではセレクタをほかのセレクタに入れ子にすることで継承を指定するために長いセレクタを組み立てる必要をなくしています。 こうすることでスタイルの継承を明確にし、さらにスタイルシートを短く記述することができます。

// LESS

#header {
  h1 {
    font-size: 26px;
    font-weight: bold;
  }
  p { font-size: 12px;
    a { text-decoration: none;
      &:hover { border-width: 1px }
    }
  }
}

/* コンパイル後のCSS */

#header h1 {
  font-size: 26px;
  font-weight: bold;
}
#header p {
  font-size: 12px;
}
#header p a {
  text-decoration: none;
}
#header p a:hover {
  border-width: 1px;
}

関数と演算

スタイルシート内の要素でほかの要素と比例する要素がありますか? 演算は色や数値の対して足し算、引き算、割り算、かけ算を行うことができます。 これによりプロパティ間に複雑な関係性を持たせることができるようになります。 演算はCSSとの互換性を保つため括弧内でのみ実行されます。 関数はJavaScriptと同じ機能を持つため値の操作を自由に行うことができます。

// LESS

@the-border: 1px;
@base-color: #111;
@red:        #842210;

#header {
  color: @base-color * 3;
  border-left: @the-border;
  border-right: @the-border * 2;
}
#footer { 
  color: @base-color + #003300;
  border-color: desaturate(@red, 10%);
}

/* コンパイル後のCSS */

#header {
  color: #333;
  border-left: 1px;
  border-right: 2px;
}
#footer { 
  color: #114411;
  border-color: #7d2717;
}

クライアントサイドでの使用法

クライアントサイドでの利用はLESSを始めるのに最も手軽な方法で、開発を行うのにも便利です。プロダクション用、とくにパフォーマンスが重要になる場合はnodeかサードパーティツールを使ってプリコンパイルを行うことを推奨しています。

.lessスタイルシートをrelの値を"stylesheet/less"にしてリンクします:

    <link rel="stylesheet/less" type="text/css" href="styles.less">

less.jsをページの上記からダウンロードし、<head>内に下記のように追記します:

    <script src="less.js" type="text/javascript"></script>

スタイルシートは必ずスクリプトのに記述するようにしてください。

ウォッチモード

ウォッチモードはスタイルの変更が保存されるたびに自動的に更新がされるクライアントサイドの機能です。

ブラウザ上のURLの後に‘#!watch’を追記してページを更新するか、コマンドラインからless.watch()を実行すれば利用できます。

サーバーサイドでの使用法

インストール

LESSをサーバにインストールするのにもっとも簡単な方法はnode.jsのパッケージマネージャであるnpmを利用する方法です:

    $ npm install -g less

コマンドラインでの利用方

LESSはコマンドラインからコンパイラを起動することができます:

    $ lessc styles.less

上記のコマンドによりstdoutへコンパイル後のCSSを出力できます。この出力をお好きなファイルにリダイレクトすることができます:

    $ lessc styles.less > styles.css

-xオプションを追記することで圧縮したCSSを出力することができます。もう少し高度な圧縮を利用したい場合はYUI CSS Compressor--yui-compressオプションを使って利用できます。

node.jsでの利用方

node.jsから下記のようにコンパイラを起動できます:

    var less = require('less');
    less.render('.class { width: 1 + 1 }', function (e, css) {
        console.log(css);
    });

以下のように出力されます。

    .class {
      width: 2;
    }

以下のように手動でパーサとコンパイラを起動することもできます:

    var parser = new(less.Parser);

    parser.parse('.class { width: 1 + 1 }', function (err, tree) {
        if (err) { return console.error(err) }
        console.log(tree.toCSS());
    });

設定

コンパイラに対していくつかのオプションを設定できます:

    var parser = new(less.Parser)({
        paths: ['.', './lib'], // @import用にパスを指定します
        filename: 'style.less' // わかりやすいエラーメッセージを出力するためファイル名を指定します
    });

    parser.parse('.class { width: 1 + 1 }', function (e, tree) {
        tree.toCSS({ compress: true }); // CSS出力を圧縮します
    });

サードパーティツール

githubのwiki上でツールに関するセクションがドキュメントされています。

コマンドラインツール

GUIツール

シンタックス

LESSはCSSのエクステンションとしてCSSへの後方互換だけではなく追加機能もCSSの既存シンタックスを利用します。そのためLESSは非常に簡単に覚えることができるし、もし確信が持てなくてもCSSに立ち戻ることができます。

変数

以下の例は一目瞭然:

@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;

#header { color: @light-blue; }

コンパイル後:

#header { color: #6c94be; }

変数名を使って変数を定義することもできます:

@fnord: "I am fnord.";
@var: 'fnord';
content: @@var;

以下のようにコンパイルされます:

content: "I am fnord.";

LESSにおける変数は実際には「定数」となり、定義できるのは1度のみとなります。

ミックスイン

LESSではスタイルのルールセット内にある宣言を別のルールセットに含むことができます。例えば以下のようなクラスがあったとします:

.bordered {
	border-top: dotted 1px black;
	border-bottom: solid 2px black;
}

そしてこれらのプロパティを他のルールセットで再利用したいとした場合、このルールセットで定義した
宣言を他のルールセットで再利用する場合は以下のように記述します:

#menu a {
	color: #111;
	.bordered;
}
.post a {
	color: red;
	.bordered;
}
.borderedクラスの宣言ブロックは #menu a.post aでも宣言されます:
#menu a {
color: #111;
	border-top: dotted 1px black;
	border-bottom: solid 2px black;
}
.post a {
color: red;
	border-top: dotted 1px black;
	border-bottom: solid 2px black;
}

どのCSSの *クラス*や*id*の宣言ブロックでも上記のようにミックスインすることができます。

ミックスインの引数利用

LESSにはクラスのようにミックスインすることができる上、パラメータを渡すこともできる特別なルールセットがあります。以下はその標準的な例です:

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

複数のルールセット内で使用する例:

#header {
	.border-radius(4px);
}
.button {
	.border-radius(6px);  
}

パラメータが利用できるミックスインはデフォルト値を定義することもできます:

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

と記述すると以下のようにすることができます:

#header {
	.border-radius;  
}

上記の例では5pxのborder-radiusを宣言したことになります。

またパラメータが利用できるミックスインではパラメータを利用しないこともできます。
ここで定義した宣言ブロックを他のルールセットで利用はしたいが、定義したルールセット自体はCSSに出力する必要がない場合に便利です:

.wrap () {
	text-wrap: wrap;
	white-space: pre-wrap;
	white-space: -moz-pre-wrap;
	word-wrap: break-word;
}

pre { .wrap }

上記の例は以下のように出力されます:

pre {
	text-wrap: wrap;
	white-space: pre-wrap;
	white-space: -moz-pre-wrap;
	word-wrap: break-word;
}

@arguments変数

@argumentsにはミックスインの中で定義した引数を渡すことができます。これにより個別に値の定義をする必要がなくなります:

.box-shadow (@x: 0, @y: 0, @blur: 1px, @color: #000) {
	box-shadow: @arguments;
	-moz-box-shadow: @arguments;
	-webkit-box-shadow: @arguments;
}
.box-shadow(2px, 5px);
上記の例は以下のように出力されます:
box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;

パターンマッチングとガードエクスプレション

パラメータによってミックスインの挙動を変更させたい場合があります。まずは基本から初めてみましょう:

.mixin (@s, @color) { ... }

.class {
	.mixin(@switch, #888);
}

.mixinの挙動を@switchの値によって変更させてみましょう。.mixinを以下のように定義したとします:

.mixin (dark, @color) {
	color: darken(@color, 10%);
}
.mixin (light, @color) {
	color: lighten(@color, 10%);
}
.mixin (@_, @color) {
	display: block;
}

そして、以下のように呼び出します:

@switch: light;

.class {
	.mixin(@switch, #888);
}

以下のようなCSSが出力されます:

.class {
	color: #a2a2a2;
	display: block;
}

.mixinに渡された色は明度が高くなりました。もし@switchdarkだった場合、結果は明度が低い色となります。

以下にどう処理されたかを示します:

  • 一番始めのミックスインの定義は第一引数としてdarkを要求していたため、マッチしません。
  • 二番目のミックスインの定義はlightを要求していたためマッチしました。
  • 三番目のミックスインの定義はどんな引数も要求していないためマッチしました。

ミックスインの定義のなかでマッチしたものだけが利用されます。変数はその変数に定義されたどの値ともマッチします。それ以外は引数として渡した値そのものにのみマッチします。

また引数の個数に対してマッチさせることができます。例は以下になります:

.mixin (@a) {
	color: @a;
}
.mixin (@a, @b) {
	color: fade(@a, @b);
}

.mixinに引数を1つ渡した場合には、一番目のミックスインの定義が出力されます。しかし、引数を2つ渡した場合は、二番目の定義が出力されます。この例では@a@bの透明度を持つことになります。

ガード

ガードはシンプルな値や変数の個数ではなく式にマッチさせたい場合に有効です。関数型のプログラミング言語になじみがあれば、すでに見たことがあることでしょう。

LESSではCSSの元になっている宣言型言語を可能な限り無視しないようにif/else宣言ではなく ガードミックスイン を条件文として実装しています。これは@media query の仕様の流れと同じになるようになっています。

まずは例を見てみましょう:

.mixin (@a) when (lightness(@a) >= 50%) {
	background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
	background-color: white;
}
.mixin (@a) {
	color: @a;
}

キーになるのはwhenキーワードです。これによりガードシーケンスが開始します(例では1つのガードのみあります)。では以下のコードを実行したとします:

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

以下のように出力されます:

.class1 {
	background-color: black;
	color: #ddd;
}
.class2 {
	background-color: white;
	color: #555;
}

ガードで利用できる比較オペレータは: > >= = =< < となります。加えてキーワードtrueは正の場合を表し、以下の2つのミックスインの例は同じ意味になります:

.truth (@a) when (@a) { ... }
.truth (@a) when (@a = true) { ... }

キーワードtrue以外の値は偽になります:

.class {
	.truth(40); // 上記の例のどの定義にも当てはまりません
}

ガードはコンマ ',' によって分割することができます。どのガードが正の場合でもマッチとして扱われます:

.mixin (@a) when (@a > 10), (@a < -10) { ... }

引数を比較することも、引数でない値を比較することもできます:

@media: mobile;

.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }

.max (@a, @b) when (@a > @b) { width: @a }
.max (@a, @b) when (@a < @b) { width: @b }

値のタイプによってミックスインをマッチさせたい場合にはis*関数を利用できます:

.mixin (@a, @b: 0) when (isnumber(@b)) { ... }
.mixin (@a, @b: black) when (iscolor(@b)) { ... }

タイプチェック用の関数の基本は以下です:

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl

もし値が数字であるかに加えて特定のユニットであるかをチェックする場合には以下が利用できます:

  • ispixel
  • ispercentage
  • isem

最後にガードの中での条件文に追加の条件が必要な場合には `and` キーワードを利用できます:

.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

notキーワードは否定の条件になります:

.mixin (@b) when not (@b > 0) { ... }

ルールセットのネスト

LESSはカスケードの代わり、またはカスケードとのコンビネーションとして *入れ子* を利用することができます。
例えば以下のCSSを見てください:

#header { color: black; }
#header .navigation {
	font-size: 12px;
}
#header .logo { 
	width: 300px; 
}
#header .logo:hover {
	text-decoration: none;
}

LESSでは以下のように記述することができます:

#header {
	color: black;
	.navigation {
		font-size: 12px;
	}
	.logo {
		width: 300px;
		&:hover { text-decoration: none }
	}
}

または下記のように書くこともできます:

#header        { color: black;
	.navigation  { font-size: 12px }
	.logo        { width: 300px;
		&:hover    { text-decoration: none }
	}
}

コードは短く、DOMツリーの構造に近い書き方をすることができます。

&コンビネータは親セレクタに対して子孫セレクタとしてセレクタを入れ子にする代わりに、親セレクタに連結することができます。
疑似クラスの:hover:focusを定義する場合には特に重要になります。

例:

.bordered {
	&.float {
		float: left; 
	}
	.top {
		margin: 5px; 
	}
}

は以下のように出力されます:

.bordered.float {
	float: left;  
}
.bordered .top {
	margin: 5px;
}

&の高度な使い方

&記号は複数クラスと入れ子ルールの順番を反対にするのにも利用できます。

例:

.child, .sibling {
    .parent & {
        color: black;
    }
    & + & {
        color: red;
    }
}

は以下のように出力されます:

.parent .child,
.parent .sibling {
    color: black;
}
.child + .child,
.child + .sibling,
.sibling + .child,
.sibling + .sibling {
    color: red;
}

また&はミックスイン内でミックスイン外の入れ子ルールに対する参照としても利用できます。

演算

数字、色、変数に演算を利用することができます。以下にいくつかの例をあげます:

@base: 5%;
@filler: @base * 2;
@other: @base + @filler;

color: #888 / 4;
background-color: @base-color + #111;
height: 100% / 2 + @filler;

これらは期待した通りに出力されます。LESSは色とユニットの違いを解釈することができます。
もしユニットを演算で利用した場合:

@var: 1px + 5;

LESSはそのユニットを結果に反映します。この例では6pxとなります。

カッコも演算では期待通りに解釈されます:

width: (@var + 5) * 2;

また以下のような複合値では必須となります:

border: (@width * 2) solid black;

カラー関数

LESSには色を変換するための関数があります。
色はまずHSLカラースペースに変換され、チャネルレベルで操作することができます:

lighten(@color, 10%);     // @colorより10%明度が*高い*値を返します
darken(@color, 10%);      // @colorより10%明度が*低い*値を返します

saturate(@color, 10%);    // @colorに10%の彩度を*追加*した値を返します
desaturate(@color, 10%);  // @colorから10%の彩度を*削減*した値を返します

fadein(@color, 10%);      // @colorから10%透明度が*高い*値を返します
fadeout(@color, 10%);     // @colorから10%透明度が*低い*値を返します
fade(@color, 50%);        // @colorの50%の透明度を持つ値を返します

spin(@color, 10);         // @colorから10度色相が大きい値を返します
spin(@color, -10);        // @colorから10度色相が小さい値を返します

mix(@color1, @color2);    // @color1 と @color2 をミックスした値を返します

contrast(@color1, @darkcolor, @lightcolor); 
		// もし@color1が >50%以上のluma(例: 明るい色)の場合に@darkcolorを返し、
		// そうでなければ@lightcolorを返します

使い方は簡単です:

@base: #f04615;

.class {
color: saturate(@base, 5%);
	background-color: lighten(spin(@base, 8), 25%);
}

また色の情報を抽出することもできます:

hue(@color);        // @colorの色相チャネルの値を返します
saturation(@color); // @colorの彩度チャネルの値を返します
lightness(@color);  // @colorの明度チャネルの値を返します
alpha(@color);      // @colorの透明度チャネルの値を返します
luma(@color);       // @colorのluma値(知覚明度)を返します

これは別のカラーチャネルを利用して新しい色を作成する場合に活用できます。例えば:

@new: hsl(hue(@old), 45%, 90%);

@new@old色相を保ちつつ、自身の彩度と明度を定義しています。

Math関数

LESSは数字の値に対して利用できる便利なmath関数を用意しています:

round(1.67); // `2` を返します
ceil(2.4);   // `3` を返します
floor(2.6);  // `2` を返します

値をパーセンテージに変換させたい場合はパーセンテージ関数を利用することができます:

percentage(0.5); // `50%` を返します

名前空間

構成やカプセル化のために変数やミックスインをグループ化する必要があることがあります。
LESSではそれを直感的に行うことがでます。例えば配布目的や再利用の際に#bundle以下に変数やミックスインを1つにまとめたいとします:

#bundle {
	.button () {
		display: block;
		border: 1px solid black;
		background-color: grey;
		&:hover { background-color: white }
	}
	.tab { ... }
	.citation { ... }
}

#header a.buttonミックスインを利用したい場合、以下のように記述できます:

#header a {
	color: orange;
	#bundle > .button;
}

スコープ

LESSにおけるスケープはほかのプログラム言語と似ています。変数やミックスインはローカル内をまず検索し、見つからなければ 親スコープを検索します。

@var: red;

#page {
	@var: white;
	#header {
		color: @var; // white
	}
}

#footer {
	color: @var; // red  
}

コメント

CSSと同じコメントルールをLESSでも利用できます:

/* Hello, I'm a CSS-style comment */
.class { color: black }

または1行コメントもLESSでは利用できますがこのコメントはコンパイル後のCSSには表示されません:

// Hi, I'm a silent comment, I won't show up in your CSS
.class { color: white }

インポート

.lessファイルはCSSと同じようにインポートすることができ、変数やミックスインはメインファイルでも利用することができます。
.less拡張子は任意のため以下の2行とも同じ意味となります:

@import "lib.less";
@import "lib";

通常のCSSファイルをインポートし、LESSでの処理が必要ない場合、.css拡張子を利用してください:

@import "lib.css";
@import "common.less"; // reset, grid, layout, typography, etc
@import "module.less"; // modules
@import "style.less"; // project specific style

@import "home.less"; // styles for home
@import "about.less"; // styles for about page
@import "article.less"; // styles for article page

ファイルは変更されず出力されます。

文字列の挿入

変数はrubyやPHPと同じように@{name}と定義することで文字列を挿入することができます:

@base-url: "http://assets.fnord.com";
background-image: url("@{base-url}/images/bg.png");

エスケープ

CSSシンタックスにおいて有効ではないか、あるいはLESSが認識できない固有のシンタックスを利用する必要がある場合に~を文字列の前に含めることで出力することができます:

.class {
	filter: ~"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png')";
}

エスケープ値と呼ばれ、以下のような出力になります:

.class {
	filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png');
}

セレクタの挿入

もしLESSの変数をセレクタとして利用したい場合に、文字列の挿入と同じように@{selector}を使って変数を参照できます。例として:

@name: blocked;
.@{name} {
    color: black;
}

は以下のように出力されます:

.blocked {
    color: black;
}

注意: LESS 1.3.1以前のバージョンでは(~"@{name}")のようなセレクタはサポートされていましたが、近い将来このサポートされなくなる予定です。

JavaScriptの実行

.lessファイル内でJavaScriptの式は値内で実行することができます。ただしこの機能を使う場合は注意が必要です。LESSのバージョン違いの互換性を保つことが出来ませんし、LESSそのもののメンテナンスも難しくなるからです。可能であれば、実装しようとしている関数についてはgithubにて依頼してください。現在デフォルトで利用できる関数について拡張しようとしています。しかし、それでもJavaScriptを.lessファイル内で実行したい場合は式をバックティックスで囲んでください:

@var: `"hello".toUpperCase() + '!'`;

上記は以下のように評価されます:

@var: "HELLO!";

文字列の挿入やエスケープを行うこともできます:

@str: "hello";
@var: ~`"@{str}".toUpperCase() + '!'`;

上記は以下のように評価されます:

@var: HELLO!;

またJavaScriptの環境にアクセスすることもできます:

@height: `document.body.clientHeight`;

アバウト

LESSはcloudheadとしても知られるAlexis Sellierによって開発されています。

Fork me on GitHub