ngStyle i ngClass – dynamiczne style
Nauczysz się dynamicznie zmieniać wygląd elementów HTML – dodawać i usuwać klasy CSS oraz ustawiać style bezpośrednio z TypeScript. Poznasz różne sposoby – od prostego bindingu po pełne dyrektywy.
Po co dynamiczne style?
Statyczny wygląd strony to jedno. Ale prawdziwa aplikacja reaguje na dane i działania użytkownika – elementy zmieniają kolor, rozmiar, stają się aktywne lub nieaktywne. Do tego służą dynamiczne style.
Kilka przykładów z życia:
- Wiersz tabeli zmienia się na czerwono gdy średnia spada poniżej 2.0
- Aktywna zakładka w menu dostaje klasę
active - Przycisk zmienia kolor gdy formularz jest poprawnie wypełniony
- Odznaka statusu zmienia kolor: zielony (dostępny), żółty (mało), czerwony (brak)
Angular oferuje kilka sposobów na dynamiczne style – od prostego bindingu jednej klasy po dyrektywy obsługujące wiele klas i właściwości naraz. Zacznijmy od najprostszych.
Dyrektywy ngClass i ngStyle pochodzą z pakietu
@angular/common. W komponentach standalone musisz je
zaimportować do tablicy imports[]:
import { NgClass, NgStyle } from '@angular/common'; @Component({ standalone: true, imports: [NgClass, NgStyle], ... })
Binding pojedynczej klasy CSS
Najprostszy sposób – dodaje lub usuwa jedną konkretną klasę
w zależności od wartości wyrażenia. Używamy składni
[class.nazwaklas]="warunek".
export class AppComponent { czyAktywny = true; czyBledny = false; czyWybrany = true; srednia = 1.8; }
<!-- Dodaje klasę "active" gdy czyAktywny = true --> <li class="nav-item" [class.active]="czyAktywny"> Strona główna </li> <!-- Dodaje "is-invalid" gdy pole ma błąd --> <input class="form-control" [class.is-invalid]="czyBledny" type="text" > <!-- Kilka klas jednocześnie przez osobne bindingi --> <div class="card" [class.border-primary]="czyWybrany" [class.border-danger]="srednia < 2.0" > Karta ucznia </div>
Możesz łączyć statyczne klasy (class="card")
z dynamicznym bindingiem ([class.border-primary]="warunek").
Angular inteligentnie scala obie listy –
statyczne klasy są zawsze obecne, dynamiczne dodaje lub usuwa
zależnie od warunku.
Dyrektywa ngClass – wiele klas naraz
Gdy chcesz zarządzać wieloma klasami jednocześnie,
[class.X] staje się nieporęczny – trzeba by pisać
osobny binding dla każdej klasy. Dyrektywa [ngClass]
przyjmuje obiekt lub tablicę i obsługuje wszystko naraz.
Sposób 1 – Obiekt klas
Przekazujesz obiekt, gdzie klucze to nazwy klas CSS,
a wartości to warunki (true/false)
kiedy ta klasa ma być dodana.
export class AppComponent { czyAktywny = true; czyBledny = false; rozmiar = 'duzy'; }
<!-- Obiekt inline – { 'nazwa-klasy': warunek } --> <div [ngClass]="{ 'text-success': czyAktywny, 'text-danger': czyBledny, 'fs-5': rozmiar === 'duzy' }" > Status systemu </div> <!-- Wynik gdy czyAktywny=true, czyBledny=false, rozmiar='duzy': class="text-success fs-5" -->
Sposób 2 – Tablica klas
Gdy chcesz po prostu dodać kilka stałych klas dynamicznie (bez warunków), możesz podać tablicę stringów.
export class AppComponent { klasyStylow: string[] = ['card', 'p-3', 'shadow-sm']; }
<!-- Tablica ze zmiennej --> <div [ngClass]="klasyStylow"> Karta ze stylami z tablicy </div> <!-- Wynik: class="card p-3 shadow-sm" --> <!-- Tablica inline --> <button [ngClass]="['btn', 'btn-primary', 'mt-2']"> Kliknij </button>
Sposób 3 – Metoda zwracająca obiekt (zalecane)
Najczystsze rozwiązanie – przenosisz logikę do klasy TypeScript, a szablon pozostaje prosty.
export class AppComponent { srednia = 4.2; // Metoda zwraca obiekt klas – logika POZA szablonem klasySredniej(): object { return { 'text-success': this.srednia >= 4.5, 'text-primary': this.srednia >= 3.5 && this.srednia < 4.5, 'text-warning': this.srednia >= 2.0 && this.srednia < 3.5, 'text-danger': this.srednia < 2.0, 'fw-bold': this.srednia >= 4.5 // pogrubienie dla celujących }; } }
<!-- Szablon jest czysty – logika w metodzie --> <span class="fs-5" [ngClass]="klasySredniej()"> {{ srednia }} </span> <!-- Dla srednia=4.2: class="fs-5 text-primary" Dla srednia=5.0: class="fs-5 text-success fw-bold" Dla srednia=1.5: class="fs-5 text-danger" -->
Binding pojedynczego stylu CSS
Tak jak [class.X] obsługuje jedną klasę, tak
[style.właściwość] ustawia jedną właściwość CSS
bezpośrednio ze zmiennej TypeScript.
export class AppComponent { kolorTla = '#1a73e8'; kolorTekstu = 'white'; rozmiarCzcionki = 20; // liczba – jednostkę dodamy w szablonie szerokosc = '300px'; // string – jednostka wbudowana przezroczystosc = 0.8; }
<!-- Kolor tła ze zmiennej --> <div [style.backgroundColor]="kolorTla">Nagłówek</div> <!-- Kolor tekstu --> <p [style.color]="kolorTekstu">Tekst kolorowy</p> <!-- Rozmiar czcionki – liczba + jednostka przez .px --> <p [style.fontSize.px]="rozmiarCzcionki">Duży tekst</p> <!-- Wynik: font-size: 20px --> <!-- Szerokość ze stringa zawierającego jednostkę --> <div [style.width]="szerokosc">Blok</div> <!-- Przezroczystość – wartość 0.0–1.0 --> <img src="images/logo.png" [style.opacity]="przezroczystosc" alt="Logo">
| Składnia | Co robi? | Przykład |
|---|---|---|
[style.color] |
Ustawia kolor tekstu | [style.color]="kolorTekstu" |
[style.fontSize.px] |
Ustawia rozmiar czcionki w px (liczba ze zmiennej) | [style.fontSize.px]="20" |
[style.width] |
Ustawia szerokość (string z jednostką) | [style.width]="'300px'" |
[style.backgroundColor] |
Ustawia kolor tła (camelCase!) | [style.backgroundColor]="'#fff'" |
CSS używa myślników: background-color, font-size.
W bindingu stylu Angular używasz camelCase:
backgroundColor, fontSize.
Alternatywnie możesz użyć cudzysłowów: [style.'background-color']
– ale camelCase jest czytelniejsze.
Dyrektywa ngStyle – wiele stylów naraz
Gdy chcesz ustawić wiele właściwości CSS jednocześnie,
użyj dyrektywy [ngStyle]. Przyjmuje obiekt gdzie kluczami
są właściwości CSS, a wartościami – wartości tych właściwości.
export class AppComponent { priorytet = 'wysoki'; // 'wysoki' | 'sredni' | 'niski' stylPriorytetu(): object { if (this.priorytet === 'wysoki') { return { 'background-color': '#f8d7da', 'border-left': '4px solid #dc3545', 'font-weight': 'bold' }; } if (this.priorytet === 'sredni') { return { 'background-color': '#fff3cd', 'border-left': '4px solid #ffc107' }; } return { 'background-color': '#d1e7dd', 'border-left': '4px solid #198754' }; } }
<!-- Obiekt inline --> <p [ngStyle]="{ 'color': 'red', 'font-size': '20px', 'font-weight': 'bold' }"> Ważny komunikat </p> <!-- Obiekt z metody – czytelniejsze przy złożonej logice --> <div class="p-3 mb-2 rounded" [ngStyle]="stylPriorytetu()" > Zadanie o priorytecie: {{ priorytet }} </div>
ngClass z Bootstrapem – praktyczne przykłady
Największa siła ngClass ujawnia się w połączeniu z Bootstrap –
dynamicznie przypisujesz klasy utilityowe Bootstrapa na podstawie danych.
Kolorowe odznaki statusu
export class AppComponent { produkty = [ { id: 1, nazwa: 'Laptop', stan: 15 }, { id: 2, nazwa: 'Myszka', stan: 3 }, { id: 3, nazwa: 'Klawiatura', stan: 0 }, ]; klasaStanu(stan: number): object { return { 'bg-success': stan > 5, 'bg-warning': stan > 0 && stan <= 5, 'bg-danger': stan === 0 }; } }
<table class="table"> <thead> <tr><th>Produkt</th><th>Stan magazynowy</th></tr> </thead> <tbody> @for (produkt of produkty; track produkt.id) { <tr> <td>{{ produkt.nazwa }}</td> <td> <span class="badge text-white" [ngClass]="klasaStanu(produkt.stan)" > @if (produkt.stan === 0) { Brak } @else { {{ produkt.stan }} szt. } </span> </td> </tr> } </tbody> </table>
Aktywna pozycja w menu
export class AppComponent { aktywnaZakladka: string = 'home'; przelaczZakladke(nazwa: string): void { this.aktywnaZakladka = nazwa; } }
<ul class="nav nav-tabs"> <li class="nav-item"> <button class="nav-link" [ngClass]="{ 'active': aktywnaZakladka === 'home' }" (click)="przelaczZakladke('home')" >Strona główna</button> </li> <li class="nav-item"> <button class="nav-link" [ngClass]="{ 'active': aktywnaZakladka === 'uczniowie' }" (click)="przelaczZakladke('uczniowie')" >Uczniowie</button> </li> <li class="nav-item"> <button class="nav-link" [ngClass]="{ 'active': aktywnaZakladka === 'plan' }" (click)="przelaczZakladke('plan')" >Plan lekcji</button> </li> </ul> <!-- Treść aktywnej zakładki --> @if (aktywnaZakladka === 'home') { <p>Strona główna...</p> } @if (aktywnaZakladka === 'uczniowie') { <p>Lista uczniów...</p> } @if (aktywnaZakladka === 'plan') { <p>Plan lekcji...</p> }
Kiedy co używać?
Masz teraz kilka narzędzi do dynamicznych stylów. Oto prosta zasada pomagająca wybrać właściwe.
| Narzędzie | Kiedy używać? | Przykład |
|---|---|---|
[class.X]="warunek" |
Jedna klasa, prosty warunek boolean | [class.active]="czyAktywny" |
[ngClass]="{...}" |
Kilka klas, każda z osobnym warunkiem | [ngClass]="{'text-danger': blad, 'fw-bold': wazny}" |
[ngClass]="metoda()" |
Złożona logika klas – przenosisz ją do TypeScript | [ngClass]="klasySredniej()" |
[style.X]="wartość" |
Jedna właściwość CSS ze zmiennej | [style.color]="kolorTekstu" |
[ngStyle]="{...}" |
Kilka właściwości CSS naraz | [ngStyle]="{'color': 'red', 'font-size': '20px'}" |
W praktyce ngClass jest znacznie popularniejszy niż
ngStyle. Definiujesz style w pliku CSS (gdzie jest ich
miejsce), a przez ngClass tylko włączasz i wyłączasz
gotowe klasy. ngStyle mieszasz style z TypeScriptem –
stosuj go tylko gdy wartość stylu naprawdę
musi być dynamiczna (np. wynika z kalkulacji lub danych użytkownika).
Częste błędy
❌ Błąd 1 – Brak importu NgClass lub NgStyle
❌ Błąd w konsoli: unknown directive
// Brak importu w @Component @Component({ standalone: true, imports: [], // ← NgClass nie jest tutaj! ... })
✅ Zaimportowany z @angular/common
import { NgClass, NgStyle } from '@angular/common'; @Component({ standalone: true, imports: [NgClass, NgStyle], ... })
❌ Błąd 2 – Myślnik w nazwie klasy bez cudzysłowów
❌ Błąd parsowania – myślnik bez cudzysłowów
<!-- Angular nie może parsować myślnika w kluczu --> <div [ngClass]="{ text-danger: blad }"></div>
✅ Cudzysłowy wokół nazwy klasy z myślnikiem
<div [ngClass]="{ 'text-danger': blad }"></div>
❌ Błąd 3 – ngStyle z liczbą bez jednostki
❌ Liczba bez jednostki – styl nie zadziała
// rozmiar = 20 (liczba bez px) <p [ngStyle]="{ 'font-size': rozmiar }">Tekst</p> <!-- CSS dostanie: font-size: 20 → nieprawidłowe -->
✅ Dołącz jednostkę do wartości
// Sposób 1 – dodaj jednostkę w szablonie <p [ngStyle]="{ 'font-size': rozmiar + 'px' }">Tekst</p> // Sposób 2 – użyj [style.fontSize.px] <p [style.fontSize.px]="rozmiar">Tekst</p>
Zadanie – tabela uczniów z dynamicznym wyglądem
Stwórz tabelę uczniów, która dynamicznie zmienia wygląd wierszy i odznak w zależności od danych.
W klasie zdefiniuj tablicę uczniów z polami:
id,imie,nazwisko,srednia,obecnosc(liczba w %),aktywny(boolean)
W szablonie zastosuj:
-
[class.table-danger] na wierszu tabeli
(
<tr>) gdy średnia poniżej 2.0 - [class.table-success] na wierszu gdy średnia powyżej 4.5
-
ngClass na odznace (
<span class="badge">) z metodąklasaSredniej(srednia)zwracającą odpowiednie klasy Bootstrap (bg-success,bg-primary,bg-warning,bg-danger) -
[class.text-muted] i [class.text-decoration-line-through]
na imieniu i nazwisku gdy
aktywny = false - [ngStyle] na kolumnie obecności ustawiający kolor tekstu: zielony gdy ≥90%, pomarańczowy gdy ≥75%, czerwony poniżej
W następnym materiale poznamy ng-template, ng-container i ng-content – zaawansowane mechanizmy szablonów pozwalające budować elastyczne i wielokrotnie używalne komponenty.