如何样式子组件从父组件's CSS文件?

我有一个父组件:

<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的样式表包含到child组件中,以解决范围问题:

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

但这并没有帮助,我也尝试了另一种方式,将child样式表提取到parent中,但这也没有帮助。

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

350194 次浏览

更新3:

::ng-deep也已弃用,这意味着你不应该再这样做了。当你需要从父组件重写子组件的样式时,不清楚这会如何影响这些事情。对我来说,如果这被完全删除,这似乎很奇怪,因为这将如何影响你需要在库组件中覆盖样式的库?

如果你对此有任何见解,请评论。

更新2:

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

更新:

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

原:

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

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

(>>>)(和等价的/deep/)和::shadow在2.0.0-beta.10中添加。它们类似于shadow DOM CSS组合子(已弃用),并且只适用于封装:ViewEncapsulation。在Angular2中是默认的。它们也可能与ViewEncapsulation一起工作。没有but,然后只是忽略,因为他们是不必要的。在支持更高级的跨组件样式化特性之前,这些组合子只是一种中间解决方案。

所以简单地做:

:host >>> .child {}

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

更新-最新方式

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

最后一次更新

安装角4.3.0到现在(Angular 12.x),所有穿孔的css组合子都已弃用。Angular团队引入了一个新的组合子::ng-deep,如下所示:

DEMO: https://plnkr.co/edit/RBJIszu14o4svHLQt563?p =预览< / >

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

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

遗憾的是/deep/选择器已弃用(至少在Chrome中) https://www.chromestatus.com/features/6750456638341120 < / p > 简而言之,除了以某种方式让你的子组件动态地设置样式之外,似乎(目前)没有长期的解决方案。 你可以将一个样式对象传递给你的子对象,并通过
应用它 <div [attr.style]="styleobject">

或者如果你有一个特定的风格,你可以使用类似于:
<div [style.background-color]="colorvar"> < / p >

更多相关的讨论: https://github.com/angular/angular/issues/6511 < / p >

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

< p >砰砰作响: https://plnkr.co/edit/ooBRp3ROk6fbWPuToytO?p=preview < / p >

例如:

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

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

1)你可以使用深层css选择器

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

2)你也可以改变视图封装,它被设置为模拟作为默认值,但可以很容易地改变为本地使用阴影DOM原生浏览器实现,在你的情况下,你只需要禁用它

例如:“

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


}
}

我提出一个例子让它更清楚,因为angular.io /指导/组件样式声明:

阴影穿透的后代组合子已弃用,并已从主要浏览器和工具中移除支持。因此,我们计划在Angular中放弃对/deep/、>>>和::ng-deep的支持。在此之前,::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;
}

将规则应用到单个组件

app-login组件上所有具有btn-red类的按钮都将被设置样式。

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


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

如果你可以访问子组件代码,我发现它有很多cleaner传递一个@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>

简单的回答是,你根本不应该这么做。它破坏了组件封装,破坏了从自包含组件中获得的好处。考虑将道具标志传递给子组件,然后它可以自行决定如何以不同的方式呈现或应用不同的CSS,如果需要的话。

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

Angular不赞成所有影响父样式的子样式的方法。

< a href = " https://angular。Io /guide/component-styles# deprecable -deep——and-ng-deep" rel="nofollow noreferrer">https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep

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

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


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

然后,你就可以修改组件的css,而不需要使用::ng-deep

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

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

为了将css的范围限制在这个组件及其子组件上,在组件的顶部标记中添加一个css类,并将css "这个标签:

模板:

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

你不应该在父组件中为子组件元素编写CSS规则,因为Angular组件是一个自包含的实体,它应该显式地声明什么对外界可用。如果将来子组件的布局发生变化,分散在其他组件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>

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

实际上还有一个选择。这样比较安全。你可以使用ViewEncapsulation。但把你所有的组件样式放到它的标签(又名选择器)。但无论如何,总是喜欢一些全局风格加上封装风格。

下面是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() { }
}

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

在parrent

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

子组件

@Input() ContainerCustomStyle: string;

在child In 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);
}

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

我已经在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将被贬低,在我看来,禁用封装只是太多的代码泄漏。

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

首先是一些警告。

  1. 还是不要这么做。澄清一下,我不打算让子组件允许您对它们进行样式设置。SOC。如果你作为组件设计者想要允许这一点,那么你就拥有了更多的权力。
  2. 如果你的孩子没有生活在阴影中,那么这对你来说就行不通了。
  3. 如果你必须支持一个浏览器,不能有一个影子dom,那么这也不会为你工作。

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

截至今天(Angular 9), Angular使用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应用中,这可能是这样的:

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

要在子组件中为元素的类赋值,只需在子组件中使用@Input字符串,并将其用作模板中的表达式。下面是我们在共享Bootstrap加载按钮组件中更改图标和按钮类型的示例,而不影响它在整个代码库中的使用方式:

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

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

app-loading-button.component.ts

@Input() additionalClasses: string;

parent.html

<app-loading-button additionalClasses="fa fa-download btn-secondary">...</app-loading-button>

设'parent'是父类的类名,'child'是子类的类名

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

你可以使用这个格式来定义父组件中的子组件的CSS格式

Since /deep/, >>>和::ng-deep都不建议使用。 最好的方法是在您的子组件样式

中使用以下方法
:host-context(.theme-light) h2 {
background-color: #eef;
}
这将在你的子组件的任何祖先中寻找主题光。 https://angular.io/guide/component-styles#host-context

我希望通过以下方式实现这一目标:

使用@Component将css类添加到宿主元素,并将encapsulation设置为none。然后在组件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;
}

这是一个只有普通css的解决方案,没有什么花哨的,你甚至不需要!important。我假设你不能修改子结点,否则答案就更简单了,我把答案放在最后以防万一。

当使用库中预先制作的组件时,有时需要覆盖子CSS,并且开发人员没有提供任何class输入变量。::ng-deep已弃用,而encapsulation: ViewEncapsulation.None将组件的所有CSS转换为全局。这里有一个简单的解决方案,这两个都不用。

事实上,我们确实需要一个全局样式,以便CSS到达子节点。因此,我们可以将样式放在styles.css中,或者我们可以创建一个新的CSS文件,并将其添加到angular.json中的styles数组中。唯一的问题是我们需要一个特定的选择器,这样就不会针对其他元素。这是一个非常简单的解决方案-只需在html中添加一个唯一的类名,我建议在类名中使用父组件的名称,以确保它是唯一的。

父组件

<child class="child-in-parent-component"></child>

让我们假设我们想要改变child中所有按钮的背景颜色,我们确实需要实现正确的专一性以确保我们的样式优先。我们可以将!important放在所有属性的旁边,但更好的方法是重复类名,直到我们的选择器足够特定,这可能需要尝试几次。这样,其他人可以在必要时再次重写此css。

全局样式文件

.child-in-parent-component.child-in-parent-component.child-in-parent-component
button {
background-color: red;
}

或者使用!important(不推荐)

.child-in-parent-component button {
background-color: red !important;
}

如果子组件可以修改

只需向组件中添加一个输入变量,并使用Angular的ngStyle指令。您可以添加多个变量来为组件的多个区域设置样式。

子组件

type klass = { [prop: string]: any } | null;


@Component({...})
export class ChildComponent {
@Input() containerClass: klass = null;
@Input() pClass: klass = null;
...
}
<div [ngStyle]="containerClass">
<p [ngStyle]="pClass">What color will I be?</p>
</div>

父组件

<child
[containerClass]="{ padding: '20px', 'background-color': 'black' }"
[pClass]="{ color: 'red' }"
>
</child>

这是创建具有动态样式的组件的预期方法。许多预制组件都有类似的输入变量。

这对我来说很有效

在父组件中:

<child-component [styles]="{width: '160px', borderRadius: '16px'}" >
</child-component>