htmlcss CSSの拡張メタ言語 LESS の基本的な使い方のメモ

2013年9月1日

以下のサイトを参考にまとめた「LESS」の基本的な使い方のメモ。詳細(解説等)は以下のサイトを参考にしてください。

参考にさせていただいたサイト

LESS 日本語ページ「The dynamic stylesheet language」
gihyo.jp 「LESSで3倍ラクするスマートフォンコーディング」

ネスト

CSS のセレクタを入れ子にすることができる

//LESS
#header {
  h1 {
    font-size: 26px;
    font-weight: bold;
  }
  p { font-size: 18px;
    a { text-decoration: none;
      &:hover { color: red; }
    }
  }
}

コンパイルされた CSS

#header h1 {
  font-size: 26px;
  font-weight: bold;
}
#header p {
  font-size: 18px;
}
#header p a {
  text-decoration: none;
}
#header p a:hover {
  color: red;
}

& コンビネータ

「&」には「& を指定した親要素に,& 以降のセレクタをつなげる」という意味がある。
「&」のあとにスペースを入れると、普通にネストした場合と同様になってしまう。

//LESS
.foo {
     background: red;
     &.var {
          background: blue;
     }
}

a {
     color: red;
     &:hover {
          color: blue;
     }
}

コンパイルされた CSS

.foo {
  background: red;
}
.foo.var {
  background: blue;
}
a {
  color: red;
}
a:hover {
  color: blue;
}

& を使って入れ子ルールの順番を反対にする

//Less
.child, .sibling {
    .parent & {
        color: black;
    }
}

コンパイルされた CSS

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

& を使って複数クラスを掛け合わせる

//Less
.child, .sibling {
    & + & {
        color: red;
    }
}

コンパイルされた CSS

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

特定の class がある要素に付いている場合のみ指定する方法

たとえば「”eco”という class が body に付いているときのみ,背景を緑にする」には、「&」を利用すると,「親要素に body.eco があった場合」という記述ができる。

//Less
.foo {
     .var {
          background: red;
     }
     body.eco & .var {
          background: green;
     }
}

コンパイルされた CSS

.foo .var {
  background: red;
}
body.eco .foo .var {
  background: green;
}

変数

  • 「@~:値」で変数を定義できる。(@以降の文字列は任意のもの)
  • LESSにおける変数は実際には「定数」みたいなもので、定義できるのは1度のみ
  • 統一したい色や余白の幅、フォントサイズなどを指定しておくと便利
//Less
@color : #0B68B5;
@color2: @color + #663333;  //色の演算も可能
@h1size: 24px;
@h2size: round(@h1size * 0.8);  //math関数の利用
h1 {
  color: @color;
  font-size: @h1size;
}
h2 {
  color: @color2;
  font-size: @h2size;
}

コンパイルされた CSS

h1 {
  color: #0b68b5;
  font-size: 24px;
}
h2 {
  color: #719be8;
  font-size: 19px;
}

変数名を使って変数を定義

//Less
@foo: "This is Foo.";
@bar: 'foo';
#foo {
  content: @@bar;  //@bar は 'foo' なので @@bar は @foo
}

コンパイルされた CSS

#foo {
  content: "This is Foo.";
}

ミックスイン

ミックスイン(mixin)
あらかじめ宣言しておいたCSSプロパティの組み合わせを呼び出すことができる仕組み
  • ミックスインはクラス名をプロパティの一部のように記述することで、そのクラス内で設定したすべてのプロパティをほかのクラスに埋め込むことができる。
  • ミックスインは関数と同じく引数(複数指定可能)を設定できる。
  • 引数のデフォルト値は「@~:値」で指定可能(ミックスインの変数の後に「:」を入れてデフォルト値を指定)
  • LESSでは,ミックスインとして宣言したclassやidは,HTMLの中にidやclassとして記述しない(ことが多い)
//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 {
  border: 1px solid #ccc;
  .rounded-corners;
}

#main {
  border: 2px solid #999;
  .rounded-corners(10px);
}

コンパイルされた CSS

#header {
  border: 1px solid #ccc;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  -ms-border-radius: 5px;
  -o-border-radius: 5px;
  border-radius: 5px;
}
#main {
  border: 2px solid #999;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  -ms-border-radius: 10px;
  -o-border-radius: 10px;
  border-radius: 10px;
}

@arguments 変数

@arguments にはミックスインの中で定義した引数を渡すことができ、これにより個別に値の定義をしなくて済む。

//Less
.box-shadow (@x: 0, @y: 0, @blur: 1px, @color: #000) {
  box-shadow: @arguments;
  -moz-box-shadow: @arguments;
  -webkit-box-shadow: @arguments;
}
#header {
  .box-shadow(2px, 5px);
}

コンパイルされた CSS

#header {
  box-shadow: 2px 5px 1px #000000;
  -moz-box-shadow: 2px 5px 1px #000000;
  -webkit-box-shadow: 2px 5px 1px #000000;
}

演算

四則演算を用いて値を指定することができ、変数値を用いて計算するときなどに便利。

例えば、ある変数を文字サイズの基準値として設定すれば、その変数の値を変更するだけで,すべての文字サイズの比率を保ったまま文字の大きさを変更することができる。余白やマージンの値などにも利用すると便利。

//Less
@baseFontSize: 12px;  //文字サイズの基準値
h1 {
  font-size: @baseFontSize * 2;  //基準値の2倍
}
h2 {
  font-size: round(@baseFontSize * 1.8);  //基準値の1.8倍を四捨五入
}

コンパイルされた CSS

h1 {
  font-size: 24px;
}
h2 {
  font-size: 22px;
}

Math関数

LESS は数字の値に対して利用できる math 関数を用意している。値をパーセンテージに変換させたい場合はパーセンテージ関数を利用することができる。

//Less
round(1.67); // `2` を返す(四捨五入)
ceil(2.4);   // `3` を返す(切り上げ)
floor(2.6);  // `2` を返す(切り下げ)

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

以下は Math 関数を使って、最初の li 要素の幅は34pxに、それ以外の li 要素の幅は33pxにする例。

//Less
@ulWidth: 100px;
@lis: 3;

ul {
  width: @ulWidth;
   li {
      width: floor(@ulWidth/@lis);  //切り下げ
      &:first-child {
          width: ceil(@ulWidth/@lis); 切り上げ
      }
   }
}

コンパイルされた CSS

ul {
  width: 100px;
}
ul li {
  width: 33px;
}
ul li:first-child {
  width: 34px;
}

コメント

  • CSS のコメント(/* ~ */)に加え,「//」を行頭につける形のコメントも可能。
  • コンパイルした際に「//」のコメントが生成対象から外れ,リソースの削減になる

インポート

CSS の「@import: url()」
外部から読み出すCSSのファイルを追加。指定したCSSは別ファイルとしてリクエストされる
LESS の「@import」
生成の際に「@import」を貼りつけた箇所にそのまま CSS を貼りつけたような状態になり,1つのファイルとして扱われる

CSSの「@import:url()」は,パフォーマンス的な問題があるが、LESSの「@import」ではそのような心配がない。

そのため,機能ごとにCSSを分割して,コンパイル時にひとまとめに結合すると良い。

.less 拡張子は任意のため以下の2行とも同じ意味。

//Less
@import "lib.less";
@import "lib";

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

//Less
@import "lib.css";

変数のスコープ(参照範囲)

変数やミックスインはローカル内をまず検索し、見つからなければ 親スコープを検索し、最後にグローバルを検索する。

//Less
@var: red;  //グローバル

#page {
  @var: white;  //ローカル
  #header {
    color: @var; // white
  }
}

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

コンパイルされた CSS

#page #header {
  color: #ffffff;
}
#footer {
  color: #ff0000;
}

特定ページでしか使わない変数などは,グローバルな変数を宣言するのではなく,ページごとに id を振り,その id の中で変数を宣言すると良い。

//Less
@pageColor: yellow;  //指定ページ意外の色(グローバル)
body {
  background: @pageColor;     //yellow(グローバル)
  #top {
     @pageColor: red;  //ローカル(トップページ)
     background: @pageColor;     //red
  }
  
  #about {
     @pageColor: blue;  //ローカル(Aboutページ)
     background: @pageColor;     //blue
  }
  
  #contact {
     @pageColor: green;  //ローカル(Contactページ)
     background: @pageColor;     //green
  }
}
body {
  background: #ffff00;
}
body #top {
  background: #ff0000;
}
body #about {
  background: #0000ff;
}
body #contact {
  background: #008000;
}

変数定義の注意点

  • 同じスコープで,同じ変数に,違う値を宣言してはいけない。
  • 通常プログラミング言語では,「変数」は,随時その値を変更してくことができるが、LESS では,同じスコープでは後で宣言した内容が全範囲において優先される。
  • 変数(Variables)と名前が付いているが,実質的には定数のようなもの。

名前空間

構成やカプセル化のために変数やミックスインをグループ化することができる。
以下は #foo に変数やミックスインを1つにまとめて、#bar a で.button ミックスインを利用する例。

//Less
#foo {
  .button () {
    display: block;
    border: 1px solid black;
    background-color: grey;
    &:hover { background-color: white }
  }
  .box { ... }
  .border { ... }

}

#bar a {
  color: red;
  #foo > .button;
}

コンパイルされた CSS

#bar a {
  color: red;
  display: block;
  border: 1px solid black;
  background-color: grey;
}
#bar a:hover {
  background-color: #ffffff;
}

カラー関数

カラー関数
LESS の色を演算する機能で、以下の4種類の値を,加算や割合で計算することができる。
  • 明度(hue)
  • 彩度(saturation)
  • 色相(lightness)
  • 透明度(alpha)

色はまず HSL カラースペース(色空間)に変換され、チャネルレベルで操作することができる。

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

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

spin(@color, 10);         // @color から 10 度色相が大きい値を返す
spin(@color, -10);        // @color から 10 度色相が小さい値を返す
//spinのみ,割合の値の単位が%ではない

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

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

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

lighten()、darken()、saturate()、desaturate()は spin() 同様に負(マイナス)の値も指定できる。以下の2つは同じカラーコードになる。

//Less
lighten(@color, 10%);     //@colorより 10 %明度が高い色を計算する
darken(@color, -10%);     //@colorより -10 %明度が低い色(=10%明度が高い色を計算する)
HSL カラースペース(色空間)
色相(Hue)、彩度(Saturation)、明度(lightness)の3つの成分からなる色空間のこと。色相を0〜360度の範囲(赤を0度に置き、時計回りに赤、橙、黄、黄緑、緑、青緑、青、青紫、紫、赤紫の順に変化)で、彩度を純色から灰色の範囲で、明度を白から黒の範囲で表す。CSS3 で HSL による色指定を行うには、hsl 関数(透明度を指定する際には、hsla)を用いて指定。引数は、色相(0〜360までの数値)、彩度(0%〜100%)、明度(0%〜100%)の順に指定。
(hsla 関数の場合は、上記に加え、透明度を0.0〜1.0の値で指定。)
参考サイト:Asial Blog「HSL色空間による色指定のすゝめ」

カラー関数を使ってミックスイン(.bg_gradient)を作成し、#foo、#bar に適用する例

//Less
.bg_gradient(@color:#FF3300) {
   background: linear-gradient(
          @color,
          darken(@color, 30%)
     );
}

#foo {
  .bg_gradient;
}

#bar {
  .bg_gradient(fade(green, 20%));
}

コンパイルされた CSS

#foo {
  background: linear-gradient(#ff3300, #661400);
}
#bar {
  background: linear-gradient(rgba(0, 128, 0, 0.2), rgba(0, 0, 0, 0.2));
}

色情報の取得

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

文字列

他のプログラム言語と同様,LESS でも’(シングルクォーテーション)や”(ダブルクォーテーション)で囲ったものは,すべて文字列として扱う。

文字列の挿入

変数は ruby や PHP と同じように @{name} と定義することで文字列を挿入することができる。
url の宣言に利用する例

//Less
@base-url: "http://www.webdesignleaves.com/";

#foo {
  background-image: url("@{base-url}/images/bg.png");
}

コンパイルされた CSS

#foo {
  background-image: url("http://www.webdesignleaves.com//images/bg.png");
}

エスケープ

CSS シンタックスにおいて有効ではないか、あるいは LESS が認識できない固有のシンタックスを利用する必要がある場合は「~」を文字列の前に付けることで出力することができる。エスケープすることで、カンマなど LESS の特定の機能を持つ文字を出力することが可能。

また、エスケープされた文字列内では、変数を記述しても通常の文字列として認識されるため、エスケープ内で変数を利用するには、@{(変数名)}とする必要がある。

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

.opacity(@opacity) {
  opacity: @opacity;
  // IE8 filter
  @opacity-ie: (@opacity * 100);
  filter: ~"alpha(opacity=@{opacity-ie})";
}
.foo {
  .opacity(0.5);
}

コンパイルされた CSS

.class {
  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='image.png');
}
.foo {
  opacity: 0.5;
  filter: alpha(opacity=50);
}

カンマが含まれる場合のエスケープの例

//Less
.box-shadow(@arg){
    -moz-box-shadow: @arg;
    -webkit-box-shadow: @arg;
    box-shadow: @arg;
}
 
.shadow1{
  //複数のbox-shadowではカンマが含まれるためエスケープ(この場合改行するとエラー)
    .box-shadow(~"0 1px 2px rgba(255,255,255,0.2) inset, 0 -1px 2px rgba(0,0,0,0.15) inset");
}
.shadow2{
  //引数を変数に入れて指定することも可能(この場合改行も使える)結果は.shadow1 と同じ。
    @arg:
      0 1px 2px rgba(255,255,255,0.2) inset,
      0 -1px 2px rgba(0,0,0,0.15) inset;
    .box-shadow(@arg);
}

コンパイルされた CSS

.shadow1 {
  -moz-box-shadow: 0 1px 2px rgba(255,255,255,0.2) inset, 0 -1px 2px rgba(0,0,0,0.15) inset;
  -webkit-box-shadow: 0 1px 2px rgba(255,255,255,0.2) inset, 0 -1px 2px rgba(0,0,0,0.15) inset;
  box-shadow: 0 1px 2px rgba(255,255,255,0.2) inset, 0 -1px 2px rgba(0,0,0,0.15) inset;
}
.shadow2 {
  -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2) inset, 0 -1px 2px rgba(0, 0, 0, 0.15) inset;
  -webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2) inset, 0 -1px 2px rgba(0, 0, 0, 0.15) inset;
  box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2) inset, 0 -1px 2px rgba(0, 0, 0, 0.15) inset;
}

/(スラッシュ)などの記号をプロパティの値として記述する場合の例。「’」で囲ったものは文字列として認識されるが,それをさらに「~」でエスケープすることにより,「/」を「割る」ではなく「/」という文字(記号)のまま認識させることができる。

//Less
.class1 {
  border-radius: 100px ~'/' 50px;
}

.class2 {
    border-radius: 100px / 50px;  //「100px÷50px」という計算結果が出力されてしまう
}

コンパイルされた CSS

.class1 {
  border-radius: 100px / 50px;
}
.class2 {
  border-radius: 2px;
}

JavaScript の実行

  • 制限付きだが,LESS ファイルの中でJavaScriptを実行できる。
  • LESS のバージョン違いの互換性を保つことが出来ない。
  • LESS そのもののメンテナンスも難しくなる。
  • 数値計算などは元から LESS で扱えるので,JavaScript では文字列を編集するのがおもな活用法。
  • JavaScript の関数を記述する際は`(バッククォート)で対象となる箇所を囲う必要がある。
//Less
@foo: 'Hello';
@bar: 'World';

div::before {
     content: `@{foo}.length`;     //文字列の長さを調べる:5
}
div::before {
     content: `@{foo}.slice(0, 2)`;     //文字列の一部を切り取る:"He"
}

div::before {
     content: `@{foo}.match(/Hell/) + "!"`;     //正規表現で該当した部分を取り出して「"!"」を連結:"Hell!"
}

div::before {
     content: `@{bar}.replace('World','Universe')`;     //該当した部分を置き換える:"Word"
}

コンパイルされた CSS

div::before {
  content: 5;
}
div::before {
  content: "He";
}
div::before {
  content: "Hell!";
}
div::before {
  content: "Universe";
}

パターンマッチング

パラメータによってミックスインの挙動を変更させる。
以下は第1パラメータの値によって挙動を変更させる例。

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

@switch1: light;
@switch2: dark;

.class1 {
  .mixin_switch(@switch1, #888);
}

.class2 {
  .mixin_switch(@switch2, #888);
}
  • 一番始めのミックスインの定義は第一引数としてdarkを要求しているので、.class2(@switch2)にマッチ。
  • 二番目のミックスインの定義はlightを要求しているので、.class1(@switch1)にマッチ。
  • 三番目のミックスインの定義はどんな引数も要求していないのでどちらにもマッチ。

コンパイルされた CSS

.class1 {
  color: #a2a2a2;
  display: block;
}
.class2 {
  color: #6f6f6f;
  display: block;
}

引数の個数に対してマッチさせる(引数の個数により挙動を変更させる)例。

//Less
.mixin_pn (@a) {
  color: @a;
}
.mixin_pn (@a, @b) {
  color: fade(@a, @b);
}

.class1 {
  .mixin_pn(#888);
}

.class2 {
  .mixin_pn(#888, 50%);
}

コンパイルされた CSS

.class1 {
  color: #888888;
}
.class2 {
  color: rgba(136, 136, 136, 0.5);
}

条件分岐

  • LESS の場合,if ではなく,when という構文を使う。(LESS では CSS の元になっている宣言型言語を可能な限り無視しないように if/else 宣言ではなく「ガードミックスイン」を条件文として実装していて、@media query の仕様の流れと同じになるようになっているとのこと。)
  • 利用できる比較オペレータ:「 > 」「 >= 」「 = 」「 =< 」「 < 」
  • キーワード「true」以外の値は偽となる。
  • 条件文に追加の条件が必要な場合には 「and」キーワードを利用できる。
  • 「not」キーワードは否定の条件になる。
  • 条件はカンマ「,」によって分割することができ、いずれかの条件が真の場合はマッチとして扱われる。
//Less
.mixin_color (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin_color (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin_color (@a) {
  color: @a;
}

.class1 { .mixin_color(#eee) }
.class2 { .mixin_color(#666) }

コンパイルされた CSS

.class1 {
  background-color: black;
  color: #eeeeee;
}
.class2 {
  background-color: white;
  color: #666666;
}

特定のベンダープレフィックスのみを付ける例。変数(@webkit、@moz)の値を変更することにより出力を変更できる。

//Less
@webkit: true;
@moz: false;

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

.foo {
  .border-radius(5px);
}

コンパイルされた CSS

.foo {
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

「and」キーワード

条件の追加(&& のようなもの)

//Less
.mixin (@a) when (ispixel(@a)) and (@a > 10) 
  {
    margin: @a;
   }
#foo {
  .mixin(20px);
}
#bar {
  .mixin(5px);
}

コンパイルされた CSS(#bar は(@a > 10) を満たさない)

#foo {
  margin: 20px;
}

「not」キーワード

否定の条件

//Less
.mixin (@b) when not (@b > 10){
    margin: @b;
   }
   
#foo {
  .mixin(20px);
}
#bar {
  .mixin(5px);
}

コンパイルされた CSS(#foo は not (@b > 10) 「10より大きくない」を満たさない)

#bar {
  margin: 5px;
}

条件をカンマ「,」で分割

いずれかの条件が真の場合はマッチとして扱われる。

//Less
.mixin (@a) when (@a > 10), (@a < -10){
    margin: @a;
   }
   
#foo {
  .mixin(20px);
}
#bar {
  .mixin(-50px);
}
#not {
  .mixin(-3px);
}

コンパイルされた CSS(#not はいずれも満たしていない。)

#foo {
  margin: 20px;
}
#bar {
  margin: -50px;
}

タイプチェック用の関数

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl
  • ispixel
  • ispercentage
  • isem