如何从父组件的 CSS 文件中设置子组件的样式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36527605/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 11:52:33  来源:igfitidea点击:

How to style child components from parent component's CSS file?

cssangularangular-components

提问by Chrillewoodz

I've got a parent component:

我有一个父组件:

<parent></parent>

And I want to populate this group with child components:

我想用子组件填充这个组:

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

Parent template:

父模板:

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

Child template:

子模板:

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

Since parentand childare two seperate components, their styles are locked to their own scope.

由于parentchild是两个独立的组件,它们的样式被锁定在它们自己的范围内。

In my parent component I tried doing:

在我的父组件中,我尝试做:

.parent .child {
  // Styles for child
}

But the .childstyles are not getting applied to the childcomponents.

但是.child样式并未应用于child组件。

I tried using styleUrlsto include the parent's stylesheet into childcomponent to solve the scope issue:

我尝试使用styleUrlsparent的样式表包含到child组件中来解决范围问题:

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

But that didn't help, also tried the other way by fetching the childstylesheet into parentbut that didn't help either.

但这没有帮助,还尝试了另一种方式,将child样式表提取到其中,parent但这也无济于事。

So how do you style child components that are included into a parent component?

那么如何为包含在父组件中的子组件设置样式呢?

采纳答案by micronyks

Update - Newest Way

更新 - 最新方式

Don't do it, if you can avoid it. As Devon Sans points out in the comments: This feature will most likely be deprecated.

如果可以避免,请不要这样做。正如 Devon Sans 在评论中指出的那样:此功能很可能会被弃用。

Update - Newer Way

更新 - 更新方式

From Angular 4.3.0, all piercing css combinartors were deprecated. Angular team introduced a new combinator ::ng-deep(still it is at experimental level and not the full and final way)as shown below,

Angular 4.3.0 开始,所有的 piercing css 组合器都被弃用了。Angular 团队引入了一个新的组合器::ng-deep(仍然处于实验级别,而不是完整的和最终的方式),如下所示,

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

演示: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>      
    `



Old way

老办法

You can use encapsulation modeand/or piercing CSS combinators >>>, /deep/ and ::shadow

您可以使用encapsulation mode和/或piercing CSS combinators >>>, /deep/ and ::shadow

working example : http://plnkr.co/edit/1RBDGQ?p=preview

工作示例: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>      
`

回答by Chrillewoodz

UPDATE 3:

更新 3:

::ng-deepis also deprecated which means you should not do this at all anymore. It is unclear how this affects things where you need to override styles in child components from a parent component. To me it seems odd if this gets removed completely because how would this affect things as libraries where you need to override styles in a library component?

::ng-deep也已弃用,这意味着您根本不应再这样做了。目前尚不清楚这如何影响您需要从父组件覆盖子组件中的样式的事情。对我来说,如果这被完全删除似乎很奇怪,因为这将如何影响作为需要覆盖库组件中样式的库的东西?

Comment if you have any insight in this.

如果您对此有任何见解,请发表评论。

UPDATE 2:

更新 2:

Since /deep/and all other shadow piercing selectors are now deprecated. Angular dropped ::ng-deepwhich should be used instead for a broader compatibility.

因为/deep/和所有其他阴影穿透选择器现在已弃用。Angular 已删除::ng-deep,应改为使用它以获得更广泛的兼容性。

UPDATE:

更新:

If using Angular-CLI you need to use /deep/instead of >>>or else it will not work.

如果使用 Angular-CLI,您需要使用/deep/而不是,>>>否则它将无法工作。

ORIGINAL:

原来的:

After going to Angular2's Github page and doing a random search for "style" I found this question: Angular 2 - innerHTML styling

在转到 Angular2 的 Github 页面并随机搜索“样式”后,我发现了这个问题:Angular 2 - innerHTML 样式

Which said to use something that was added in 2.0.0-beta.10, the >>>and ::shadowselectors.

其中说要使用在2.0.0-beta.10>>>::shadow选择器中添加的东西。

(>>>) (and the equivalent/deep/) and ::shadow were added in 2.0.0-beta.10. They are similar to the shadow DOM CSS combinators (which are deprecated) and only work with encapsulation: ViewEncapsulation.Emulated which is the default in Angular2. They probably also work with ViewEncapsulation.None but are then only ignored because they are not necessary. These combinators are only an intermediate solution until more advanced features for cross-component styling is supported.

(>>>)(以及等效的/deep/)和 ::shadow 是在 2.0.0-beta.10 中添加的。它们类似于 shadow DOM CSS 组合器(已弃用)并且仅适用于封装:ViewEncapsulation.Emulated,这是 Angular2 中的默认值。它们可能也与 ViewEncapsulation.None 一起使用,但随后只会被忽略,因为它们不是必需的。在支持跨组件样式的更高级功能之前,这些组合器只是一个中间解决方案。

So simply doing:

所以简单地做:

:host >>> .child {}

In parent's stylesheet file solved the issue. Please note, as stated in the quote above, this solution is only intermediate until more advanced cross-component styling is supported.

Inparent的样式表文件解决了这个问题。请注意,如上面引用所述,在支持更高级的跨组件样式之前,此解决方案只是中间的。

回答by Tonio

You should NOT use ::ng-deep, it is deprecated. In Angular, the proper way to change the style of children's component from the parent is to use encapsulation(read the warning below to understand the implications):

您不应该使用::ng-deep,它已被弃用。在 Angular 中,从父级更改子组件样式的正确方法是使用encapsulation(阅读下面的警告以了解其含义):

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

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

And then, you will be able to modify the css form your component without a need from ::ng-deep

然后,您将能够在不需要 ::ng-deep 的情况下修改组件的 css 表单

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

WARNING: Doing this will make all css rules you write for this component to be global.

警告:这样做将使您为此组件编写的所有 css 规则成为全局规则。

In order to limit the scope of your css to this component only, add a css class to the top tag of your component and put your css "inside" this tag:

为了将 css 的范围仅限于该组件,请在组件的顶部标签中添加一个 css 类,并将您的 css 放在此标签的“内部”:

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

Scss file:

.scss 文件:

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

回答by Matthew B.

Sadly it appears that the /deep/ selector is deprecated (at least in Chrome) https://www.chromestatus.com/features/6750456638341120

可悲的是,似乎 /deep/ 选择器已被弃用(至少在 Chrome 中) https://www.chromestatus.com/features/6750456638341120

In short it appears there is (currently) no long term solution other than to somehow get your child component to style things dynamically.

You could pass a style object to your child and have it applied via:
<div [attr.style]="styleobject">

Or if you have a specific style you can use something like:
<div [style.background-color]="colorvar">

简而言之,除了以某种方式让您的子组件动态设置样式之外,似乎(目前)没有长期解决方案。

您可以将样式对象传递给您的孩子并通过以下方式应用它:
<div [attr.style]="styleobject">

或者如果您有特定的样式,则可以使用以下内容:
<div [style.background-color]="colorvar">

More discussion related to this: https://github.com/angular/angular/issues/6511

与此相关的更多讨论:https: //github.com/angular/angular/issues/6511

回答by SergiySev

Had same issue, so if you're using angular2-cli with scss/sass use '/deep/' instead of '>>>', last selector isn't supported yet (but works great with css).

有同样的问题,所以如果你将 angular2-cli 与 scss/sass 一起使用,请使用“/deep/”而不是“>>>”,最后一个选择器尚不支持(但与 css 一起使用时效果很好)。

回答by code5

If you want to be more targeted to the actual child component than you should do the follow. This way, if other child components share the same class name, they won't be affected.

如果您想更加针对实际的子组件而不是您应该执行以下操作。这样,如果其他子组件共享相同的类名,它们就不会受到影响。

Plunker: https://plnkr.co/edit/ooBRp3ROk6fbWPuToytO?p=preview

Plunker:https://plnkr.co/edit/ooBRp3ROk6fbWPuToytO ?p =preview

For example:

例如:

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 {}

Hope this helps!

希望这可以帮助!

codematrix

代码矩阵

回答by ilius33

Actually there is one more option. Which is rather safe. You can use ViewEncapsulation.None BUT put all your component styles into its tag (aka selector). But anyway always prefer some global style plus encapsulated styles.

其实还有一种选择。这是比较安全的。您可以使用 ViewEncapsulation.None 但将所有组件样式放入其标记(又名选择器)中。但无论如何总是更喜欢一些全局样式加上封装样式。

Here is modified Denis Rybalka example:

这是修改后的 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() { }
}

回答by Alexander Abakumov

You should not write CSS rules for a child component elements in a parent component, since an Angular component is a self-contained entity which should explicitly declare what is available for the outside world. If child layout changes in the future, your styles for that child component elements scattered across other components' SCSS files could easily break, thus making your styling very fragile. That's what ViewEncapsulationis for in the case of CSS. Otherwise, it would be the same if you could assign values to private fields of some class from any other class in Object Oriented Programming.

你不应该为父组件中的子组件元素编写 CSS 规则,因为 Angular 组件是一个独立的实体,它应该明确声明外部世界可用的内容。如果将来子布局发生变化,那么分散在其他组件的 SCSS 文件中的子组件元素的样式很容易被破坏,从而使您的样式变得非常脆弱。这ViewEncapsulation就是 CSS 的用途。否则,如果您可以将值分配给面向对象编程中任何其他类的某个类的私有字段,那将是相同的。

Therefore, what you should do is to define a set of classes you could apply to the child host element and implement how the child responds to them.

因此,您应该做的是定义一组可以应用于子宿主元素的类,并实现子元素如何响应它们。

Technically, it could be done as follows:

从技术上讲,可以按如下方式完成:

// 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>

In other words, you use :hostpseudo-selector provided by Angular + set of CSS classes to define possible child styles in child component itself. You then have the ability to trigger those styles from outside by applying pre-defined classes to the <child>host element.

换句话说,您使用:hostAngular 提供的伪选择器 + 一组 CSS 类来定义子组件本身中可能的子样式。然后,您可以通过将预定义的类应用于<child>宿主元素来从外部触发这些样式。

回答by Denis Rybalka

There are a few options to achieve this in Angular:

在 Angular 中有几个选项可以实现这一点:

1) You can use deep css selectors

1) 您可以使用深 css 选择器

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

2) You can also change view encapsulation it's set to Emulated as a default but can be easily changed to Native which uses Shadow DOM native browser implementation, in your case you just need to disable it

2) 您还可以更改视图封装,它默认设置为 Emulated,但可以轻松更改为使用 Shadow DOM 本机浏览器实现的 Native,在您的情况下,您只需要禁用它

For example:`

例如:`

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() {

   }
 }

回答by robert king

I find it a lot cleaner to pass an @INPUT variableif you have access to the child component code:

如果您可以访问子组件代码,我发现传递 @INPUT 变量会更清晰

The idea is that the parent tells the child what its state of appearance should be, and the child decides how to display the state. It's a nice architecture

这个想法是父母告诉孩子它的外观状态应该是什么,孩子决定如何显示状态。这是一个不错的架构

SCSS Way:

SCSS方式:

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

Better way:- use selectedvariable:

更好的方法:- 使用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>