Nach oben

Angular – Kontextspezifische Stilregeln

Komponenten in Angular werden idealerweise so gebaut, dass sie universell eingesetzt werden können. Leider werden aber bei der Einbindung dieser Komponenten häufig kontextuelle Anpassungen benötigt. Wir zeigen auf, welche Möglichkeiten bestehen, um solche Anpassungen vorzunehmen.

Angular Logo

Komponenten haben in Angular ihre eigenen Stildefinitionen, welche nur innerhalb dieser Komponente gelten. Im Idealfall kann eine Komponente dann an allen gewünschten Stellen eingesetzt werden, ohne dass es eine Anpassung an der Komponente braucht. Häufig aber gibt es Spezialfälle: Das Padding muss etwas verändert werden; die Grösse ist an einer Stelle anders; die Farbe passt sich kontextspezifisch an.

Drei verschiedene Herangehensweisen ermöglichen kontextspezifische Anpassungen:

  1. Anpassungsbedarf wird der Komponente mit Input-Parametern mitgeteilt
  2. Komponente beinhaltet Stilregeln für den jeweiligen Kontext
  3. Eltern-Komponente definiert Stilregeln für Kind-Komponente

Vor- und Nachteile dieser drei Ansätze sowie deren Verwendungsmöglichkeiten werden im Folgenden aufgezeigt.

Darstellung mit Input-Parameter steuern

Eine Angular-Komponente kann mit Input-Parametern von aussen angesprochen werden. So kann einer Komponente mitgeteilt werden, welche Darstellung gewünscht wird. Diese Input-Parameter veranlassen, dass die Komponente mit den benötigten CSS-Klassen versehen wird, so dass die gewünschten Stilregeln zum Einsatz kommen.

Beispiel

Im HTML wird einer Komponente ein Input-Parameter für die Grösse mitgegeben:

<component [isBig]="true"></code>

Die Komponente hat einen entsprechenden Input-Parameter:

@Input() isBig: boolean;

Im HTML der Komponente wird mit [ngClass] (ggf. mit @Hostbinding) eine entsprechende Klasse gesetzt:

<div class="component" [ngClass]= "{ 'component—big': isBig }"/>

Im CSS der Komponente wird eine entsprechende Stildefinition für diese Klasse aufgeführt:

.component—big { font-size: 2rem }

Vorteile

Da die Stil-Regeln in der Komponente definiert werden, sind Abhängigkeiten bei Anpassungen besser ersichtlich (im Vergleich zu Stilregeln, welche in Eltern-Komponente definiert werden; siehe unten).

Nachteile

Es besteht die Gefahr, dass viele Input-Parameter für z.T. kleine Anpassungen (z.B. unterschiedliche Paddings) benötigt werden.

Eine nachvollziehbare Benennung von Input-Parametern gelingt mal besser und mal schlechter (z.B. reducedPaddingRight: «true»).

Anwendung

Die Definition von input-abhängigen Stilregeln eignet sich v.a. für eine limitierte Anzahl an gut benennbaren Varianten (z.B. bestimmte Grössen-Ausprägungen, invertierte Variante).

Wird mit einem Input-Parameter das HTML angepasst, sollten auch die dazugehörigen Stil-Anpassungen über diesen Input-Parameter gesteuert werden.

Darstellung mit kontextspezifischen Stildefinitionen steuern

Stilregeln für eine Angular-Komponente sind normalweise nur innerhalb dieser Komponente wirksam. Angular bietet aber mit «host-context» die Möglichkeit, innerhalb einer Komponente auf deren Einsatzkontext zu hören. Als Einsatzkontext kann eine CSS-Klasse oder ein Komponenten-Selektor angegeben werden.

Beispiel

Eine Komponente ChildComponent wird in einer ParentComponent eingesetzt:

<parent-component>
   <child-component></child-component>
</parent-component>

Im CSS der ChildComponent werden Stilregeln definiert, welche nur gelten, wenn die Komponente in der ParentComponent eingesetzt wird:

:host-context(parent-component) { 
   .child-component { 
      background: yellow; 
   } 
}

Vorteile

Wie bei der Steuerung mit Input-Parametern werden Stil-Regeln in der Komponente definiert, wodurch Abhängigkeiten bei Anpassungen besser ersichtlich sind (im Vergleich zu Stilregeln, welche in Eltern-Komponente definiert werden; siehe unten).

Nachteile

Für verschachtelte Abhängigkeiten ist «host-context» nicht geeignet, da nur die Verwendung einer Kontext-Ebene möglich ist. Es ist also nicht möglich, z.B. auf eine Browser-Detection-Klasse auf dem html-Tag und eine Eltern-Komponente zu hören (weder :host-context(.msie parent-component) { …} noch :host-context(.msie) { :host-context(parent-component) { … } } ist möglich).

Anwendung

Die «host-context»-Lösung eignet sich für Kontext-Stilregeln, welche sich mit einer Kontext-Ebene behandeln lassen. Ein Beispiel dafür wäre etwa, wenn eine Komponente für verschiedene Themes farblich angepasst wird (basierend auf einer Theme-Klasse auf dem html-Tag).

Die «host-context»-Lösung funktioniert aber nur bei nicht-verschachtelten Regeln. Es können z.B. Ausnahmeregeln basierend auf einer Browser-Detection definiert oder spezielle Stilregeln für den Einsatz der Komponente innerhalb einer einbettenden Komponente (z.B. Elternkomponente) angelegt werden, aber beides zusammen funktioniert nicht.

Sinnvoll kann sein, solche «host-context»-Stilregeln in eine separates CSS-Datei auszulagern (Komponenten können mehrere CSS-Dateien haben), um allgemeine von kontextspezifischen Regeln zu trennen. So kann der kontextspezifische Ballast einer Komponente z.B. für die Wiederverwertung in einem anderen Projekt schnell entfernt werden.

Darstellung der Kind-Komponente in Eltern-Komponente steuern

Eine Kind-Komponente kann auch aus einer Eltern-Komponente heraus mit Stilregeln versehen werden. Zum einen kann eine Kind-Komponente mit einer Klasse versehen werden, wodurch zumindest für den Host dieser Kind-Komponente Stilregeln definiert werden können. Zum andern kann der Angular-CSS-Pseudoselektor «ng-deep» eingesetzt werden, um den Host oder andere Elemente der Kind-Komponente anzusprechen.

Beispiel

Eine Komponente ChildComponent wird in einer ParentComponent eingesetzt und mit einer Klasse versehen:

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

Die Parent-Komponente führt in ihrem CSS Regeln für die Kind-Komponente auf. Mit «ng-deep» wird auf das HTML der Kind-Komponente zugegriffen:

.parent-component__child { 
   // Styles für Host der Kind-Komponente 
}
.parent-component__child { 
   ::ng-deep .child-component__title { 
      // Styles für HTML der Kind-Komponente 
   } 
}

Vorteile

Vorteilhaft ist an diesem Ansatz, dass Ausnahmeregeln dort gesetzt werden können, wo sie benötigt werden.

Nachteile

Da die Stilregeln nicht in der betroffenen (Kind-)Komponente definiert werden, sind Abhängigkeiten bei einer Anpassung an dieser Komponente schwerer zu eruieren.
Dazu kommt, dass «ng-deep» gemäss Angular-Guide veraltet und damit nicht oder nur bedingt zukunftsfähig ist.

Anwendung

Sinnvoll ist die Verwendung dieses Ansatzes v.a. dann, wenn die Stilanpassung nur in dieser Eltern-Komponente gilt.

Schlussfolgerung

Es gibt keinen Köngisweg – alle drei Ansätze haben ihren Nutzen.

Mit Input-Parametern werden alle Stilregeln in der Komponente definiert, was im Grundsatz sauber und übersichtlich ist. Mit vielen Input-Parametern aber wächst die Komplexität und Lesbarkeit.

Kontext-Stilregeln («host-context») werden ebenfalls in der Komponente definiert, was den Vorteil hat, dass bei weiteren Anpassungen an der Komponente die Abhängigkeiten und Ausnahmen schnell eruiert sind. Leider lässt dieser Ansatz keine Verschachtelung der Kontexte zu, weshalb er schnell an seine Grenzen stösst.

Die Steuerung einer Kind-Komponente in der Eltern-Komponente bedeutet, dass ein Teil der Stilregeln für die Kind-Komponente in (verschiedenen) Eltern-Komponenten definiert wird. Dadurch leidet die Nachvollziehbarkeit. Der Ansatz kann aber äusserst hilfreich sein, wenn kleine Anpassungen von Nöten sind, welche nicht über Input-Parameter realisiert werden sollen.

Die drei Ansätze können natürlich auch kombiniert werden. Insbesondere kann die Limitation des «host-context»-Ansatzes, welcher nur eine Kontext-Ebene erlaubt, mit der Steuerung durch die Elternkomponente kombiniert werden. So kann z.B. auf eine Klasse auf dem html-Tag mit «host-context» gehört werden und in einer Eltern-Komponente festgelegt werden, welche Stilregeln die Kind-Komponente in diesem Fall bekommt.

Für die Weiterentwicklung von Angular ist aber zu hoffen, dass für den veralteten «ng-deep»- und für den limitieren «host-context»-Ansatz neue und skalierbare Lösung angeboten werden, sei es nun in Angular selbst oder über breit unterstützte W3C-Standards.

Dieser Artikel ist Teil unserer Serie über Stärken und Schwächen von Angular.

Kommentare

Kommentar schreiben

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert