Nadpisywanie styli podczas pisania aplikacji webowych to problem, z którym spotkał się nie jeden początkujący jak i doświadczony programista. Jak to się dzieje, że style w Angularze nie kolidują ze sobą? Jest to możliwe dzięki ich odpowiedniej enkapsulacji.

Czym jest enkapsulacja?
Enkapsulacja (inaczej hermetyzacja) polega na ukrywaniu danych – w tym przypadku styli w obrębie danego komponentu tak, aby nie były one dostępne na zewnątrz niego.
Jak to działa?
Dekorator Component w obiekcie konfiguracyjnym (obiekt, który podajemy jako argument) przyjmuje pole o nazwie encapsulation typu ViewEncapsulation.
import { Component } from '@angular/core';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
stylesUrl: ['./test.component.css'],
encapsulation: ViewEncapsulation.Emulated
})
export class TestComponent {}
ViewEncapsulation
W enumie mamy do wyboru 4 wartości: Emulated, None, ShadowDom i Native (wychodzący z użycia).
Dla wyjaśnienia co przy wykorzystaniu każdej opcji się dzieje posłużę się przykładem TestComponent, który wyświetla tekst i posiada klasę .test oraz selektor :host.
<div class="test">
test
</div>
:host {
border: 1px solid red;
display: block;
}
.test {
width: 100%;
}
Emulated
Domyślna forma enkapsulacji. Generuje id dla każdego elementu, a następnie do każdego stylu dokleja odpowiednio wygenerowane id – powoduje to unikalność wszystkich styli w obrębie całej aplikacji.
Kod, który zostaje wygenerowany znajduję się poniżej. Angular dodaje atrybuty takie jak _nghost-* i _ngcontent-* gdzie * oznacza losowy ciąg znaków unikalny w całej aplikacji.
<app-test _ngcontent-yup-c12 _nghost-yup-c11>
<div _ngcontent-yup-c11 class="test">
test
</div>
</app-test>
[_nghost-yup-c11] {
border: 1px solid red;
display: block;
}
.test[_ngcontent-yup-c11] {
width: 100%;
}
None
W danym komponencie zostaje wyłączona enkapsulacja styli co powoduję, że style z naszego komponentu będą również dostępne w pozostałych.
<app-test _ngcontent-hbt-c12>
<div class="test">
test
</div>
</app-test>
.test {
width: 100%;
}
W przypadku użycia ViewEncapsulation.None selektor :host nie jest obsługiwany, dlatego nie wygenerowano dla niego stylu css.
ShadowDom
Wykorzystuje mechanizm Shadow Dom do enkapsulacji styli. Jest to technika, która jest używana w Web Components – pozwala na ukrycie logiki w obrębie danego elementu DOM. Dzięki czemu nasze style będą osadzone razem z naszym komponentem w DOM.
<app-test>
#shadow-root
<style>
:host {
border: 1px solid red;
display: block;
}
.test {
width: 100%;
}
</style>
<div class="test">
test
</div>
</app-test>
#shadow-root pozwala na załączenie naszych styli w obrębie naszego komponentu przez co nie wpływają one resztę styli.
Więcej informacje o Shadow Dom.
Native
To poprzednia nazwa używana dla zastosowania Shadow Dom. Zalecane jest używanie wartości ShadowDom, ponieważ Native niedługo zostanie usunięte z kodu.
Podsumowanie
Kolidowanie styli to powszechny problem. Jest rozwiązywany na wiele sposobów w różnych technologiach: przy użyciu odpowiedniej metodologii, użyciu specjalnych bibliotek np. styled-components lub są dostarczane razem z technologią jak w przypadku Angulara.
Fakt, że Angular rozwiązuje ten problem bez dodatkowej konfiguracji ułatwia codzienną pracę i oszczędza nam kilka/kilkanaście godzin poświeconych na debuggowanie dlaczego element ma inny styl niż powinien.