Стиль дочерних компонентов из 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>
поскольку parent
а также child
являются двумя отдельными компонентами, их стили привязаны к их собственному объему.
В моем родительском компоненте я попытался сделать:
.parent .child {
// Styles for child
}
Но .child
стили не применяются к child
компоненты.
Я пытался с помощью styleUrls
включить parent
таблица стилей в child
компонент для решения проблемы области:
// child.component.ts
styleUrls: [
'./parent.component.css',
'./child.component.css',
]
Но это не помогло, также попробовал другой путь, выбирая child
таблица стилей в parent
но это тоже не помогло.
Так как же стилизовать дочерние компоненты, которые включены в родительский компонент?
22 ответа
Обновление - Новейший путь
Не делай этого, если можешь этого избежать. Как отмечает Девон Санс в комментариях: эта функция, скорее всего, будет устаревшей.
Обновление - новый путь
Начиная с версии 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>
`
Старый способ
Ты можешь использовать 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>
`
Если вы не хотите использовать::ng-deep, вы можете сделать это, что кажется правильным:
import { ViewEncapsulation } from '@angular/core';
@Component({
....
encapsulation: ViewEncapsulation.None
})
И тогда вы сможете изменить css форму вашего компонента без необходимости из:: ng-deep
.mat-sort-header-container {
display:flex;
justify-content:center;
}
ВНИМАНИЕ: будьте осторожны, так как если ваш компонент имеет много дочерних элементов, CSS, который вы пишете для этого компонента, может повлиять на все дочерние элементы!
ОБНОВЛЕНИЕ 3:
::ng-deep
также считается устаревшим, что означает, что вы больше не должны этого делать. Неясно, как это влияет на вещи, где вам нужно переопределить стили в дочерних компонентах из родительского компонента. Мне кажется странным, если это будет удалено полностью, потому что как это повлияет на вещи как библиотеки, где вам нужно переопределить стили в компоненте библиотеки?
Прокомментируйте, если у вас есть понимание этого.
ОБНОВЛЕНИЕ 2:
поскольку /deep/
и все другие теневые пирсинг селекторы теперь устарели. Угловой упал ::ng-deep
который следует использовать вместо этого для более широкой совместимости.
ОБНОВИТЬ:
Если вы используете Angular-CLI, вам нужно использовать /deep/
вместо >>>
или это не будет работать.
ОРИГИНАЛ:
После перехода на страницу Github на Angular2 и случайного поиска "style" я нашел этот вопрос: Angular 2 - styleHTML
Который сказал использовать что-то, что было добавлено в 2.0.0-beta.10
, >>>
а также ::shadow
селекторы.
(>>>) (и эквивалент /deep/) и::shadow были добавлены в 2.0.0-beta.10. Они похожи на CSS-комбинаторы теневого DOM (которые устарели) и работают только с инкапсуляцией: ViewEncapsulation.Emulated, которая используется по умолчанию в Angular2. Вероятно, они также работают с ViewEncapsulation.None, но затем игнорируются только потому, что в них нет необходимости. Эти комбинаторы являются лишь промежуточным решением, пока не поддерживаются более продвинутые функции для многокомпонентного стиля.
Так просто делаешь
:host >>> .child {}
В parent
В файле стилей решена проблема. Обратите внимание, что, как указано в приведенной выше цитате, это решение является промежуточным, пока не поддерживается более продвинутый межкомпонентный стиль.
Не следует писать правила 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>
Другими словами, вы используете :host
Псевдо-селектор, предоставляемый Angular + набор CSS-классов для определения возможных дочерних стилей в самом дочернем компоненте. Затем у вас есть возможность вызывать эти стили извне, применяя предопределенные классы к <child>
хост-элемент.
К сожалению, похоже, что / 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
Возникла та же проблема, поэтому, если вы используете angular2-cli с scss/sass, используйте "/deep/" вместо ">>>", последний селектор еще не поддерживается (но отлично работает с css).
Если вы хотите быть более нацеленным на фактический дочерний компонент, чем вы должны сделать следующее. Таким образом, если другие дочерние компоненты имеют одинаковое имя класса, они не будут затронуты.
Плункер: 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 {}
Надеюсь это поможет!
codematrix
На самом деле есть еще один вариант. Что довольно безопасно. Вы можете использовать ViewEncapsulation.None, но поместите все стили вашего компонента в его тег (он же селектор). Но в любом случае всегда предпочитайте какой-нибудь глобальный стиль плюс инкапсулированные стили.
Вот модифицированный пример Дениса Рыбалки:
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() { }
}
Поскольку /deep/, >>> и:: ng-deep устарели. Наилучший подход - использовать следующее при оформлении дочерних компонентов:
:host-context(.theme-light) h2 {
background-color: #eef;
}
Это будет искать световую тему в любом из предков вашего дочернего компонента. См. Документы здесь: https://angular.io/guide/component-styles#host-context
Есть несколько вариантов для достижения этой цели в Angular:
1) Вы можете использовать глубокие селекторы CSS
:host >>> .childrens {
color: red;
}
2) Вы также можете изменить инкапсуляцию вида, для нее установлено значение Эмуляция по умолчанию, но ее можно легко изменить на Native, который использует реализацию собственного браузера Shadow 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() {
}
}
Я считаю, что намного проще передать переменную @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>
На сегодняшний день (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 это может быть примерно так:
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;
}
Я предпочитаю архивировать следующее:
используйте @Component, чтобы добавить класс css к элементу хоста и установить для инкапсуляции значение none. Чем ссылаться на этот класс, который был добавлен к хосту в компонентах style.css.scss. Это позволит нам объявлять стили, которые будут влиять только на нас и наших детей в рамках нашего класса. fe
@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, если это необходимо.
<parent>
<child [foo]="bar"></child>
</parent>
Angular осуждает все способы воздействия на дочерние стили от родителей.
Для назначения класса элемента в дочернем компоненте вы можете просто использовать @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>
Это решение только с ванильным css, ничего особенного, вам даже не нужно . Я предполагаю, что вы не можете изменить дочерний элемент, в противном случае ответ будет еще более простым, я на всякий случай поместил этот ответ в конец.
Иногда необходимо переопределить дочерний CSS при использовании предварительно созданного компонента из библиотеки, и разработчики не предоставили никаких
class
входные переменные.
::ng-deep
устарел и
encapsulation: ViewEncapsulation.None
превращает весь CSS вашего компонента в глобальный. Итак, вот простое решение, которое не использует ни то, ни другое.
Дело в том, что нам нужен глобальный стиль, чтобы CSS мог достичь дочернего элемента. Итак, мы можем просто добавить стиль в
styles.css
или мы можем создать новый файл CSS и добавить его в
styles
массив в
angular.json
. Единственная проблема заключается в том, что нам нужен конкретный селектор, чтобы не нацеливаться на другие элементы. Это довольно простое решение — просто добавьте уникальное имя класса в html, я рекомендую использовать имя родительского компонента в имени класса, чтобы обеспечить его уникальность.
Родительский компонент
<child class="child-in-parent-component"></child>
Давайте представим, что мы хотим изменить цвет фона всех кнопок в дочернем элементе, нам нужно добиться правильной специфичности, чтобы убедиться, что наши стили имеют приоритет. Мы можем сделать это рядом со всеми нашими свойствами, но лучший способ — просто повторять имя класса, пока наш селектор не станет достаточно конкретным, может потребоваться несколько попыток. Таким образом, кто-то другой может снова переопределить этот 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>
Это предполагаемый способ создания компонента с динамическим стилем. Многие готовые компоненты будут иметь аналогичную входную переменную.
У меня также была эта проблема, и я не хотел использовать устаревшее решение, поэтому я закончил с:
в отрыве
<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);
}
работает как положено и не должно быть устаревшим;)
это сработало для меня
в родительском компоненте:
<child-component [styles]="{width: '160px', borderRadius: '16px'}" >
</child-component>
I have solved it outside Angular. I have defined a shared scss that I'm importing to my children.
shared.scss
%cell {
color: #333333;
background: #eee;
font-size: 13px;
font-weight: 600;
}
child.scss
@import 'styles.scss';
.cell {
@extend %cell;
}
My proposed approach is a way how to solve the problem the OP has asked about. As mentioned at multiple occasions,::ng-deep,:ng-host will get depreciated and disabling encapsulation is just too much of a code leakage, in my view.
По мере обновления Интернета я нашел решение.
Сначала несколько предостережений.
- По-прежнему не делай этого. Чтобы уточнить, я бы не стал планировать дочерние компоненты, позволяющие вам стилизовать их. SOC. Если вы, как разработчик компонентов, хотите позволить это, тем больше возможностей для вас.
- Если ваш ребенок не живет в теневом доме, это не сработает для вас.
- Если вам необходимо поддерживать браузер, в котором не может быть теневого домена, это также не сработает для вас.
Во-первых, отметьте инкапсуляцию вашего дочернего компонента как тень, чтобы она отображалась в реальном теневом пространстве. Во-вторых, добавьте атрибут части к элементу, который вы хотите разрешить родителю для стилизации. В таблице стилей родительского компонента вы можете использовать метод::part() для доступа к
Я предлагаю пример, чтобы сделать его более понятным, так как https://angular.io/guide/component-styles заявляет:
Пронзающий теневой комбайнатор устарел, и поддержка удаляется из основных браузеров и инструментов. Поэтому мы планируем отказаться от поддержки в Angular (для всех 3 of /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;
}
Применить правило к одному компоненту
Все кнопки, имеющие btn-red
класс на app-login
Компонент будет стилизован.
@import `./theme/sass/_colors`;
/deep/ app-login button.red-btn {
color: $button_ripple_white_text;
background: $button_ripple_red;
}
Пусть 'parent' будет именем класса родителя, а 'child' будет именем класса дочернего элемента
.parent .child{
//css definition for child inside parent components
}
вы можете использовать этот формат для определения формата CSS для "дочернего" компонента внутри "родительского"