AngularAtlased. 22.2

Cap. 02Fundamente moderne11 / 75

Stilurile componentelor și încapsularea

:host, cele trei moduri de încapsulare, teme cu variabile CSS și de ce ::ng-deep e ultima soluție.

Fiecare componentă își aduce propriul CSS și, implicit, CSS-ul ăsta rămâne în componentă: o regulă .title dintr-o componentă nu atinge un .title din alta. Angular face asta rescriindu-ți selectorii când compilează componenta. Mecanismul se numește view encapsulation.

Dacă știi cum funcționează rescrierea, ai răspuns la întrebările pe care le pune oricine în prima lună: de ce CSS-ul părintelui nu ajunge la copil, de ce un stil apare brusc pe altă pagină și cum faci o componentă personalizabilă fără ::ng-deep.

De ce contează
În browser, CSS-ul e global prin natura lui. Încapsularea e ce te lasă să scrii selectori scurți și simpli într-o aplicație mare fără grijă — cât timp știi unde îi sunt marginile.

Unde stau stilurile unei componente

Inline în styles sau într-un fișier, cu styleUrl. Oricum ar fi, aparțin componentei: Angular le adaugă în pagină când apare prima instanță și le scoate când e distrusă ultima. CSS-ul global — reset-uri, fonturi, design tokens — merge în styles.scss, care nu e încapsulat.

@Component({
  selector: 'app-note',
  template: `<p class="note"><ng-content /></p>`,
  // stiluri inline…
  styles: `
    :host { display: block; }
    .note { padding: 0.5rem 0.75rem; border-left: 3px solid var(--accent); }
  `,
  // …sau un fișier: styleUrl: './note.css'
})
export class Note {}

Emulated: modul implicit

Angular dă fiecărei componente un id unic și îi marchează elementele cu două atribute: _nghost-… pe elementul gazdă și _ngcontent-… pe fiecare element din template. Apoi adaugă atributul pe fiecare parte a selectorilor tăi: .note devine .note[_ngcontent-ng-c123]. Regulile tale nu pot ieși din componentă — dar regulile din afară tot intră: CSS-ul global și componentele fără încapsulare se aplică normal.

/* ce scrii tu */
:host { display: block; }
.note { border-left: 3px solid var(--accent); }
.list .note:hover { background: var(--surface-2); }

/* ce primește browserul (Emulated) */
[_nghost-ng-c123] { display: block; }
.note[_ngcontent-ng-c123] { border-left: 3px solid var(--accent); }
.list[_ngcontent-ng-c123] .note[_ngcontent-ng-c123]:hover { background: var(--surface-2); }

Cele patru moduri, live

ViewEncapsulation.None sare peste rescriere: stilurile devin globale imediat ce apare componenta. ShadowDom folosește Shadow DOM-ul adevărat al browserului, deci CSS-ul paginii nu intră. ExperimentalIsolatedShadowDom (experimental din v21) merge un pas mai departe, cum vezi mai jos.

import { ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-embed-widget',
  // Emulated (implicit) · None · ShadowDom · ExperimentalIsolatedShadowDom
  encapsulation: ViewEncapsulation.ShadowDom,
  template: `…`,
  styles: `…`,
})
export class EmbedWidget {}
LiveAceeași regulă în patru moduri de încapsulare

În altă parte pe pagină

Un paragraf cu clasa .enc-lab-note

Emulated (implicit)

None

Nemontată.

ShadowDom

ExperimentalIsolatedShadowDom

ModSelectorii din browserUnde stă stilul
Fiecare componentă are o regulă .enc-lab-note. Bifează căsuța ca să montezi componenta None și urmărește la ce paragrafe ajunge — unul dintre ele e într-un shadow root.

Regula componentei None ajunge la pagină și la componenta Emulated — și, surprinzător, și la cea ShadowDom. În modul ShadowDom, Angular copiază stilurile celorlalte componente din aplicație în fiecare shadow root. Selectorii Emulated nu se potrivesc acolo, dar cei globali da. ExperimentalIsolatedShadowDom pune în shadow root doar stilurile componentei. La SSR, ambele moduri shadow sunt randate ca Emulated.

Ce mod, când

ModStilurile tale ies?Stilurile paginii intră?Folosește-l pentru
Emulatednudaaproape orice
Noneda, devin globaledarar: markup pe care nu-l controlezi, o foaie de stil globală livrată ca o componentă
ShadowDomnunu — dar Angular copiază înăuntru stilurile celorlalte componentewidget-uri puse în paginile altora
ExperimentalIsolatedShadowDomnunuizolare completă (experimental)

:host, :host() și :host-context()

Elementul gazdă — chiar <app-card> — aparține template-ului părintelui, deci un selector obișnuit din componentă nu ajunge la el. :host ajunge. Gazda pornește cu display: inline, așa că cele mai multe componente au nevoie de :host { display: block }. :host(.active) se aplică atunci când gazda are o clasă; :host-context(.dark), când o are orice strămoș.

/* elementul gazdă: chiar <app-card> */
:host {
  display: block; /* gazdele sunt inline implicit */
  border: 1px solid var(--border);
}

/* o variantă oferită de componentă: <app-card class="compact"> */
:host(.compact) {
  padding: 0.5rem;
}

/* când un strămoș are clasa (emulat în modul Emulated) */
:host-context(.print) {
  border-color: black;
}

Preferă :host() pentru variantele pe care le oferă o componentă. Angular emulează :host-context() în modul Emulated, dar într-un shadow root adevărat doar Chromium îl suportă. Pentru teme, variabilele CSS merg peste tot.

Cum stilizezi un copil din părinte

Întrebarea pe care o pune toată lumea: „CSS-ul meu nu merge pe componenta copil!” Selectorii părintelui primesc atributul părintelui, iar elementele din copil îl poartă pe al copilului — deci nu se potrivesc niciodată. Iată cum încearcă oamenii, compilat live.

LiveRestilizează butonul Cumpără din părinte
Părinte
A ajuns la buton
nu
Regulă globală
nu

Fiecare parte a selectorului a primit atributul părintelui. Butonul din copil poartă atributul copilului, deci nu se potrivește nimic.

Tu scrii
.attempt-plain app-buy-button button {
  background: var(--bad);
}
Browserul primește
—
Încearcă fiecare variantă și compară ce scrii cu ce primește de fapt browserul.

Ultimele două rezistă la refactorizări: copilul publică ce se poate schimba, iar părintele folosește doar atât. ::ng-deep e deprecated, dar nu are înlocuitor, așa că Angular îl păstrează pentru cazurile în care nu tu deții copilul — stilizarea unei biblioteci externe, de exemplu. Chiar și atunci, începe-l mereu cu :host. Fii atent și la specificitate: în modul Emulated, .buy[_ngcontent-…] din copil contează ca două clase, deci o regulă din afară are nevoie de cel puțin atât ca să câștige.

/* ✗ global: activ pe fiecare pagină cât timp există componenta */
::ng-deep .mat-mdc-button { text-transform: uppercase; }

/* ✓ dacă chiar trebuie: doar în interiorul acestei componente */
:host ::ng-deep .mat-mdc-button { text-transform: uppercase; }

Teme cu variabile CSS

Declară în copil variabile cu valori de rezervă — var(--buy-bg, var(--surface-2)) — și setează-le oriunde mai sus: în styles.scss pentru toată aplicația, pe un container pentru o secțiune sau cu [style.--buy-bg] pentru o singură instanță. Modul întunecat devine atunci doar alt set de valori.

@Component({
  selector: 'app-buy-button',
  template: `<button class="buy"><ng-content /></button>`,
  styles: `
    /* API-ul public de stil: variabile cu valori de rezervă… */
    .buy {
      background: var(--buy-bg, var(--surface-2));
      color: var(--buy-fg, var(--text));
      border-radius: var(--buy-radius, 8px);
    }
    /* …și variantele pe care le suportă copilul */
    :host(.danger) .buy {
      --buy-bg: var(--bad-soft);
      --buy-fg: var(--bad);
    }
  `,
})
export class BuyButton {}

Ce intră în styles.scss

Reset-uri, fonturi, design tokens (culori, spațieri și raze ca variabile) și stiluri pentru HTML care nu e randat de componentele tale — innerHTML dintr-un CMS, de exemplu. Tot restul aparține componentei care îl randează.

Clasele și stilurile legate dinamic sunt la Class & style bindings; cum se comportă Shadow DOM într-un Web Component, la Web Components cu Angular Elements.

Capcane frecvente

  • O componentă care ignoră width și margin. Gazda e implicit display: inline. Adaugă :host { display: block }.
  • ViewEncapsulation.None ca să „repari” un selector. Stilurile devin globale și rămân așa: lovesc fiecare element cu clasa respectivă cât timp există componenta.
  • ::ng-deep fără :host. Aceeași problemă, câte o regulă pe rând.
  • Stilizezi markup-ul intern al copilului. Merge cu ::ng-deep până când copilul își schimbă template-ul. Cere-i copilului o variabilă sau o variantă.
  • Te bazezi pe ShadowDom pentru izolare. Angular copiază în shadow root stilurile celorlalte componente. Dacă ai nevoie de izolare reală, uită-te la ExperimentalIsolatedShadowDom.

Fișă rapidă

styles / styleUrl      CSS-ul componentei; adăugat cu prima instanță, scos odată cu ultima
Emulated (default)     selectorii primesc [_ngcontent-…]; nimic nu iese, CSS-ul paginii tot intră
None                   fără rescriere: stilurile sunt globale cât timp există componenta
ShadowDom              shadow root adevărat; Angular tot copiază înăuntru stilurile celorlalte componente
Isolated (exp. v21)    ExperimentalIsolatedShadowDom: doar stilurile componentei
:host                  elementul gazdă; inline implicit → :host { display: block }
:host(.x)              o variantă a gazdei: <app-card class="x">
:host-context(.x)      un strămoș are .x; evită-l într-un shadow root adevărat
::ng-deep              oprește delimitarea; deprecated; mereu :host ::ng-deep, doar pentru cod care nu e al tău
CSS variables          se moștenesc peste orice graniță: API-ul public de stil al unei componente
styles.scss            reset-uri, fonturi, tokens, markup din CMS/innerHTML — nu stiluri de componente

Cap. 02 · 0 din 8 terminate

Ai terminat lecția?

Marcheaz-o și apare pe harta ta: în cuprins și pe prima pagină.

Se marchează singură după ce citești toată lecția.

  1. Standalone & bootstrap
  2. Data binding și evenimente
  3. Control flow: @if, @for, @switch
  4. @let și expresiile noi din template
  5. @defer — lazy loading în template
  6. Class & style bindings
  7. Stilurile componentelor și încapsularea
  8. Pipes: când și cum
Vezi toată harta ta

Toate cele 75 de pagini · scrie ca să filtrezi

  • 01Ce e nou în Angular 21 & 22Toate schimbările importante din v21 și v22, pe scurt, cu link către pagina care le explică.Start
  • 01Prima ta aplicație, pas cu pasO listă de lecturi construită de la o componentă goală la o aplicație terminată — signals, @for, input-uri și output-uri, un serviciu și un formular, pas cu pas.Start
  • 01Decizii rapide„Unde pun asta?”, „Signal sau Observable?”, „Shared sau feature?” — răspunsuri scurte la întrebările de zi cu zi.Start
  • 01Întrebări de interviu Angular60 de întrebări reale de interviu pentru junior, mid și senior, cu răspunsul de dat, întrebarea care urmează și greșelile de evitat. Plus o simulare de interviu.Start
  • 02Standalone & bootstrapCum pornește o aplicație fără NgModule: bootstrapApplication, app.config.ts, imports în componentă.Fundamente moderne
  • 02Data binding și evenimenteInterpolare, binding pe proprietăți și pe atribute, evenimente cu $event și filtre de taste și cum e construit [( )] — ce intră în DOM și ce se întoarce.Fundamente moderne
  • 02Control flow: @if, @for, @switchSintaxa de blocuri care înlocuiește *ngIf/*ngFor/ngSwitch, cu track, @empty și verificare exhaustivă.Fundamente moderne
  • 02@let și expresiile noi din templateVariabile locale cu @let, arrow functions, spread, regex, instanceof, comentarii în tag-uri.Fundamente moderne
  • 02@defer — lazy loading în templateÎncarci componente grele doar când e nevoie: triggere, prefetch, placeholder, loading, error.Fundamente moderne
  • 02Class & style bindingsDe ce [class.x] și [style.x] au înlocuit ngClass și ngStyle (cu migrare automată din v21).Fundamente moderne
  • 02Stilurile componentelor și încapsularea:host, cele trei moduri de încapsulare, teme cu variabile CSS și de ce ::ng-deep e ultima soluție.Fundamente moderne
  • 02Pipes: când și cumPipe pur vs impur, pipe custom și cum alegi între pipe, computed() și o metodă.Fundamente moderne
  • 03signal() și computed()Primitivele reactive: stare scriibilă, stare derivată, egalitate, untracked și reguli de imutabilitate.Signals & reactivitate
  • 03effect() — când DA, când NUEfecte secundare sincronizate cu semnale: localStorage, logging, API-uri imperative. Și capcanele lor.Signals & reactivitate
  • 03linkedSignal() — stare derivată editabilăUn semnal care se resetează când se schimbă sursa, dar pe care îl poți și seta manual.Signals & reactivitate
  • 03resource, rxResource, httpResourceDate asincrone ca semnale: status, value, error, reload, anulare automată. Stabile din v22.Signals & reactivitate
  • 03debounced() — semnale cu întârziereVarianta „debounce” a unui semnal, fără RxJS. Perfect pentru căutare.Signals & reactivitate
  • 03Liste: căutare, filtrare, sortare, paginareUn lanț de computed-uri care recalculează doar ce s-a schimbat, cu filtrele ținute în URL, ca un link să redeschidă aceeași vedere.Signals & reactivitate
  • 03Observables de la zeroCe e un Observable, subscribe și unsubscribe, operatorii pe care îi folosești în fiecare săptămână, cold vs hot — și când ajunge un signal.Signals & reactivitate
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — și când RxJS rămâne alegerea bună.Signals & reactivitate
  • 04input() și output()Inputuri ca semnale (required, transform, alias) și outputuri tipizate. Data down, events up.Componente: comunicare
  • 04model() — two-way bindingBanana-in-a-box [( )] cu un singur API. Când îl folosești și când e mai bine input + output.Componente: comunicare
  • 04viewChild & contentChildInterogări ca semnale: viewChild, viewChildren, contentChild, contentChildren, opțiunea read.Componente: comunicare
  • 04Lifecycle & DestroyRefCe hook-uri mai contează în era signals, afterNextRender, DestroyRef și ngOnChanges tipizat.Componente: comunicare
  • 04Content projectionng-content cu select, sloturi multiple, conținut implicit și capcana proiecției condiționale.Componente: comunicare
  • 04ng-template & ngTemplateOutletTemplate-uri ca valori: render props în Angular, context tipizat și personalizare de componente.Componente: comunicare
  • 05Smart vs DumbContainer vs presentational: cine ține starea, cine doar afișează, și cum le împarți corect.Design de componente
  • 05Componente generice <T>Un DataTable<T> sau Select<T> tipizat corect, cu template-uri pentru celule.Design de componente
  • 05Componente dinamiceNgComponentOutlet, createComponent cu inputBinding/outputBinding și un dashboard construit din config.Design de componente
  • 05Directive & host compositionDirective atribut, metadata host: {} și Directive Composition API (hostDirectives).Design de componente
  • 05Controale custom de formularFormValueControl (Signal Forms) vs ControlValueAccessor: un rating cu stele, în ambele variante.Design de componente
  • 05Change detectionOnPush e implicit din v22, zone.js lipsește din v21. Ce declanșează randarea și cum să nu te arzi.Design de componente
  • 06inject() & @Service()Noul decorator @Service() din v22, inject() vs constructor și contextul de injecție.Dependency Injection
  • 06Providers & ierarhia de injectoriRoot vs rută vs componentă, useClass/useValue/useFactory/useExisting și modificatorii optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Configurare tipizată, funcții provideFeature(), makeEnvironmentProviders și inițializatori.Dependency Injection
  • 06injectAsync() — servicii lazyÎncarci un serviciu greu abia când ai nevoie de el, cu prefetch la idle.Dependency Injection
  • 07Structura de folderecore / shared / features, ce intră în fiecare și cum arată un feature pe dinăuntru.Arhitectura aplicației
  • 07Shared vs featureCând muți o componentă în shared și (mai ales) când NU. Checklist concret.Arhitectura aplicației
  • 07Interfețe & modeleInterfață inline sau fișier separat? DTO vs model de domeniu, type vs interface, unde le pui.Arhitectura aplicației
  • 07State management cu signalsStore-uri simple pe semnale, facade, stare locală vs globală și când îți trebuie NgRx.Arhitectura aplicației
  • 07Style guide & namingConvențiile oficiale actuale: nume de fișiere fără sufixe, protected, readonly, ordinea membrilor.Arhitectura aplicației
  • 07Barrels, aliasuri & granițeindex.ts, path aliases, API public pe feature și reguli de dependență care se pot verifica automat.Arhitectura aplicației
  • 07Erori: @boundary & ErrorHandlerNoul bloc @boundary din v22.2, ErrorHandler global, erori HTTP și erori din resource.Arhitectura aplicației
  • 08Routing modern & lazy loadingloadComponent, rute copil, parametri ca input-uri și moștenirea parametrilor (default nou în v22).Routing
  • 08Guards & resolverscanActivate, canMatch, canDeactivate și resolve ca funcții, cu redirect prin UrlTree / RedirectCommand.Routing
  • 09Signal Forms — bazeleFormulare construite pe semnale: form(), [formField], validare prin schemă. Stabile din v22.Formulare
  • 09Signal Forms — avansatValidare custom și cross-field, async/HTTP cu debounce, liste dinamice, disabled/hidden, scheme reutilizabile.Formulare
  • 09Reactive Forms tipizateFormGroup tipizat, nonNullable, FormArray — și cum conviețuiesc cu Signal Forms.Formulare
  • 10HttpClient, interceptors & API layerHttpClient fără setup (v21), Fetch implicit (v22), interceptori funcționali și stratul de API cu mapare DTO.HTTP & date
  • 11Performanță — checklistCe chiar contează: OnPush + signals, track, @defer, lazy routes, imagini, bundle și hidratare.Calitate & performanță
  • 11Testare cu VitestVitest e runner-ul implicit din v21. TestBed, componente cu semnale, servicii, HTTP și harness-uri.Calitate & performanță
  • 11DevTools: cum te uiți în aplicațieChrome DevTools și Angular DevTools pas cu pas: ce arată fiecare panou, cu exerciții care merg chiar pe site-ul ăsta.Calitate & performanță
  • 11Angular AriaComponente headless, accesibile, pe care le stilizezi cum vrei: tabs, accordion, menu, listbox...Calitate & performanță
  • 12SSR, prerender & render modesCând randezi pe server, când la build și când doar în browser: RenderMode pe rută, app.routes.server.ts și costurile reale.SSR & hidratare
  • 12Hidratare: event replay & incrementalCum preia browserul HTML-ul de pe server fără să-l refacă: hidratare completă, event replay, @defer (hydrate on …) și erorile de nepotrivire.SSR & hidratare
  • 12Cod compatibil cu serverulwindow nu există pe server: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, cache-ul HTTP și PendingTasks.SSR & hidratare
  • 13Micro frontendsCând merită să spargi o aplicație în mai multe deploy-uri și când e doar complexitate: Native Federation, Module Federation, iframes, Web Components.Arhitectură la scară
  • 13Web Components cu Angular ElementscreateCustomElement: o componentă Angular folosită ca tag HTML oriunde, plus comunicarea între aplicații prin evenimente și BroadcastChannel.Arhitectură la scară
  • 13Monorepo, librării & granițeUn workspace cu mai multe aplicații și librării: ng generate library, Nx, entry points secundare, publicare și reguli de dependență.Arhitectură la scară
  • 13Arhitectură hexagonală (ports & adapters)Domeniul fără Angular, porturi ca clase abstracte și adaptoare interschimbabile: HTTP, localStorage sau in-memory, fără să atingi UI-ul.Arhitectură la scară
  • 14Semnalele pe dinăuntruGraful reactiv: producători și consumatori, push-pull, de ce computed e lazy și glitch-free, problema diamantului și când rulează efectele.Reactivitate avansată
  • 14RxJS avansat: operatori de ordin superiorswitchMap, mergeMap, concatMap și exhaustMap pe o diagramă live, plus retry cu backoff, shareReplay și cum eviți scurgerile.Reactivitate avansată
  • 14NgRx SignalStoreState management la scară pe semnale: withState, withComputed, withMethods, rxMethod, entități și hooks — și când un store simplu e suficient.Reactivitate avansată
  • 14Mașini de stări cu signalsFără stări imposibile: o mașină tipizată pe signals, cu tranziții, guards și diagrama stărilor, live.Reactivitate avansată
  • 15WebSockets: timp real care rezistă rețeleiUn socket tipizat ca signals: reconectare cu backoff și jitter, heartbeat, coadă de mesaje cât ești offline și siguranță la SSR.Timp real și offline
  • 15Actualizări optimiste și rollbackInterfață instantanee, dar onestă: snapshot și rollback, răspunsuri sosite în altă ordine, chei de idempotență.Timp real și offline
  • 15Offline-first: Service Worker și cacheService Worker-ul Angular: strategii de cache, anunțarea versiunilor noi și o coadă pentru modificările făcute offline.Timp real și offline
  • 16Web WorkersCalcule grele fără să blochezi interfața: un worker real în pagină, comunicare prin mesaje și când nu merită.UI & performanță avansată
  • 16Liste uriașe: virtual scroll100.000 de rânduri fără lag: CDK virtual scroll, itemSize, trackBy și alternativele (paginare, infinite scroll).UI & performanță avansată
  • 16Animații moderne & View Transitionsanimate.enter și animate.leave în locul @angular/animations (depreciat), tranziții CSS și View Transitions la navigare.UI & performanță avansată
  • 16Memory leaks: cum le găsești și le repariSubscripții, timere și listeneri care trăiesc mai mult decât componenta lor — cum îi vezi în DevTools și cum îi închizi.UI & performanță avansată
  • 17Securitate: XSS, sanitizare & CSPCe face Angular automat împotriva XSS, când devine periculos bypassSecurityTrust, plus CSP cu nonce, Trusted Types și XSRF.Securitate & globalizare
  • 17Autentificare: token-uri & refreshUn interceptor care atașează token-ul, reîmprospătează o singură dată la 401 și reia cererile din coadă — plus unde ții token-ul.Securitate & globalizare
  • 17OAuth 2.1 și OpenID Connect cu PKCEFluxul authorization code cu PKCE, pas cu pas: verifier și challenge, state și nonce, ID token-ul și de ce un BFF e mai sigur.Securitate & globalizare
  • 17Internaționalizare (i18n)$localize, atributul i18n, ICU plural/select, build per limbă vs. traduceri la runtime și formatarea după locale.Securitate & globalizare