親コンポーネントのCSSファイルから子コンポーネントをスタイルする方法


266

親コンポーネントがあります:

<parent></parent>

そして、私はこのグループに子コンポーネントを入れたいです:

<parent>
  <child></child>
  <child></child>
  <child></child>
</parent>

親テンプレート:

<div class="parent">
  <!-- Children goes here -->
  <ng-content></ng-content>
</div>

子テンプレート:

<div class="child">Test</div>

以来parentchild2つの別々のコンポーネントである、彼らのスタイルは、独自のスコープにロックされています。

私の親コンポーネントで私はやってみました:

.parent .child {
  // Styles for child
}

しかし、.childスタイルはchildコンポーネントに適用されていません。

を使用styleUrlsして、スコープの問題を解決するためparentchildコンポーネントにスタイルシートを含めようとしました:

// child.component.ts
styleUrls: [
  './parent.component.css',
  './child.component.css',
]

しかし、それは助けにはなりませんでした。childスタイルシートをにフェッチすることで別の方法を試しましたが、それも助けにparentはなりませんでした。

では、親コンポーネントに含まれている子コンポーネントをどのようにスタイルするのでしょうか。



パラダイムに完全に対応し、トリックを使わない方法を私の回答で参照してください。
Alexander Abakumov

回答:


242

更新-最新の方法

あなたがそれを避けることができるなら、それをしないでください。Devon Sansがコメントで指摘しているように:この機能はおそらく非推奨になるでしょう。

更新-新しい方法

より 角度4.3.0、すべてのピアスのCSS combinartorsは廃止されました。Angularチームは、以下に示すように、新しいコンビネーターを導入しました::ng-deep (まだ完全な最終的な方法ではなく、実験的なレベルです)

デモ:https : //plnkr.co/edit/RBJIszu14o4svHLQt563? p =preview

styles: [
    `
     :host { color: red; }

     :host ::ng-deep parent {
       color:blue;
     }
     :host ::ng-deep child{
       color:orange;
     }
     :host ::ng-deep child.class1 {
       color:yellow;
     }
     :host ::ng-deep child.class2{
       color:pink;
     }
    `
],



template: `
      Angular2                                //red
      <parent>                                //blue
          <child></child>                     //orange
          <child class="class1"></child>      //yellow
          <child class="class2"></child>      //pink
      </parent>      
    `


古い方法

あなたが使用することができencapsulation mode、および/またはpiercing CSS combinators >>>, /deep/ and ::shadow

作業例:http : //plnkr.co/edit/1RBDGQ?p=preview

styles: [
    `
     :host { color: red; }
     :host >>> parent {
       color:blue;
     }
     :host >>> child{
       color:orange;
     }
     :host >>> child.class1 {
       color:yellow;
     }
     :host >>> child.class2{
       color:pink;
     }
    `
    ],

template: `
  Angular2                                //red
  <parent>                                //blue
      <child></child>                     //orange
      <child class="class1"></child>      //yellow
      <child class="class2"></child>      //pink
  </parent>      
`

3
ただし、ピアシングCSSコンビネータはChromeでは非推奨です
Robin-Hoodie 2017年

22
角度のあるチームは、:: ng-deepのサポートも削除する予定です。彼らのドキュメントから:「シャドウピアス子孫コンビネーターは非推奨になり、主要なブラウザーとツールからサポートが削除されています。そのため、Angular(/ deep /、>>>および:: ng-の3つすべて)のサポートを終了する予定です。それまでは、ツールとの互換性を高めるために、:: ng-deepをお勧めします。 " angular.io/guide/component-styles#deprecated-deep--and-ng-deep
デボンサムス

5
これが受け入れられる回答である限り、人々は誤解を招くでしょう。:: ng-deepは、上記のコメントの@DevonSamsポイントとして使用しないでください。
Kostas Siabanis

1
::ng-deepは非推奨になりました。今後のアプリケーションでの使用はお勧めしません
Wilt

11
代替手段を提供せずに何かを廃止することは、おそらく最良の解決策ではありません。
tehlivi

56

更新3:

::ng-deepも廃止予定です。つまり、これを行う必要はもうありません。親コンポーネントから子コンポーネントのスタイルをオーバーライドする必要がある場合、これがどのように影響するかは不明です。ライブラリコンポーネントのスタイルをオーバーライドする必要があるライブラリのようなものにどのように影響するので、これが完全に削除されると私には奇妙に思えますか?

これについて何か洞察があればコメントしてください。

更新2:

以降/deep/、他のすべてのシャドウピアシングセレクタは非推奨になりました。Angular Dropは::ng-deep、より広い互換性のために代わりに使用する必要があります。

更新:

Angular-CLIを使用する場合は、/deep/代わりに使用する必要があります>>>。そうしないと機能しません。

元の:

Angular2のGithubページに行き、「スタイル」をランダムに検索した後、私はこの質問を見つけました: Angular 2-innerHTML styling

これは2.0.0-beta.10>>>::shadowセレクターで追加されたものを使用すると言われています。

(>>>)(および同等の/ deep /)と:: shadowが2.0.0-beta.10で追加されました。これらはシャドウDOM CSSコンビネーター(非推奨)に似ており、カプセル化でのみ機能します:Angular2のデフォルトであるViewEncapsulation.Emulated。これらはおそらくViewEncapsulation.Noneでも機能しますが、必要がないため無視されるだけです。これらのコンビネータは、クロスコンポーネントスタイリングのより高度な機能がサポートされるまでの中間的なソリューションにすぎません。

だから単純に:

:host >>> .child {}

parentスタイルシートファイルの問題を解決しました。上記の引用で述べたように、このソリューションは、より高度なクロスコンポーネントスタイリングがサポートされるまでの中間的なものです。



42

は使用しないでください::ng-deep。非推奨です。Angularでは、子のコンポーネントのスタイルを親から変更する適切な方法を使用することですencapsulation(影響を理解するには以下の警告を読んでください):

import { ViewEncapsulation } from '@angular/core';

@Component({
    ....
    encapsulation: ViewEncapsulation.None
})

そして、あなたは:: ng-deepからの必要なしにコンポーネントからCSSを変更することができます

.mat-sort-header-container {
  display:flex;
  justify-content:center;
}

警告:これを行うと、このコンポーネントに対して作成するすべてのcssルールがグローバルになります。

CSSのスコープをこのコンポーネントのみに制限するには、CSSクラスをコンポーネントの一番上のタグに追加し、CSSをこのタグの「内側」に配置します。

template:
    <div class='my-component'>
      <child-component class="first">First</child>
    </div>,

Scssファイル:

.my-component {
  // All your css goes in there in order not to be global
}

3
これはIMOのベストアンサーです。これは、間もなくサポートが終了する予定の代替手段として実際に使用できるためです::ng-deep。一般に、コンポーネントには独自のセレクター(<my-component>, <div my-component>など)があるため、特別なクラスを持つラッパー要素は必要ありません。
アレックスウォーカー

@AlexWalkerこれがための最良の答えかもしれないあなたの状況が、価値はそれだけafaict OPの質問の半分に答えることを言及する:この方法では、CSSは、上から下に、通常のように伝播することができます、しかし、離れALLカプセル化を投げるのおかげで、doesnのそのスタイリングを特定の親の子供に限定しないでください。parent1の子を1つの方法でスタイルし、parent2の子を別の方法でスタイルすると、これらのCSSルールは両方の場所で互いに戦うことになります。これは非常に手間がかかる場合があります(それを回避するためにAngularがカプセル化を追加しました)。
ルフィン

@ruffinそのため、この手法を使用することの意味と、コンポーネントの上部のcssタグを使用して「手動でカプセル化」する方法を理解するために、回答に警告を追加しました
Tonio

1
@Tonio-はい、同意しました。あなたではなくアレックスに直接返信していました。彼のコメントは、「特別なクラスを持つラッパー要素の必要さえない」と私は少し怖がっていました。たぶん特定の状況のためかもしれませんが、Angularがカプセル化をサポートするのに理由があるのには理由があります。この答えは特定の場合に実行可能な解決策ですが、あなたが言うように、一般に潜在的に危険なものです。たとえば、MatthewBのソリューションは、カプセル化を維持しながら子のスタイルを設定します(ただし、子コンポーネントの世代が複数ある場合は、非常に複雑になります)。
ルフィン

19

悲しいことに、/ deep /セレクターは廃止されたようです(少なくともChromeでは) https://www.chromestatus.com/features/6750456638341120

つまり、子コンポーネントに動的にスタイルを設定させる以外に、(現在のところ)長期的な解決策はないようです。

あなたはあなたの子供にスタイルオブジェクトを渡してそれを介してそれを適用させることができます:
<div [attr.style]="styleobject">

またはあなたが特定のスタイルを持っているならあなたは次のようなものを使うことができます:
<div [style.background-color]="colorvar">

これに関連する詳細な議論:https : //github.com/angular/angular/issues/6511


16

同じ問題があったため、scss / sassでangular2-cliを使用していて、 '>>>'ではなく '/ deep /'を使用している場合、最後のセレクターはまだサポートされていません(ただし、cssでうまく機能します)。


11

実際の子コンポーネントをよりターゲットにしたい場合は、以下を実行する必要があります。このようにして、他の子コンポーネントが同じクラス名を共有する場合、それらは影響を受けません。

プランカー: https

例えば:

import {Component, NgModule } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>I'm the host parent</h2>
      <child-component class="target1"></child-component><br/>
      <child-component class="target2"></child-component><br/>
      <child-component class="target3"></child-component><br/>
      <child-component class="target4"></child-component><br/>
      <child-component></child-component><br/>
    </div>
  `,
  styles: [`

  /deep/ child-component.target1 .child-box {
      color: red !important; 
      border: 10px solid red !important;
  }  

  /deep/ child-component.target2 .child-box {
      color: purple !important; 
      border: 10px solid purple !important;
  }  

  /deep/ child-component.target3 .child-box {
      color: orange !important; 
      border: 10px solid orange !important;
  }  

  /* this won't work because the target component is spelled incorrectly */
  /deep/ xxxxchild-component.target4 .child-box {
      color: orange !important; 
      border: 10px solid orange !important;
  }  

  /* this will affect any component that has a class name called .child-box */
  /deep/ .child-box {
      color: blue !important; 
      border: 10px solid blue !important;
  }  


  `]
})
export class App {
}

@Component({
  selector: 'child-component',
  template: `
    <div class="child-box">
      Child: This is some text in a box
    </div>
  `,
  styles: [`
    .child-box {
      color: green;    
      border: 1px solid green;
    }
  `]
})
export class ChildComponent {
}


@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ChildComponent ],
  bootstrap: [ App ]
})
export class AppModule {}

お役に立てれば!

codematrix


9

実際にはもう1つのオプションがあります。これはどちらかと言えば安全です。ViewEncapsulation.Noneを使用できますが、すべてのコンポーネントスタイルをタグ(セレクタ)に挿入できます。しかしとにかく、常にいくつかのグローバルスタイルとカプセル化されたスタイルを好む。

修正されたDenis Rybalkaの例を次に示します。

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'parent',
  styles: [`
    parent {
      .first {
        color:blue;
      }
      .second {
        color:red;
      }
    }
 `],
 template: `
    <div>
      <child class="first">First</child>
      <child class="second">Second</child>
    </div>`,
  encapsulation: ViewEncapsulation.None,
})
export class ParentComponent  {
  constructor() { }
}

7

Angularでこれを達成するためのいくつかのオプションがあります:

1)ディープCSSセレクターを使用できます

:host >>> .childrens {
     color: red;
 }

2)デフォルトでEmulatedに設定されているビューのカプセル化を変更することもできますが、無効にする必要がある場合は、Shadow DOMネイティブブラウザ実装を使用するNativeに簡単に変更できます。

例: `

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'parent',
  styles: [`
    .first {
      color:blue;
    }
    .second {
      color:red;
    }
 `],
 template: `
    <div>
      <child class="first">First</child>
      <child class="second">Second</child>
    </div>`,
  encapsulation: ViewEncapsulation.None,
 })
 export class ParentComponent  {
   constructor() {

   }
 }

3
実際には、スタイルは子要素だけでなく、dom全体に影響することを意味します。
Kasper Ziemianek、2018年

7

Angularコンポーネントは自己完結型のエンティティであり、外部で利用できるものを明示的に宣言する必要があるため、親コンポーネントの子コンポーネント要素のCSSルールを記述しないでください。将来、子のレイアウトが変更されると、他のコンポーネントのSCSSファイルに散らばっているその子コンポーネント要素のスタイルが簡単に壊れて、スタイルが非常に壊れやすくなる可能性があります。それViewEncapsulationがCSSの場合です。それ以外の場合、オブジェクト指向プログラミングの他のクラスから、あるクラスのプライベートフィールドに値を割り当てることができれば、同じです。

したがって、実行する必要があるのは、子ホスト要素に適用できるクラスのセットを定義し、子がそれらに応答する方法を実装することです。

技術的には、次のように行うことができます。

// child.component.html:
<span class="label-1"></span>

// child.component.scss:
:host.child-color-black {
    .label-1 {
        color: black;
    }
}

:host.child-color-blue {
    .label-1 {
        color: blue ;
    }
}

// parent.component.html:
<child class="child-color-black"></child>
<child class="child-color-blue"></child>

つまり、:hostAngularが提供する疑似セレクタ+ CSSクラスのセットを使用して、子コンポーネント自体で可能な子スタイルを定義します。その後、定義済みのクラスを<child>ホスト要素に適用することにより、これらのスタイルを外部からトリガーすることができます。


良い解決策のようですが、parent.component.scssファイルはありますか?はいの場合、それを与えてもいいですか?
Manohar Reddy Poreddy 2018

@ManoharReddyPoreddy parent.component.scss子コンポーネントのスタイリングに関連するスタイリングがあってはなりません。それがこのアプローチの唯一の目的です。なぜ必要なのparent.component.scssですか?
Alexander Abakumov

わからない、ちょっとCSSを知っているだけ。jsbinなどで完全なソリューションを共有できますか?あなたのソリューションは、誰にとっても将来のソリューションになる可能性があります。
Manohar Reddy Poreddy 2018

2
@ManoharReddyPoreddy最初にこれらのコードを実際に試すことをお勧めします。次に、問題が発生した場合は、私が回答できる特定の質問や、特定のトピックを調べて問題の修正方法を理解するためのアドバイスが得られます。私が言及したViewEncapsulationそのデフォルト値はOPの質問につながるものですという理由だけで。ViewEncapsulation上記のコードを機能させるために別のものを割り当てる必要はありません。
Alexander Abakumov

1
+1ありがとうございます。将来このソリューションを採用するために戻ってきます。今日は:: ng-deep stackoverflow.com/a/36528769/984471で解決します。
Manohar Reddy Poreddy 2018

5

@INPUT変数を渡す方がずっときれいだと思います子コンポーネントのコードにアクセスできる場合はです。

アイデアは、親が子にその外観の状態をどのようにすべきかを伝え、子が状態の表示方法を決定するというものです。それは素晴らしいアーキテクチャです

SCSSウェイ:

.active {
  ::ng-deep md-list-item {
    background-color: #eee;
  }
}

より良い方法: - selected変数を使用:

<md-list>
    <a
            *ngFor="let convo of conversations"
            routerLink="/conversations/{{convo.id}}/messages"
            #rla="routerLinkActive"
            routerLinkActive="active">
        <app-conversation
                [selected]="rla.isActive"
                [convo]="convo"></app-conversation>
    </a>
</md-list>

2
また、特に再帰的なコンポーネントの場合、保守が困難です。
エリックフィリップス

2

今日(Angular 9)の時点で、AngularはShadow DOMを使用してコンポーネントをカスタムHTML要素として表示します。これらのカスタム要素をスタイルする1つのエレガントな方法は、カスタムCSS変数を使用することです。以下に一般的な例を示します。

class ChildElement extends HTMLElement {
  constructor() {
    super();
    
    var shadow = this.attachShadow({mode: 'open'});
    var wrapper = document.createElement('div');
    wrapper.setAttribute('class', 'wrapper');
    
    // Create some CSS to apply to the shadow dom
    var style = document.createElement('style');
    
    style.textContent = `
    
      /* Here we define the default value for the variable --background-clr */
      :host {
        --background-clr: green;
      }
      
      .wrapper {
        width: 100px;
        height: 100px;
        background-color: var(--background-clr);
        border: 1px solid red;
      }
    `;
    
    shadow.appendChild(style);
    shadow.appendChild(wrapper);
  }
}

// Define the new element
customElements.define('child-element', ChildElement);
/* CSS CODE */

/* This element is referred as :host from the point of view of the custom element. Commenting out this CSS will result in the background to be green, as defined in the custom element */

child-element {
  --background-clr: yellow; 
}
<div>
  <child-element></child-element>
</div>

上記のコードからわかるように、Angularがすべてのコンポーネントで行うようにカスタム要素を作成し、グローバルスコープから、カスタム要素のシャドウルート内の背景色を担当する変数をオーバーライドします。

Angularアプリでは、これは次のようになります。

parent.component.scss

child-element {
  --background-clr: yellow;
}

child-element.component.scss

:host {
  --background-clr: green;
}

.wrapper {
  width: 100px;
  height: 100px;
  background-color: var(--background-clr);
  border: 1px solid red;
}

0

簡単に言えば、これを行うべきではありません。コンポーネントのカプセル化を壊し、自己完結型コンポーネントから得られる利点を損ないます。子コンポーネントにpropフラグを渡すことを検討すると、必要に応じて、レンダリング方法やCSSの適用方法を決定できます。

<parent>
  <child [foo]="bar"></child>
</parent>

Angularは、親からの子スタイルに影響を与えるすべての方法を廃止しています。

https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep


まあ彼らはドキュメントで最終的にそれをやっていることを明示的に言った、私は彼らがそうすることを意味すると思います。私は同意しますが、すぐには起こりません。
ジェイドリチャーズ

そのため、彼らは独自のマテリアルライブラリをほとんど役に立たないものにします。各顧客が独自のデザインを必要としているため、どのライブラリーでもデフォルトのテーマを使用できませんでした。通常は、コンポーネントの機能が必要なだけです。この決定の背後にある彼らの全体的な論理を理解しているとは言えません。
Chrillewoodz

0

私にもこの問題があり、非推奨のソリューションを使用したくなかったので、次のようになりました。

親権で

 <dynamic-table
  ContainerCustomStyle='width: 400px;'
  >
 </dynamic-Table>

子コンポーネント

@Input() ContainerCustomStyle: string;

html divの子

 <div class="container mat-elevation-z8"
 [style]='GetStyle(ContainerCustomStyle)' >

そしてコードで

constructor(private sanitizer: DomSanitizer) {  }

  GetStyle(c) {
    if (isNullOrUndefined(c)) { return null; }
    return  this.sanitizer.bypassSecurityTrustStyle(c);
  }

期待どおりに動作し、廃止すべきではありません;)


面白い!私は(今のところ)似たようなものになりました。DomSanitizerはどこから入手しますか?編集:見つけました:angular.io/api/platform-b​​rowser/DomSanitizer
Zaphoid

はい、v7ではネイティブです。コンストラクターでの注入を要求する必要があります。;)、古い
バージョン

0

インターネットの更新として、私は解決策を見つけました。

最初にいくつかの注意点があります。

  1. まだそれをしないでください。明確にするために、子コンポーネントをスタイル設定できるようにするつもりはありません。SOC。コンポーネントデザイナーとしてこれを許可したい場合は、さらに強力です。
  2. あなたの子供が影のドームに住んでいない場合、これはあなたのために機能しません。
  3. シャドウDOMを使用できないブラウザをサポートする必要がある場合、これも機能しません。

まず、子コンポーネントのカプセル化をシャドウとしてマークし、実際のシャドウdomでレンダリングするようにします。次に、親がスタイルを設定できるようにする要素にpart属性を追加します。親のコンポーネントスタイルシートでは、:: part()メソッドを使用して


-1

angular.io/guide/component-stylesは次のように述べているので、より明確にするための例を提案します。

シャドウピアシングの子孫コンビネーターは非推奨となり、主要なブラウザーとツールからサポートが削除されます。そのため、Angularでサポートを終了する予定です(/ deep /、>>>、:: ng-deepの3つすべて)。それまでは、ツールとの互換性を高めるために:: ng-deepをお勧めします。

app.component.scss*.scss必要に応じてをインポートします。_colors.scssいくつかの一般的なカラー値があります:

$button_ripple_red: #A41E34;
$button_ripple_white_text: #FFF;

すべてのコンポーネントにルールを適用する

btn-redクラスを持つすべてのボタンがスタイルされます。

@import `./theme/sass/_colors`;

// red background and white text
:host /deep/ button.red-btn {
    color: $button_ripple_white_text;
    background: $button_ripple_red;
}

単一のコンポーネントにルールを適用する

コンポーネントにbtn-redクラスを持つすべてのボタンapp-loginがスタイル設定されます。

@import `./theme/sass/_colors`;

/deep/ app-login button.red-btn {
    color: $button_ripple_white_text;
    background: $button_ripple_red;
}

-1

Angularの外で解決しました。私は自分の子供にインポートする共有scssを定義しました。

shared.scss

%cell {
  color: #333333;
  background: #eee;
  font-size: 13px;
  font-weight: 600;
}

child.scss

@import 'styles.scss';
.cell {
  @extend %cell;
}

私が提案するアプローチは、OPが尋ねた問題を解決する方法です。複数の場面で言及されているように、:: ng-deep、:ng-hostは廃止され、カプセル化の無効化はコードリークの多すぎると私は考えています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.