352

我有一个父组件:

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

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

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

.parent .child {
  // Styles for child
}

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

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

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

但这并没有帮助,还尝试通过将child样式表获取到其他方式,parent但这也无济于事。

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

4

20 回答 20

306

更新 - 最新方式

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

最后更新

Angular 4.3.0到现在(Angular 12.x),所有穿孔的 css 组合器都被弃用了。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>      
`
于 2016-04-10T10:50:23.313 回答
108

您不应该使用::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 放在此标签“内部”:

模板:

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

.scs 文件:

.my-component {
  // All your css goes in there in order not to be global
}
于 2018-05-03T16:37:37.810 回答
61

更新 3:

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

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

更新 2:

由于/deep/和所有其他阴影穿透选择器现在已弃用。Angular 放弃了::ng-deep,应该使用它来实现更广泛的兼容性。

更新:

如果使用 Angular-CLI,则需要使用/deep/>>>否则它将不起作用。

原来的:

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

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

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

所以简单地做:

:host >>> .child {}

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

于 2016-04-10T08:55:21.853 回答
21

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

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

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

或者如果您有特定的样式,您可以使用类似的东西:
<div [style.background-color]="colorvar">

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

于 2017-04-13T19:59:32.797 回答
16

有同样的问题,所以如果你使用 angular2-cli 和 scss/sass 使用 '/deep/' 而不是 '>>>',最后一个选择器还不支持(但适用于 css)。

于 2016-10-15T12:03:43.533 回答
15

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

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

从技术上讲,可以这样做:

// 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>宿主元素来从外部触发这些样式。

于 2018-09-27T15:33:18.883 回答
13

如果您希望比实际的子组件更有针对性,那么您应该执行以下操作。这样,如果其他子组件共享相同的类名,它们就不会受到影响。

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

例如:

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

希望这可以帮助!

代码矩阵

于 2017-04-17T03:42:18.043 回答
12

其实还有一种选择。这是相当安全的。您可以使用 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() { }
}
于 2019-01-31T13:19:44.917 回答
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() {

   }
 }
于 2017-08-12T09:39:23.077 回答
6

如果您可以访问子组件代码,我发现传递 @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>
于 2017-10-05T20:59:38.627 回答
6

由于 /deep/、>>> 和 ::ng-deep 都已弃用。最好的方法是在您的子组件样式中使用以下内容

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

这将在您的子组件的任何祖先中查找主题灯。请参阅此处的文档:https ://angular.io/guide/component-styles#host-context

于 2020-10-09T07:58:15.063 回答
5

截至今天(Angular 9),Angular 使用Shadow DOM将组件显示为自定义 HTML 元素。为这些自定义元素设置样式的一种优雅方式可能是使用自定义 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 应用程序中,这可能类似于:

父组件.scss

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

子元素.component.scss

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

.wrapper {
  width: 100px;
  height: 100px;
  background-color: var(--background-clr);
  border: 1px solid red;
}
于 2020-05-29T20:02:49.820 回答
1

快速的回答是你根本不应该这样做。它破坏了组件封装并破坏了您从独立组件中获得的好处。考虑将 prop 标志传递给子组件,然后它可以自行决定如何以不同方式呈现或在必要时应用不同的 CSS。

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

Angular 正在弃用所有影响父母子女风格的方式。

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

于 2018-03-01T10:50:47.323 回答
1

我也有这个问题,不想使用不推荐使用的解决方案,所以我最终得到:

在父母

 <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);
  }

像预期的那样工作,不应该被弃用;)

于 2019-04-03T11:54:15.653 回答
1

为了在子组件中分配元素的类,您可以简单地在子组件中使用@Input字符串并将其用作模板内的表达式。下面是我们在共享 Bootstrap 加载按钮组件中更改图标和按钮类型的示例,而不会影响它在整个代码库中的使用方式:

app-loading-button.component.html (子)

<button class="btn {{additionalClasses}}">...</button>

应用程序加载按钮.component.ts

@Input() additionalClasses: string;

父.html

<app-loading-button additionalClasses="fa fa-download btn-secondary">...</app-loading-button>
于 2020-07-15T13:44:42.310 回答
1

我更喜欢实现以下目标:

用于@Component将 css 类添加到宿主元素并将封装设置为无。然后引用在组件中添加到主机的那个类。style.css.scss这将允许我们声明样式,这些样式只会影响我们类范围内的我们自己和我们的孩子。铁

@Component({
  selector: 'my-component',
  templateUrl: './my-component.page.html',
  styleUrls: ['./my-component.page.scss'],
  host: {
    class: 'my-component-class'
  },
  encapsulation: ViewEncapsulation.None
})

结合以下 css (my-component.page.scss)

// refer ourselves so we are allowed to overwrite children but not global styles
.my-component-class {
  // will effect direct h1 nodes within template and all h1 elements within child components of the 
  h1 {
    color: red;
  }
}
// without class "scope" will affect all h1 elements globally
h1 {
  color: blue;
}
于 2021-09-22T09:51:04.247 回答
0

随着互联网的更新,我遇到了一个解决方案。

首先是一些警告。

  1. 还是不要这样做。澄清一下,我不会计划允许您为它们设置样式的子组件。SOC。如果您作为组件设计师想要允许这样做,那么您将拥有更多的权力。
  2. 如果您的孩子不住在影子 dom 中,那么这对您不起作用。
  3. 如果您必须支持不能有 shadow dom 的浏览器,那么这对您也不起作用。

首先,将您的子组件的封装标记为阴影,以便它在实际的阴影 dom 中呈现。其次,将 part 属性添加到您希望允许父级设置样式的元素。在父组件样式表中,您可以使用 ::part() 方法来访问

于 2020-03-06T21:17:41.103 回答
-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;
}
于 2017-09-08T11:33:16.583 回答
-2

我已经在 Angular 之外解决了它。我已经定义了一个共享的 scss,我要导入我的孩子。

共享.scss

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

孩子.scss

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

我提出的方法是一种如何解决 OP 提出的问题的方法。正如在多个场合提到的,::ng-deep、:ng-host 将被贬低,在我看来,禁用封装只是太多的代码泄漏。

于 2019-08-05T10:19:04.020 回答
-2

让 'parent' 是 parent 的类名, 'child' 是 child 的类名

.parent .child{
//css definition for child inside parent components
} 

您可以使用此格式将 CSS 格式定义为“父”内的“子”组件

于 2020-08-15T08:42:04.840 回答