Pentru clase și stiluri dinamice folosești binding-urile native [class] / [class.x] și [style] / [style.x]. Directivele ngClass și ngStyle mai există, dar style guide-ul actual recomandă binding-urile native, iar v21 a adăugat migrări automate pentru ele.
Clase
<!-- O singură clasă, condiționată -->
<li [class.active]="isActive()">...</li>
<!-- Mai multe clase: string, array sau obiect -->
<div [class]="'card elevated'"></div>
<div [class]="['card', size()]"></div>
<div [class]="{ card: true, selected: isSelected(), disabled: !enabled() }"></div>
<!-- Clasele statice și cele din binding se COMBINĂ, nu se suprascriu -->
<button class="btn" [class.btn-primary]="primary()">OK</button>Stiluri
<!-- O proprietate CSS, cu unitate -->
<div [style.width.px]="width()"></div>
<div [style.height.%]="progress()"></div>
<div [style.font-size.rem]="scale()"></div>
<!-- Variabile CSS (custom properties) -->
<div [style.--accent]="brandColor()"></div>
<!-- Mai multe stiluri deodată: string sau obiect -->
<div [style]="{ 'background-color': bg(), opacity: dim() ? 0.5 : 1 }"></div>De ce nu ngClass / ngStyle
<!-- ✓ Nou: binding nativ, fără import, mai rapid -->
<div [class]="{ active: isActive(), 'is-big': size() === 'lg' }"></div>
<div [style.width.px]="width()"></div><!-- ✗ Vechi: necesită import NgClass / NgStyle (sau CommonModule) -->
<div [ngClass]="{ active: isActive, 'is-big': size === 'lg' }"></div>
<div [ngStyle]="{ 'width.px': width }"></div>- Fără import: e parte din compilator, nu o directivă.
- Mai performant: nu există un differ care să compare obiectul la fiecare change detection.
- Mai lizibil pentru cazul cel mai des — o clasă condiționată:
[class.active]="x()".
# v21: migrări automate
ng generate @angular/core:ngclass-to-class
ng generate @angular/core:ngstyle-to-styleClase pe elementul gazdă: host
Pentru elementul gazdă al unei componente (tag-ul <app-button> însuși) folosește proprietatea host din metadata, nu @HostBinding. Din v21, aceste binding-uri sunt și verificate de tipuri.
// Clase pe elementul gazdă al componentei → metadata `host`, nu @HostBinding
@Component({
selector: 'app-button',
host: {
class: 'ui-btn', // static
'[class.is-loading]': 'loading()', // dinamic
'[class]': 'variant()', // 'primary' | 'ghost'
'[style.--hue]': 'hue()',
'[attr.aria-busy]': 'loading()',
},
template: `<ng-content />`,
})
export class Button {
readonly variant = input<'primary' | 'ghost'>('primary');
readonly loading = input(false, { transform: booleanAttribute });
readonly hue = input(330);
}Cine câștigă când mai multe locuri setează același stil
Același element poate primi un stil din cinci locuri: host-ul propriei componente, host-ul unei directive, un atribut static style, o mapă [style] și un binding [style.x]. Angular nu lasă să câștige ultimul scris — aplică o ordine fixă de prioritate.
- suprascris
- suprascris
- suprascris
Câștigătorul e citit din browser (getComputedStyle), nu calculat de laborator.
De sus în jos: un binding pe o singură proprietate bate o mapă, o mapă bate o valoare statică — iar orice din template bate ce pun directivele și componenta pe host-ul lor. Observă că până și un atribut static style din template câștigă în fața binding-ului de host al unei directive. Aceeași ordine e valabilă și pentru clase: [class.active]="false" scoate un active scris în atributul static class. Încă un detaliu: un binding „oprit” trebuie să fie undefined, care lasă decizia stratului de dedesubt. null înseamnă „șterge stilul ăsta”: treci pe el și fundalul dispare, chiar dacă toate celelalte straturi sunt pornite.
// de la prioritatea cea mai mare la cea mai mică:
// 1. [style.background]="…" un property binding în template
// 2. [style]="{ background: … }" un map binding în template
// 3. style="background: …" o valoare statică în template
// 4. host bindings ale unei directive de pe element
// 5. host bindings ale componentei înseși
@Component({
template: `
<app-swatch
appTint
style="background: yellow"
[style]="{ background: 'green' }"
[style.background]="'red'"
/>
`,
})
export class Page {} // → roșu: numărul 1 e pornit
@Directive({ selector: '[appTint]', host: { '[style.background]': "'blue'" } })
export class Tint {}
@Component({ selector: 'app-swatch', host: { '[style.background]': "'gray'" }, template: '' })
export class Swatch {}Capcane frecvente
[class]și[class.x]pe același element funcționează împreună; ordinea de prioritate: binding-ul specific ([class.x]) câștigă.- Mutarea obiectului de clase: dacă modifici același obiect pe loc, Angular poate să nu observe. Creează unul nou (sau folosește un
computed()). - Unități uitate:
[style.width]="200"nu face nimic; scrie[style.width.px]="200". - Stiluri cu încapsulare: clasele aplicate pe copii proiectați nu sunt stilizate de CSS-ul componentei tale (folosește
:hostsau variabile CSS). Cum funcționează încapsularea vezi live la Stilurile componentelor.