Marginalia

[日本語訳] Angular 2 Component Styles


コンポーネントのスタイル

Angular 2のアプリケーションは標準のCSSによってスタイリングすることができます。 つまり、CSSのスタイルシートやセレクタ、ルールやメディアクエリなどについて知っていることをそのままAngular 2のアプリケーションに適用できます。

さらに、Angular 2はCSSのスタイルシートをモジュール化し、コンポーネントに同梱することが可能です。

この章ではどのようにして コンポーネントスタイル を読み込み、適用するかについて解説します。

コンポーネントスタイルを使う

Angular 2のコンポーネントを書くとき、HTMLのテンプレートだけでなく、CSSのスタイルも決めるでしょう。 コンポーネントのテンプレートに対してスタイルを適用する1つの方法は、コンポーネントのメタデータ中のstylesプロパティを使うことです。 stylesプロパティはstringの配列としてCSSを受け取ります。

@Component({
  selector: 'hero-app',
  template: `
    <h1>Tour of Heroes</h1>
    <hero-app-main [hero]=hero></hero-app-main>`,
  styles: ['h1 { font-weight: normal; }'],
  directives: [HeroAppMainComponent]
})

コンポーネントスタイルはこれまでのグローバルのスタイルとはいくつか違いが有ります。

第一に、セレクタはそのコンポーネントのテンプレート内にしか適用されません。 上の例にあるh1 { }セレクタは、hero-appコンポーネントのテンプレート内にある<h1>タグにだけ適用され、 それ以外の他の場所には影響しません。

これは古典的なCSSとくらべてモジュール化において大きな改良点です。

  1. コンポーネントのコンテキストの中で、直感的なセレクタやクラス名を使うことができます
  2. クラス名やセレクタがアプリケーション中で衝突することを気にする必要がありません
  3. コンポーネントのスタイルが別の場所から書き換えられることがありません
  4. プロジェクトの構造が変わり、CSSのコードをTypeScriptやHTMLと同じディレクトリに置くことができます。
  5. 将来的にCSSのコードを変えたり削除したりする際に、そのスタイルが他の場所で使われていないかを気にしなくてよいです

特殊セレクタ

コンポーネントスタイルではShadow DOMに由来するいくつかの特殊なセレクタを使うことができます。

:host

:host擬似クラスセレクタは、そのコンポーネント自身にマッチします。(コンポーネント内のすべての要素にヒットするわけではありません)

:host {
  display: block;
  border: 1px solid black;
}

これはホスト要素にアクセスする唯一の方法です。 他のセレクタではコンポーネント自身にマッチすることはできません。 なぜならコンポーネントの要素はそのコンポーネントのテンプレートの一部ではないからです。 ホスト要素は、その親のコンポーネントのテンプレート内の要素です。

カッコとセレクタを使って表現する 関数フォーム を使って、ホストのスタイルを状態に応じて変えることができます。 次の例では、自身にactiveクラスが付いているときだけ適用するスタイルを宣言しています。

:host(.active) {
  border-width: 3px;
}

:host-context

:host-contextセレクタは、コンポーネントの の状態に応じたスタイルを書くときに便利です。 例えば、CSSのテーマのクラスがドキュメントのbodyに適用されているとき、 コンポーネントのスタイルもそれに追従したい場合があるでしょう。

:host-context擬似クラスセレクタは、:hostの関数フォームと同じように動作します。 コンポーネントのホスト要素の親 すべて に、該当するセレクタを持っていないかをチェックします。

次の例ではコンポーネント中の<h2>要素のbackground-colorスタイルを、祖先の要素がtheme-lightを持っている時だけ変更するように書いています。

:host-context(.theme-light) h2 {
  background-color: #eef;
}

/deep/

コンポーネントスタイルは基本的に、自身のテンプレート内にしか適用されません。

ただし、/deep/セレクタを使うと、強制的に子コンポーネントの内部にスタイルを適用することができます。 ネストはどこまででも深く適用され、テンプレート中の子だけでなく、contentとしての子にも作用します。

次の例では、コンポーネント自身とその子すべてが持つ<h3>要素にマッチするCSSを書いています。

:host /deep/ h3 {
  font-style: italic;
}

/deep/セレクタは>>>と書くこともできます。

注意

/deep/>>>ViewEncapsulation.Emulatedでしか使えません。 ViewEncapsulation.Emulatedはコンポーネントのデフォルトの設定です。

スタイルをコンポーネントへ読み込む方法

コンポーネントにスタイルを追加する方法はいくつかあります。

  • テンプレートHTML中に記述する方法
  • コンポーネントのメタデータでstylesstyleUrlsを使う方法
  • CSS importsを使う方法

これまでに説明したCSSのスコーピングは、どの方法でも適用されます。

メタデータでスタイルを読み込む

@Componentデコレータのstylesプロパティで、stringの配列として記述できます。

@Component({
  selector: 'hero-app',
  template: `
    <h1>Tour of Heroes</h1>
    <hero-app-main [hero]=hero></hero-app-main>`,
  styles: ['h1 { font-weight: normal; }'],
  directives: [HeroAppMainComponent]
})

テンプレートインラインスタイル

テンプレートHTML中に<style>タグで直接埋め込むこともできます。

@Component({
  selector: 'hero-controls',
  template: `
    <style>
      button {
        background-color: white;
        border: 1px solid #777;
      }
    </style>
    <h3>Controls</h3>
    <button (click)="activate()">Activate</button>
  `
})

StyleのURLをメタデータに記述する

外部のCSSファイルをstyleUrlsとして記述することができます。

@Component({
  selector: 'hero-details',
  template: `
    <h2>{{hero.name}}</h2>
    <hero-team [hero]=hero></hero-team>
    <ng-content></ng-content>
  `,
  styleUrls: ['app/hero-details.component.css'],
  directives: [HeroTeamComponent]
})
export class HeroDetailsComponent {

注意

このURLは、index.htmlから見た相対パスであり、コンポーネントのファイルから見た相対パスではありません。

Webpackの場合

Webpackを使っている場合は、外部CSSを使いつつstylesプロパティを使用することもできます。

styles: [require('my.component.css')]

こうすることで、バンドル時にCSSの読み込みが完了します。

Linkタグによる読み込み

さらに、<link>タグでCSSファイルを読み込むこともできます。

@Component({
  selector: 'hero-team',
  template: `
    <link rel="stylesheet" href="app/hero-team.component.css">
    <h3>Team</h3>
    <ul>
      <li *ngFor="#member of hero.team">
        {{member}}
      </li>
    </ul>`
})

この場合、styleUrlsと同じように、アプリケーションのルートからの相対パスで記述します。

CSS @importsによる読み込み

最後に、コンポーネントスタイルではCSS標準の@importルールを使うこともできます。

@import 'hero-details-box.css';

ビューのカプセル化をコントロールする: Native, Emulated, None

ここまでに述べたように、コンポーネントのCSSスタイルはカプセル化されています。 Angular 2では、コンポーネントごとに、スタイルのカプセル化の設定を行うことができます。現在は3つの選択肢があります

  • Native:カプセル化にブラウザのネイティブ実装のShadow DOMを使います。 コンポーネントのテンプレートHTMLは、Shadow DOM内に描画されます。
  • Emulated:(デフォルト)Shadow DOMの振る舞いをエミュレートし、描画後の要素に適切なクラスや属性を自動で付与して擬似的にカプセル化します。
  • None:Angularによるカプセル化を行いません。 これまでに述べたスコーピングは適用されず、グローバルなスタイルが直接影響します。

これらはコンポーネントのメタデータにあるencapsulationプロパティにセットします。

// warning: few browsers support shadow DOM encapsulation at this time
encapsulation: ViewEncapsulation.Native

NativeはブラウザがShadow DOMを実装している時だけ動作します。 Shadow DOMはまだサポートが進んでいないため、多くの場合ではデフォルトのEmulatedを使うことをおすすめします。