@ Sass

@extend:スタイルの継承

@extendの基本

@extend は指定したセレクタのスタイルを継承できる機能です。

次のソースコードでは、.box で使ったスタイルを .item にも継承するために「@extend .box;」というルールで記述しています。

styles.scss

@charset "utf-8";
.box {
  margin: 0 0 30px;
  padding: 15px;
  border: 1px solid #ccc;
}
// .box で使ったスタイルを継承
.item {
  @extend .box;
}

コンパイル後の CSS は次のようになります。

styles.css

.box, .item {
  margin: 0 0 30px;
  padding: 15px;
  border: 1px solid #ccc;
}

次はもう少し @extend の便利さがわかる例を見てみましょう。

@extend 専用の Sass ファイルを用意して、スタイル用の Sass ファイル(style.scss)にパーシャルを利用してインポートします。

_extend.scss

.btnBase {
  text-align: center;
  margin: 0 0 10px;
  a {
    display: block;
    padding: 10px 20px;
    background: #999;
    color: #fff;
  }
}
.imgL {
  float: left;
  margin-right: 15px;
}

styles.scss

@import "extend";
ul.btnList {
  li {
    @extend .btnBase;
  }
}
.item {
  width: 300px;
  .photo {
    @extend .imgL;
    margin-bottom: 10px;
  }
  .text {
    .btn {
      @extend .btnBase;
      text-align: left;
    }
  }
}

あらかじめ用意した @extend 専用の Sass ファイル(_extend.scss)に書かれている「.btnBase」というセレクタのスタイルを2箇所で継承しています。

また、.btn では、.btnBase の text-align: center; を上書きして、値を left に変えています。

このように、同じスタイルを使ってから一部を上書きしたり、.photo では、_extend.scss の .imgL のスタイルを継承しつつスタイルを追加しています。

コンパイル後の CSS は次のようになります。

styles.css

.btnBase, ul.btnList li, .item .text .btn {
  text-align: center;
  margin: 0 0 10px;
}
.btnBase a, ul.btnList li a, .item .text .btn a {
  display: block;
  padding: 10px 20px;
  background: #999;
  color: #fff;
}
.imgL, .item .photo {
  float: left;
  margin-right: 15px;
}
.item {
  width: 300px;
}
.item .photo {
  margin-bottom: 10px;
}
.item .text .btn {
  text-align: left;
}

同じルールセット内で、複数継承する

@extend は複数指定することもできます。

styles.scss

@charset "utf-8";
// @extend
.notes {
  color: #d92c25;
  font-weight: bold;
  text-align: center;
}
.bd {
  border-top: 1px solid #900;
  border-bottom: 1px solid #900;
}
// 複数継承
.item {
  small {
    display: block;
    padding: 10px;
    @extend .notes;
    @extend .bd;
  }
}

コンパイル後の CSS は次のようになります。

styles.css

.notes, .item small {
  color: #d92c25;
  font-weight: bold;
  text-align: center;
}
.bd, .item small {
  border-top: 1px solid #900;
  border-bottom: 1px solid #900;
}
.item small {
  display: block;
  padding: 10px;
}

@extend の連鎖

@extend は連鎖させることができます。

style.scss

@charset "utf-8";
// @extend
.att {
  color: red;
  font-weight: normal;
}
.attBox {
  // .att を継承
  @extend .att;
  padding: 15px;
  border: 1px solid red;
}
.notes {
  // .att が継承されている .attBox を継承
  @extend .attBox;
}

コンパイル後の CSS は @extend を継承したセレクタ .attBox を継承して、次のようになります。

styles.css

.att, .attBox, .notes {
  color: red;
  font-weight: normal;
}
.attBox, .notes {
  padding: 15px;
  border: 1px solid red;
}

@extend が使えるセレクタ

クラスセレクタ以外にも次のセレクタを使うことができます。

  1. タイプセレクタ・・・・・div {・・・}、p {・・・} など
  2. IDセレクタ・・・・・#main {・・・} など
  3. 属性セレクタ・・・・・input[type=”radio”] {・・・}、[class] など
  4. 連結セレクタ・・・・・#main.text {・・・}、.text.box {・・・} など
  5. 擬似クラス・・・・・:link {・・・}、:first-child {・・・} など
  6. 擬似要素・・・・・:before {・・・}、:after {・・・} など

@extend が使える例

styles.scss

@charset "utf-8";
// クラスセレクタ
.class {
  color: blue;
}
// タイプセレクタ
small {
  color: blue;
}
// IDセレクタ
#selectorID {
  color: blue;
}
// 連結セレクタ
.pd.bd {
  color: blue;
}
// 属性セレクタ
input[type="text"] {
  color: blue;
}
// 擬似クラス
a:hover {
  color: blue;
}
// 擬似擬似要素
p:first-line {
  color: blue;
}

@extend が使えない例

styles.scss

@charset "utf-8";
// 子孫セレクタ
.item p {
  margin-bottom: 15px;
}
// 子セレクタ
#main > article {
  margin-bottom: 15px;
}
// 隣接セレクタ
h2 + h2 {
  margin-bottom: 15px;
}
// 間接セレクタ
h2 ~ h2 {
  margin-bottom: 15px;
}

@extend 専用のプレースホルダーセレクタ

@extend はセレクタを継承する機能なので、コンパイル後の CSS には継承元のセレクタも生成されます。

しかし、@extend 専用としてセレクタを書きたい場合など、継承元のセレクタは不要になる場合もあります。

そういった場合に ID セレクタやクラスセレクタの 「#」や「.」の代わりに、「%」を使う @extend 専用のプレイスホルダーセレクタを使うことで、そのセレクタを生成させないことができます。

styles.scss

@charset "utf-8";
// @extend 専用のプレイスホルダーセレクタ
%boxBase {
  padding: 15px;
  border: 1px solid #999;
}
// プレイスホルダーセレクタを継承
.item {
  @extend %boxBase;
  margin-bottom: 20px;
}
section {
  @extend %boxBase;
  margin-bottom: 60px;
}

コンパイル後の CSS は次のようになります。

styles.css

.item, section {
  padding: 15px;
  border: 1px solid #999;
}
.item {
  margin-bottom: 20px;
}
section {
  margin-bottom: 60px;
}

@media 内では @extend は使用できない

@extend は @media の外で使われているセレクタを継承することができません。

次のソースコードはエラーになります。

styles.scss

@charset "utf-8";
// @extend 専用のプレイスホルダーセレクタ
%boxBase {
  display: inline-block;
  padding: 5px 10px;
  background: #eee;
}
@media all and (orientation: landscape) {
  a {
    @extend %btnBase;
  }
}

これを解決するには、@media 内に継承したいセレクタを書く必要があります。

styles.scss

@charset "utf-8";
@media all and (orientation: landscape) {
  // @extend 専用のプレイスホルダーセレクタ
  %btnBase {
  display: inline-block;
  padding: 5px 10px;
  background: #eee;
  }
  a {
    @extend %btnBase;
  }
}

警告を抑止する !optional フラグ

!optional フラグとは、存在しないセレクタに対して @extend を使った場合に出る警告を出さないようにする機能です。

警告の有無が変わるだけで。コンパイルの結果には影響ありません。

styles.scss

.btn {
  @extend %btnBase !optional;
}