【less】今更始める less の基本文法と tips(1) - ネストと変数編

2018/12/01 追記

前書き

お仕事の方で 5000 ステップほどある CSS を編集したりするんですが、人間が管理するにはあまりにも厳しいので、lessを導入することにしました。

流石に 1 から自分の手で書き直すのは辛いのでcss2lessを使って一度変換し、後は黙々と mixin なりなんなりを作るだけです。

CSS を知っていれば文法的に難しいところもほとんどなかったんですが、ちょっとわかりづらかったり、そのうち忘れそうなところもいくつかあったので適当にメモしていきます。

文法そのものの解説はぐぐるといっぱいでてきますが、公式のドキュメントがやはり最強でした。文章量もそんなにないので、下手にどこかの解説を読むよりこっちを全部読んだ方が早い気がします。

コンパイラのインストール

基本的にはnpm -g install lessだけでいいんですが、minify するために必要なプラグインが別途用意されているのでnpm install -g less-plugin-clean-cssもしておきましょう。

セレクタのネスト

基本形式

less ではセレクタをネストして書くことができます。例えばこんな CSS があったとします。

#header nav ul li {
  display: inline;
}

#header hoge {
  color: #000;
}

こんな風に書けます。

#header {
  nav {
    ul {
      li {
        display: inline;
      }
    }
  }

  #hoge {
    color: #000;
  }
}

疑似要素

:hover:afterなどの疑似要素は&を使うことで簡単に宣言できます。

// less
#header {
  background-color: #fff;

  &:hover {
    // #header:hover
    background-color: #000;
  }

  div {
    &:hover {
      // #header div:hover
      background-color: #ff0;
    }
  }
}
/* css */
#header {
  background-color: #fff;
}
#header:hover {
  background-color: #000;
}
#header div:hover {
  background-color: #ff0;
}

&は単純にセレクタ名を格納した擬似変数なので、疑似要素の定義以外にもこんなことができます。

// less
#header {
  &-hoge {
    color: #fff;
  }
  &-fuga {
    color: #000;
  }
}
/* css */
#header-hoge {
  color: #fff;
}
#header-fuga {
  color: #000;
}

メディアクエリのネスト

ネストした要素内でそれぞれのメディアクエリを書くことができます。さらに、メディアクエリ自体のネストも可能です。

// less
#header {
  font-size: 100%;
  @media screen and (max-width: 768px) {
    font-size: 90%;
  }
  @media screen and (max-width: 560px) {
    font-size: 80%;
  }

  div {
    @media screen and (max-width: 768px) {
      color: #ff0;
      @media screen and (min-width: 560px) {
        color: #f00;
      }
    }
  }
}
/* css */
#header {
  font-size: 100%;
}
@media screen and (max-width: 768px) {
  #header {
    font-size: 90%;
  }
}
@media screen and (max-width: 560px) {
  #header {
    font-size: 80%;
  }
}
@media screen and (max-width: 768px) {
  #header div {
    color: #ff0;
  }
}
@media screen and (max-width: 768px) and screen and (min-width: 560px) {
  #header div {
    color: #f00;
  }
}

出来上がった CSS は中々おぞましいものになりますが、まぁ、気にしないことにしましょう。

@keyframes@font-faceの扱い

自動で外に吐き出されますので、どんどんネスト内で書きましょう。

// less
#header {
  background-color: #fff;
  div {
    @font-face {
      font-family: "hoge";
      src: url("/hoge.ttf");
    }
    font-family: "hoge";
  }
}
/* css */
#header {
  background-color: #fff;
}
#header div {
  font-family: "hoge";
}
@font-face {
  font-family: "hoge";
  src: url("/hoge.ttf");
}

変数

変数宣言

@識別子:値と言う形で変数宣言が可能です。

// less
@base-color: #fff;

div {
  color: @base-color;
}
/* css */
div {
  color: #ffffff;
}

変数として宣言できるもの

割となんでもいけます。

// less
// カラーコード
@base-color: #fff;
@rgba-color: rgba(0, 0, 0, 0.5); // RGBAもOK

div {
  color: @base-color;
  background-color: @rgba-color;
}

// もちろん数値もOK
@width: 100%;
@height: 50px;
@margin: 0;

div {
  width: @width;
  height: @height;
  margin: @margin;
}

// URLなんかもOK
@image-dir: "../images";
div {
  background-image: url("@{image-dir}/image.jpg");
}

// 変数にCSSのルールセットを定義することも可能
@rules: {
  color: @base-color;
  background-color: @rgba-color;
  width: @width;
  height: @height;
  margin: @margin;
  background-image: url("@{image-dir}/image.jpg");
};

div {
  @rules(); // ルールセットを展開する場合は"()"
}
/* css */
div {
  color: #ffffff;
  background-color: rgba(0, 0, 0, 0.5);
}
div {
  width: 100%;
  height: 50px;
  margin: 0;
}
div {
  background-image: url("../images/image.jpg");
}
div {
  color: #ffffff;
  background-color: rgba(0, 0, 0, 0.5);
  width: 100%;
  height: 50px;
  margin: 0;
  background-image: url("../images/image.jpg");
}

変数として宣言できるけど使い道が微妙なもの

セレクタを宣言しておくことも可能です。複数のセレクタを一まとめにしたいとき便利かもしれません。

// less
@copyright: #footer address#copyright;

@{copyright} {
  color: #000;
}
/* css */
#footer address#copyright {
  color: #000;
}

また、プロパティ名も宣言できます。長いプロパティ名を省略するとき…とか?

// less
@ff: font-family;

div {
  @{ff}: monospace;
}
/* css */
div {
  font-family: monospace;
}

変数名そのものを宣言しておくことも可能です。この辺まで来ると普通に可読性が落ちそうです。

// less
@var-name: "mono";
@mono: monospace;
@ff: font-family;

div {
  @{ff}: @@var-name;
}
/* css */
div {
  font-family: monospace;
}

メディアクエリを変数として宣言

メディアクエリの条件を変数として宣言しておくことも可能です。

// less
@tablet: ~"screen and (max-width: 768px)"; // "()"が入っているものは"~"をつけてエスケープする

@media @tablet {
  div {
    color: #fff;
  }
}
/* css */
@media screen and (max-width: 768px) {
  div {
    color: #fff;
  }
}

変数の型

厳密には less に型と言う概念はないんですが、型チェックっぽい関数が用意されています。

該当するもの 該当しないもの
Number
  • 1234
  • 56px
  • 7.8%
  • 9em
  • #ff0
  • blue
  • "string"
  • keyword
  • url(...)
  • { color: #fff; }
String
  • "string"
  • #ff0
  • blue
  • 1234
  • 56px
  • 7.8%
  • 9em
  • keyword
  • url(...)
  • { color: #fff; }
Color
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 7.8%
  • 9em
  • keyword
  • url(...)
  • { color: #fff; }
Keyword
  • keyword
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 7.8%
  • 9em
  • url(...)
  • { color: #fff; }
Url
  • url(...)
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 7.8%
  • 9em
  • keyword
  • { color: #fff; }
Pixel
  • 56px
  • #ff0
  • blue
  • "string"
  • 1234
  • 7.8%
  • keyword
  • url(...)
  • { color: #fff; }
Em
  • 9em
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 7.8%
  • keyword
  • url(...)
  • { color: #fff; }
Percentage
  • 7.8%
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 9em
  • keyword
  • url(...)
  • { color: #fff; }
Ruleset
  • { color: #fff; }
  • #ff0
  • blue
  • "string"
  • 1234
  • 56px
  • 7.8%
  • 9em
  • keyword
  • url(...)

スコープ

変数にはスコープがあります。あるセレクタ内で宣言された変数は、他のセレクタから呼び出せません。

@global-color: #000;

#hoge {
  @inner-color: #fff;
  color: @global-color;

  div {
    color: @inner-color;
  }
}

#fuga {
  color: @inner-color; // スコープ外なので呼び出せない
}

他のスコープで宣言された変数を書き換えると、そのスコープ内でのみ値が書き換わります。

// less
@global-color: #000;

#hoge {
  color: @global-color;
}

#fuga {
  @global-color: #fff; // fugaで@global-colorの値を変更する
  color: @global-color;
}

#piyo {
  color: @global-color;
}
/* css */
#hoge {
  color: #000000;
}
#fuga {
  color: #ffffff;
}
#piyo {
  color: #000000; /* piyoの@global-colorは変わらない */
}

ただし、同スコープ内で変数の値を書き換えると、変更した場所に関わらず後に宣言した値が適用されます。

// less
@global-color: #000;

#hoge {
  color: @global-color;
}

@global-color: #fff; // hogeの後に@global-colorを書き換える

#fuga {
  color: @global-color;
}

#piyo {
  color: @global-color;
}
/* css */
/* @global-colorの値はすべて#fffになる */
#hoge {
  color: #ffffff;
}
#fuga {
  color: #ffffff;
}
#piyo {
  color: #ffffff;
}

なるべくであればグローバルなスコープでの変数は書き換えないようにしましょう。危なっかしいので…。

まとめ

すごい長くなりそうなので続き物にします。

次回は mixin 関連を予定。早ければ明日に。

(2015/08/30)書きました。:-)