Enkapsulacja styli w Angular

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.

Udostępnij
Default image
Wojciech Szućko
Jestem Angular Developerem. Przedstawiam techniki i technologie, które wykorzystuje w codziennej pracy z web aplikacjami. Tworzyłem projekty między innymi dla Bank Pekao S.A., AlphaTauri czy Playmobil.