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

Chr*_*odz 223 css angular-components angular

我有一个父组件:

<parent></parent>
Run Code Online (Sandbox Code Playgroud)

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

<parent>
  <child></child>
  <child></child>
  <child></child>
</parent>
Run Code Online (Sandbox Code Playgroud)

父模板:

<div class="parent">
  <!-- Children goes here -->
  <ng-content></ng-content>
</div>
Run Code Online (Sandbox Code Playgroud)

儿童模板:

<div class="child">Test</div>
Run Code Online (Sandbox Code Playgroud)

由于parentchild是两个单独的组件,他们的风格被锁定在他们自己的范围.

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

.parent .child {
  // Styles for child
}
Run Code Online (Sandbox Code Playgroud)

.child样式没有应用于child组件.

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

// child.component.ts
styleUrls: [
  './parent.component.css',
  './child.component.css',
]
Run Code Online (Sandbox Code Playgroud)

但这并没有帮助,也尝试了另一种方式,即取出child样式表,parent但这也无济于事.

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

mic*_*yks 208

更新 - 最新方式

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

更新 - 更新的方式

Angular 4.3.0开始,所有穿孔的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>      
    `
Run Code Online (Sandbox Code Playgroud)


老路

你可以使用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>      
`
Run Code Online (Sandbox Code Playgroud)

  • 弃用某些东西而不提供替代方案可能不是最好的解决方案。 (36认同)
  • 有角度的团队计划也放弃对:: ng-deep的支持.从他们的文档:"阴影穿透后代组合器已被弃用,并且正在从主要浏览器和工具中删除支持.因此我们计划放弃对Angular的支持(对于所有3个/ deep /,>>>和:: ng-在那之前,为了更广泛地兼容工具,应该首选:: ng-deep." https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep. (18认同)
  • 只要这是一个公认的答案,人们就会误导.**:: ng-deep**不应在上面的评论中用作@DevonSams点. (4认同)
  • [::ng-deep 现已弃用](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep),[你们可以使用这个](https://angular .io/guide/component-styles#css-imports) (4认同)
  • [`::ng-deep` 现已弃用](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep),我不建议在未来的应用程序中使用它 (3认同)
  • 但是,Chrome中不推荐使用穿孔CSS组合器 (2认同)
  • 这是我有时做的事情.我不是试图从父母那里引用孩子,而是反过来.我使用SASS父选择器引用子进程中的父进程.在您的子组件中:: host {parent-component&{/*your styles*/}}.只要子组件嵌套在父组件中,该样式就会应用.我不知道这种方法是否是犹太教,但它现在有效.https://sass-lang.com/documentation/file.SASS_REFERENCE.html#parent-selector (2认同)
  • 如果没有`ng-deep`,仍然没有替代或推荐的方法吗?Angular为我们提供这样做的好方法似乎是荒谬的。除了全局样式之外,是否有其他技术可以做到这一点? (2认同)
  • @Vincent-cm 那么你将如何改变库的样式?创建您自己的版本吗? (2认同)

Chr*_*odz 52

更新3:

::ng-deep也已弃用,这意味着您不应该再这样做了.目前还不清楚这会如何影响您需要从父组件覆盖子组件中的样式的内容.对我而言,如果完全删除它似乎很奇怪,因为这会影响作为库需要覆盖库组件中的样式的库?

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

更新2:

因为现在/deep/和所有其他阴影穿孔选择器都已弃用.角度下降::ng-deep应该用于替代更广泛的兼容性.

更新:

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

原版的:

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

据说使用了添加的内容2.0.0-beta.10,选择器>>>::shadow选择器.

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

所以简单地做:

:host >>> .child {}
Run Code Online (Sandbox Code Playgroud)

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

  • 2023 年仍然没有替代,也没有删除 ng-deep。 (2认同)

Ton*_*nio 21

如果你不想使用:: ng-deep,你可以这样做,这似乎是正确的方法:

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

@Component({
    ....
    encapsulation: ViewEncapsulation.None
})
Run Code Online (Sandbox Code Playgroud)

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

.mat-sort-header-container {
  display:flex;
  justify-content:center;
}
Run Code Online (Sandbox Code Playgroud)

警告:小心你的组件有很多孩子,你为这个组件编写的CSS可能会影响所有孩子!

  • 在我看来,这是最好的答案,因为它实际上是即将弃用的 `::ng-deep` 的可行替代方案。一般来说,组件无论如何都有自己的选择器(`&lt;my-component&gt;、&lt;div my-component&gt;`等),因此甚至不需要具有特殊类的包装元素。 (7认同)
  • @AlexWalker这可能是_your_情况的最佳答案,但值得一提的是,它只回答了OP问题的一半:此方法允许CSS正常地从上到下传播,但是,由于抛弃了所有封装,* *不将该样式限制为特定父级的子级**。如果您以一种方式设置parent1 的子级,而以另一种方式设置parent2 的子级,则这些 CSS 规则现在将在这两个地方相互冲突。这可能会让人感到非常痛苦(Angular 添加了封装来避免这种情况)。 (3认同)
  • @Tonio——是的,同意;直接回复亚历克斯而不是你。他的评论“_所以甚至不需要具有特殊类的包装元素_”让我有点害怕。也许是针对_特定_情况,但 Angular “浪费”时间支持封装是有原因的。这个答案在特定情况下是一种可行的解决方案,但正如您所说,一般来说是一个潜在危险的解决方案。[MatthewB 的解决方案](/sf/answers/3038054281/),例如,在保持封装的同时设置子组件的样式(但如果您有不止一代的子组件,它会变得_真的_混乱)。 (2认同)

Ser*_*Sev 16

有同样的问题,所以如果你使用angular2-cli和scss/sass使用'/ deep /'而不是'>>>',那么最后的选择器还不支持(但是对css很有用).


Mat*_* B. 16

遗憾的是,似乎已弃用/ deep/selector(至少在Chrome中) https://www.chromestatus.com/features/6750456638341120

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

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

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

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


cod*_*de5 10

如果您希望更多地针对实际的子组件而不是您应该执行的操作.这样,如果其他子组件共享相同的类名,则不会受到影响.

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 {}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

codematrix


Abd*_*eeb 9

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

:host-context(.theme-light) h2 {
  background-color: #eef;
}
Run Code Online (Sandbox Code Playgroud)

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


Den*_*lka 7

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

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

:host >>> .childrens {
     color: red;
 }
Run Code Online (Sandbox Code Playgroud)

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

   }
 }
Run Code Online (Sandbox Code Playgroud)

  • 实际上这意味着样式会影响整个 dom,而不仅仅是子元素。 (3认同)

rob*_*ing 6

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

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

SCSS方式:

.active {
  ::ng-deep md-list-item {
    background-color: #eee;
  }
}
Run Code Online (Sandbox Code Playgroud)

更好的方法: - 使用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>
Run Code Online (Sandbox Code Playgroud)

  • 也很难维护,特别是对于递归组件。 (2认同)

Ale*_*mov 6

您不应为父组件中的子组件元素编写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>
Run Code Online (Sandbox Code Playgroud)

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

  • @ManoharReddyPoreddy 我建议你先在实践中尝试这些代码片段。然后,如果您遇到任何问题,您会有一个特定的问题,我可以回答或建议查看特定主题以了解如何解决您的问题。我提到 `ViewEncapsulation` 只是因为它的默认值是导致 OP 问题的原因。您不必为上述代码分配不同的`ViewEncapsulation`。 (3认同)

小智 5

实际上,还有另一种选择。这比较安全。您可以使用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() { }
}
Run Code Online (Sandbox Code Playgroud)


viv*_*nov 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);
Run Code Online (Sandbox Code Playgroud)
/* 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; 
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <child-element></child-element>
</div>
Run Code Online (Sandbox Code Playgroud)

从上面的代码中我们可以看到,我们创建了一个自定义元素,就像 Angular 为我们对每个组件所做的那样,然后我们从全局范围覆盖自定义元素的阴影根中负责背景颜色的变量.

在 Angular 应用程序中,这可能类似于:

父组件.scss

child-element {
  --background-clr: yellow;
}
Run Code Online (Sandbox Code Playgroud)

子元素.component.scss

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

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