angular

angular.io Guide: Component Styles

More than 1 year has passed since last update.

これは、Angular の公式ドキュメントの Component Styles の章を意訳したものです。
駆け足で翻訳したので至らない点もありますが、あしからずご了承を。
バージョン 4.2.6 のドキュメントをベースにしています。

Component Styles

Angular のあるアプリケーションは標準のCSSでスタイルされています。つまり、CSSスタイルシート、セレクタ、ルール、およびメディアクエリについて知っているすべてをAngular アプリケーションに直接適用できます。

さらに、Angularはコンポーネントスタイルをコンポーネントとバンドルすることで、通常のスタイルシートよりもモジュラーデザインを可能にします。

このページでは、これらのコンポーネントスタイルをロードして適用する方法について説明します。

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

あなたが書くすべてのAngularコンポーネントについて、HTMLテンプレートだけでなく、そのテンプレートに付随するCSSスタイルを定義して、必要なセレクタ、ルール、メディアクエリを指定することもできます。

これを行う1つの方法は、コンポーネントのメタデータにstylesプロパティを設定することです。 stylesプロパティは、CSSコードを含む文字列の配列をとります。通常は、次の例のように1つの文字列を与えます。

src/app/hero-app.component.ts

  selector: 'hero-app',
  template: `
    <h1>Tour of Heroes</h1>
    <hero-app-main [hero]=hero></hero-app-main>`,
  styles: ['h1 { font-weight: normal; }']
})
export class HeroAppComponent {
/* . . . */
}

コンポーネントのスタイルに入れたセレクタは、そのコンポーネントのテンプレート内でのみ適用されます。

前の例の h1 セレクタは、HeroAppComponent のテンプレートの <h1> タグにのみ適用されます。アプリケーション内の他の場所にある <h1> 要素は影響を受けません。

これは、CSSの伝統的な動作と比較して、モジュール性の大幅な向上です。

  • CSSクラス名と各コンポーネントの文脈で最も合理的なセレクタを使用することができます。
  • クラス名とセレクタはコンポーネントに対してローカルであり、アプリケーションの他の場所で使用されるクラスやセレクタと衝突しません。
  • アプリケーション内の他の場所でのスタイルの変更は、コンポーネントのスタイルに影響しません。
  • それぞれのコンポーネントのCSSコードをコンポーネントのTypeScriptとHTMLコードと同じ場所に配置することができ、きれいで整然としたプロジェクト構造につながります。
  • アプリケーション全体を検索せずに、コンポーネントのCSSコードを変更または削除して、コードがどこに使用されているかを調べることができます。

特殊セレクタ

コンポーネントスタイルには、シャドウ DOM スタイルスコープの世界からの特別なセレクタがいくつかあります(W3CサイトのCSSスコープモジュールレベル1のページを参照)。

:host

:host 擬似クラスセレクタを使用して、(コンポーネントのテンプレート内のターゲティング要素とは対照的に)コンポーネントをホストする要素のスタイルをターゲットにします。

src/app/hero-details.component.css

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

:host セレクタは、ホスト要素をターゲットにする唯一の方法です。
コンポーネントの独自のテンプレートの一部ではないため、他のセレクタを使用してコンポーネント内からホスト要素に到達することはできません。ホスト要素は、親コンポーネントのテンプレート内にあります。

関数フォームを使用して、ホストの後にカッコ内に別のセレクタを含めることで、ホストスタイルを条件付きで適用します。

次の例では、active なCSSクラスも持っている場合にのみ、ホスト要素を再度対象としています。

src/app/hero-details.component.css

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

:host-context

場合によっては、コンポーネントのビューの外にある条件に基づいてスタイルを適用すると便利です。たとえば、CSSのテーマクラスをドキュメントの <body> 要素に適用し、それに基づいてコンポーネントの外観を変更したいとします。

:host() の関数形式と同じように動作する :host-context() 擬似クラスセレクタを使用してください。

次の例では、コンポーネント内のすべての <h2> 要素に背景色のスタイルを適用します。これは、祖先要素のCSSクラス theme-light がある場合のみです。

rc/app/hero-details.component.css

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

/deep/

コンポーネントスタイルは、通常、コンポーネント独自のテンプレート内のHTMLにのみ適用されます。

/deep/ セレクタを使用して、子コンポーネントツリーを経由してすべての子コンポーネントビューにスタイルを強制的に適用します。/deep/ セレクタは、ネストされたコンポーネントの深さに作用し、コンポーネントの子ビューとコンテンツ子の両方に適用されます。

次の例では、すべての <h3> 要素を対象としています。ホスト要素からこのコンポーネントを経由してDOM内のすべての子要素に至ります。

src/app/hero-details.component.css

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

/deep/ セレクタには別名 >>> があります。どちらも使用することができます。

/deep/ および >>> セレクタは、エミュレートされたビューカプセル化でのみ使用してください。
Emulatedは、デフォルトで適用されており、最も一般的に使われるビューカプセル化のアプローチです。
詳細は、「Controlling view encapsulation」セクションを参照してください。

コンポーネントスタイルのローディング

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

  • stylesまたはstyleUrlsメタデータを設定します。
  • テンプレートHTMLのインライン
  • CSSのインポート

先に解説した有効範囲規則は、これらのロードパターンのそれぞれに適用されます。

メタデータ内でのスタイル

@Component デコレータに styles 配列プロパティを追加できます。配列内の各文字列(通常は1文字列)はCSSを定義します。

src/app/hero-app.component.ts

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

メタデータ内での URL スタイル

コンポーネントの @Component デコレータに styleUrls 属性を追加すると、外部CSSファイルからスタイルをロードできます。

src/app/hero-details.component.ts

@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']
})
export class HeroDetailsComponent {
/* . . . */
}

URLはアプリケーションルートからの相対パスです。通常、アプリケーションをホストする index.html Webページの場所です。スタイルファイルのURLはコンポーネントファイルとは関係ありません。
そのため、例のURLは src/app/ で始まります。コンポーネントファイルに関連するURLを指定するには、Appendix 2 を参照してください。

Webpackのようなモジュールバンドルを使用する場合、ビルド時にスタイル属性を使用して外部ファイルからスタイルをロードすることもできます。あなたは書くことができます:

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

styleUrls プロパティではなく、styles プロパティを設定します。モジュールバンドラーはAngularではなくCSS文字列を読み込みます。 Angular は、バンドルラーがロードした後にのみCSS文字列を表示します。
Angularからは、あなたが手でスタイル配列を書いたかのようです。この方法でCSSをロードする方法については、モジュールバンドラーのドキュメントを参照してください。

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

スタイルをHTMLテンプレートに直接埋め込むには、スタイルを <style> タグの中に入れます。

src/app/hero-controls.component.ts

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

テンプレートリンクタグ

<link> タグをコンポーネントの HTML テンプレートに埋め込むこともできます。
styleUrls と同様に、リンクタグの href URL はコンポーネントファイルではなく、アプリケーションのルートからの相対パスです。

src/app/hero-team.component.ts

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

CSS @imports

また、標準CSS @import ルールを使用して CSS ファイルを CSS ファイルにインポートすることもできます。詳細は、MDNサイトの @import を参照してください。

src/app/hero-details.component.css (抜粋)

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

View encapsulation(カプセル化表示)

前に説明したように、コンポーネントのCSSスタイルはコンポーネントのビューにカプセル化され、アプリケーションの残りの部分には影響しません。

このカプセル化がコンポーネントごとにどのように行われるかを制御するには、コンポーネントのメタデータにビューのカプセル化モードを設定します。次のモードから選択してください。

  • Native ... ブラウザのネイティブシャドウDOM実装(MDNサイトのシャドウDOMを参照)を使用して、シャドウDOMをコンポーネントのホスト要素にアタッチし、そのシャドウDOM内にコンポーネントビューを配置します。
  • Emulated(デフォルト) ... CSSのコードを効果的にスコープしてコンポーネントのビューに適用するために、CSSコードを前処理(および名前変更)することによって、シャドーDOMの動作をエミュレートします。詳細は、Appendix 1を参照してください。
  • None ... Angularがカプセル化を表示しないことを意味します。Angularは、CSSをグローバルスタイルに追加します。

コンポーネントのカプセル化モードを設定するには、コンポーネントメタデータのencapsulation プロパティを使用します。

src/app/quest-summary.component.ts

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

Native ビューのカプセル化は、シャドウ DOM をネイティブにサポートしているブラウザでのみ機能します(Can I useサイトの Shadow DOM v0 で確認してください)。

Appendix 1: 生成されたCSSの検証

エミュレートされたビューカプセル化を使用する場合、Angularはすべてのコンポーネントスタイルを前処理して、標準的なシャドウCSSスコープ規則に近似させます。

エミュレートされたビューのカプセル化が有効になっている実行中のAngularアプリケーションのDOMでは、各DOM要素にはいくつかの特別な属性が付加されます。

<hero-details _nghost-pmm-5>
  <h2 _ngcontent-pmm-5>Mister Fantastic</h2>
  <hero-team _ngcontent-pmm-5 _nghost-pmm-6>
    <h3 _ngcontent-pmm-6>Team</h3>
  </hero-team>
</hero-detail>

生成される属性には2種類あります。

  • ネイティブカプセル化でシャドウDOMホストとなる要素には、生成された _nghost 属性があります。これは通常、コンポーネントのホスト要素の場合です。
  • コンポーネントのビュー内の要素には、この要素がどのホストのエミュレートされたシャドウDOMに属するかを識別する _ngcontent 属性があります。

これらの属性の正確な値は重要ではありません。この値は自動的に生成するため、アプリケーションコードで参照することはありません。
しかし、生成されたコンポーネントスタイルは、DOMの <head> セクションにあります。

[_nghost-pmm-5] {
  display: block;
  border: 1px solid black;
}

h3[_ngcontent-pmm-6] {
  background-color: white;
  border: 1px solid #777;
}

これらのスタイルは後処理され、各セレクターに _nghost または _ngcontent 属性セレクターが付加されます。これらの自動付加されたセレクタにより、このページで説明する有効範囲規則が有効になります。

Appendix: 相対URLによる読み込み

コンポーネントのコード、HTML、CSS は、同じディレクトリ内で3つの別々のファイルに分割するのが一般的な方法です:

quest-summary.component.ts
quest-summary.component.html
quest-summary.component.css

templateUrl および styleUrls メタデータプロパティをそれぞれ設定することによって、テンプレートファイルと CSS ファイルをインクルードできます。
これらのファイルはコンポーネントと同じ場所に配置されているため、アプリケーションのルートに戻るパスを指定する必要もなく、名前で参照することもできます。

ファイル名の先頭に ./: という相対URLを使用することができます:

src/app/quest-summary.component.ts

@Component({
  selector: 'quest-summary',
  templateUrl: './quest-summary.component.html',
  styleUrls:  ['./quest-summary.component.css']
})
export class QuestSummaryComponent { }