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.

[class] [style] ngClass ngStyle
01

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.

Import NgClass i NgStyle

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],
  ...
})
02

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".

ts/app.component.ts TS
export class AppComponent {
  czyAktywny   = true;
  czyBledny    = false;
  czyWybrany   = true;
  srednia      = 1.8;
}
html/class-binding.html HTML
<!-- 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>
class=”” i [class.X] mogą współistnieć

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.

03

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.

ts/app.component.ts TS
export class AppComponent {
  czyAktywny = true;
  czyBledny  = false;
  rozmiar    = 'duzy';
}
html/ngclass-obiekt.html HTML
<!-- 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.

ts/app.component.ts TS
export class AppComponent {
  klasyStylow: string[] = ['card', 'p-3', 'shadow-sm'];
}
html/ngclass-tablica.html HTML
<!-- 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.

ts/app.component.ts TS
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
    };
  }
}
html/ngclass-metoda.html HTML
<!-- 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"
-->
04

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.

ts/app.component.ts TS
export class AppComponent {
  kolorTla     = '#1a73e8';
  kolorTekstu  = 'white';
  rozmiarCzcionki = 20;         // liczba – jednostkę dodamy w szablonie
  szerokosc    = '300px';       // string – jednostka wbudowana
  przezroczystosc = 0.8;
}
html/style-binding.html HTML
<!-- 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ładniaCo 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'"
camelCase w nazwach właściwości CSS

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.

05

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.

ts/app.component.ts TS
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'
    };
  }
}
html/ngstyle.html HTML
<!-- 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>
06

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

ts/app.component.ts TS
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
    };
  }
}
html/odznaki-statusu.html HTML
<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

ts/app.component.ts TS
export class AppComponent {
  aktywnaZakladka: string = 'home';

  przelaczZakladke(nazwa: string): void {
    this.aktywnaZakladka = nazwa;
  }
}
html/menu-zakładki.html HTML
<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>   }
07

Kiedy co używać?

Masz teraz kilka narzędzi do dynamicznych stylów. Oto prosta zasada pomagająca wybrać właściwe.

NarzędzieKiedy 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'}"
Preferuj klasy CSS nad ngStyle

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).

08

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
Następny temat

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.