Czego użyć zamiast :: ng-deep

100

Próbuję stylizować element umieszczony przy wylocie routera na kątowy i chcę się upewnić, że wygenerowany element uzyska szerokość 100%

Z większości odpowiedzi wynika, że ​​powinienem użyć ::ng-deepselektora, ale z dokumentów Angulara jest on przestarzały. Czy jest alternatywa dla ::ng-deep?

Jacob Schwartz
źródło
2
::ng-deepnigdzie się nie wybiera. Zawsze będzie to ustawienie, które możesz włączyć. Nie ma absolutnie żadnego sposobu, aby mogli go teraz usunąć bez masowego sprzeciwu społeczności. Zobacz, ile wyników wróci dla tego wyszukiwania github.com/search?q=%3A%3Ang-deep&type=Code - to tak, jakby powiedzieć, że !importantwłaściwość css zniknie
Simon_Weaver
Nie wiem - z ciekawości przeszukałem cały projekt w naszym mono-repo (wiele dość dużych aplikacji korporacyjnych) i wyszedłem tylko z 69 referencjami. Wydaje mi się, że to zdecydowanie akceptowalny refaktor, aby wyjść z deprecjonowania i chętnie to zrobiłbym, gdy tylko wydadzą alternatywę. Poza tym !importantzajmuje ważne miejsce w specyfikacji CSS, podczas gdy ::deepzawsze była tylko propozycją.
dudewad

Odpowiedzi:

111

FWIW W moich badaniach nie znalazłem żadnego zamiennika dla ng-deep ani innych odpowiednich alternatyw. Dzieje się tak, ponieważ, jak sądzę, zespół Angular opiera się na specyfikacji W3C dotyczącej Shadow Dom, która początkowo miała takie selektory jak deep. Jednak od tego czasu W3c usunął zalecenie, ale nie zastąpił go nowym. Dopóki to się nie stanie, wyobrażam sobie, że zespół Angular zachowa ::ng-deepi jego alternatywy będą dostępne, ale w stanie przestarzałym z powodu oczekującego stanu wersji roboczych W3C. Nie jestem teraz w stanie znaleźć dokumentacji, aby to potwierdzić, ale ostatnio to widziałem.

Krótko mówiąc: kontynuuj używanie ::ng-deepi jego alternatywy, dopóki nie zostanie utworzony zamiennik - wycofanie jest tylko wczesnym powiadomieniem, aby ludzie nie byli zaskoczeni, gdy rzeczywista zmiana się zmaterializuje.

- AKTUALIZACJA -

https://drafts.csswg.org/css-scoping-1/ Oto projekt propozycji, jeśli jesteś zainteresowany. Wygląda na to, że pracują nad solidnym zestawem selektorów dla elementów w drzewie cienia; Myślę, że to ta specyfikacja, po zatwierdzeniu, będzie informować klona kątowego, jeśli w ogóle istnieje (tj. angular może nie potrzebować implementować własnych selektorów, gdy zostanie uruchomiona w przeglądarkach).

dudewad
źródło
Zgadzam się z tym, ale nie polecałbym celowego pisania nowego kodu przy użyciu przestarzałej funkcjonalności frameworka (i przeglądarki).
MT_
7
Ja też bym. Ale nie ma alternatywy, która, jak sądzę, jest tutaj słabo zarysowana. Czy masz jakieś sugestie, które mogą w tym pomóc?
dudewad
1
Jedyną alternatywą, o której mogę szybko pomyśleć, byłaby refaktoryzacja zagnieżdżania komponentów, co może wymagać więcej pracy niż masz czasu, ale może przynieść inne korzyści ...
MT_
36
Z biblioteką innej firmy praktycznie nie da się uniknąć konieczności korzystania ::ng-deepz niej od czasu do czasu (jeśli w ogóle zależy Ci na wyglądzie witryny) - nawet w przypadku czegoś w rodzaju kanciastego materiału. Mają błędy, które nie są naprawiane od miesięcy, a obejścia często obejmują ng-deep. I nie myl różnych przestarzałych „głębokich” selektorów - ::ng-deepjest zdecydowanie najmniej wycofanym.
Simon_Weaver
1
Tak, to jedna z najbrzydszych części całego systemu. Ale enkapsulacja jest tym, czym jest hermetyzacja. Musisz przełamać granice albo jawnie używając :: ng-deep w css, albo musisz to zrobić programowo. Czasami używamy atrybutu w tagu komponentu, aby wskazać, w jakim "trybie" znajduje się komponent (tj. Kontekst), a następnie style mogą żyć w komponencie potomnym bez :: ng-deep poprzez selektor atrybutu, taki jak: :host[some-context] {}- it zależy od tego, jakiego rodzaju elastyczności / przenośności chcesz. Nie lubię tak czy inaczej, ale to jest świat hermetyzacji.
dudewad
23

Aby ominąć przestarzałe ::ng-deep, zwykle wyłączamViewEncapsulation . Chociaż nie jest to najlepsze podejście, dobrze mi służyło.

Aby wyłączyć ViewEncapsulation, wykonaj następujące czynności w swoim komponencie:

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

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

Spowoduje to, że style .scss w tym komponencie będą globalne dla całej aplikacji. Aby nie pozwolić stylom na przechodzenie w górę łańcucha do komponentów rodzica i rodzeństwa, opakuj cały scss selektorem w następujący sposób:

app-header {
  // your styles here and any child component styles can go here
}

Teraz style określone tutaj zostaną przeniesione do komponentów podrzędnych, więc musisz być bardziej konkretny w swoich selektorach css i zwracać uwagę na swoje p i q podczas dodawania CSS (może dodać selektor potomny określony w aplikacji Angular, a następnie jego style).

Mówię, że nie jest to najlepsze podejście ze względu na powyższy akapit, ale to mi dobrze służyło.

AliF50
źródło
12
Jest to tylko obejście problemu, a jeśli masz duży projekt, wyłączenie go ViewEncapsulationspowoduje wiele szkód, umożliwiając przenikanie tych stylów do wszystkich komponentów. Z tej funkcji należy korzystać mądrze iz pełnym zrozumieniem
mpro
5
@mpro Rozumiem, dlatego dałem zastrzeżenie i powiedziałem, że to nie jest najlepsze podejście i musisz uważać na swoje p i q i musisz być bardziej szczegółowy. Dla mnie to podejście do tej pory działało dobrze. :: ng-deep jest oznaczony jako przestarzały i jest to obejście.
AliF50
1
Szczerze mówiąc, myślę, że to okropny wniosek, jeśli zrobiłeś to z powodu groźby utraty wartości. Tak, wiem, że to przyznajesz, ale naprawdę myślę, że strzelasz sobie w stopę, robiąc to. Widok hermetyzacji jest tak przydatny z wielu powodów. Jednak nie jest tak źle, jak ktokolwiek z zespołu kątowego porzucił go bez żadnego logicznego obejścia i doprowadzając wielu do wielu zamieszania. Koniec końców nadal piszesz kod dla przeglądarki internetowej - a nie jakiś zastrzeżony silnik kątowy.
Simon_Weaver
2
@Simon_Weaver Szanuję Twoją opinię i dziękuję za udostępnienie. Po prostu je ujawniam, ponieważ właśnie to pomijałem wycofanie. Zgłosiłem również zastrzeżenia.
AliF50
4
@ AliF50 „Oszukiwanie depresji” nie jest tak naprawdę rzeczą. Prawdziwy problem polega na tym, że i nigdy wcześniej tego nie widziałem, wycofali to bez podania alternatywy . Moja odpowiedź (zaakceptowana powyżej) wyjaśnia moją hipotezę, dlaczego (W3C go zdeprecjonował), aby dostosować się do specyfikacji. Jeśli jednak przeczytasz propozycje, wygląda na to, że :: ng-deep zostanie zastąpiony odpowiednią alternatywą, co oznacza, że ​​gdy stanie się dostępna, po prostu zaktualizuj swoje odniesienia :: ng-deep, a nie swoje podejście, które wymaga dosłownie przeprojektowanie całej aplikacji.
dudewad
19

Prostą i łatwą alternatywą dla stylu głębokiego jest styl wspólny wykorzystujący selektor elementu komponentu macierzystego. Więc jeśli masz to w hero-details.component.css:

:host ::ng-deep h3 {
  font-style: italic;
}

Stałoby się tak w styles.css:

app-hero-details h3 {
  font-style: italic;
}

Zasadniczo styl głęboki jest stylem niezamkniętym, więc koncepcyjnie wydaje mi się bardziej typowym stylem niż stylem składowym. Osobiście nie używałbym już głębokich stylów. Przełomowe zmiany są normalne w głównych aktualizacjach wersji, a usuwanie przestarzałych funkcji jest uczciwą grą.

J. Lenthe
źródło
1
Wow, teraz czuję się głupio. Dzięki! Wychodząc z innych frameworków front-endowych myślałem, że to niemożliwe
Rafael Vidaurre
1
To jest naprawdę przydatne. Szkoda, że ​​:: ng-deep był przestarzały przez tak długi czas bez wymiany (: host :: ng-deep działa zgodnie z oczekiwaniami, ale nie chcę używać przestarzałych rzeczy).
Alexei
8

Jak ktoś powiedział wcześniej, jeśli korzystasz z biblioteki innej firmy, praktycznie niemożliwe jest uniknięcie konieczności korzystania ::ng-deepz niej od czasu do czasu. Ale co zamierzasz zrobić ze swoimi poprzednimi projektami, gdy ::ng-deepprzeglądarka przestanie być obsługiwana?

Aby być gotowym na ten moment, zasugeruję co następuje:

  1. Użyj ViewEncapsulation.None mądrze. Co przekłada się na tylko te komponenty, które muszą mieć dostęp do głębszych komponentów.
@Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.scss'],
      encapsulation: ViewEncapsulation.None
    })
  1. Teraz, aby uniknąć kolizji i dziwności CSS, powinieneś (z reguły) zawsze zawijać szablon komponentu klasą. Tak więc example.component.html powinno wyglądać następująco:
<section class="app-example-container">
<!-- a third party component -->
<mat-tab-group>
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
</mat-tab-group>
</section>
  1. Ponownie, zgodnie z regułą, pierwszy wiersz każdego pliku SCSS będzie dotyczył kontenera komponentów. Ponieważ nie ma enkapsulacji , możesz modyfikować komponent innej firmy, kierując jego klasy. To powiedziawszy, przykład.component.scss powinien wyglądać następująco:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}

Notatka na przyszłość: https://angular.io/guide/component-styles
To powinno być pierwsze miejsce, w którym należy szukać oficjalnych alternatyw / sposobów na to, aby przejść

guzmanoj
źródło
But what are you going to do about your previous projects when the ::ng-deep became no longer supported by browsers?Czy to nie jest skompilowane / wypełnione przez angular cli, więc nie ma udziału przeglądarki? Świetna odpowiedź przy okazji.
beppe9000
W rzeczywistości jest to renderowane w pliku CSS, a następnie przeglądarka odpowiednio stosuje style. Aliasing jest możliwy (myślę), :host /deep/ .mat-tab-labelże należy go przekształcić w ::ng-deep. Szczerze mówiąc, wydaje się, że używanie aliasu jest wygodniejsze, ponieważ CLI może go zmienić w czasie kompilacji, ale nadal będziesz musiał wykonać ng buildi wdrożyć ponownie. ::ng-deep
Postanowiłem
tak, ma sens, aby uniknąć ponownego wdrożenia
beppe9000
1

Nie jest to ogólny zamiennik dla :: ng-deep, ale dla przypadku użycia opisanego przez autora pytania:

W szczególnym przypadku, gdy chcesz stylizować element wstawiony przez gniazdo routera, istnieje eleganckie rozwiązanie wykorzystujące sąsiedni selektor sąsiada w CSS:

router-outlet+* {
  /* styling here... */
}

Dotyczy to wszystkich elementów, które są bezpośrednimi sąsiadami routera.

Więcej informacji:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet

mrm1st3r
źródło
1
Nie polecam używania tego selektora. Wygląda na to, że otwierasz dosłowny koszmar kolizji, zwłaszcza gdy twoja aplikacja rośnie. Co więcej, selektor * jest dosłownie jednym najwolniejszym selektorem w CSS.
dudewad
@dudewad, podczas gdy selektor * jest najwolniejszym selektorem, jest stosowany tylko do dosłownie następnego rodzeństwa (+), a nie do całego łańcucha / drzewa, więc powinno to robić tylko nominalną różnicę.
Erik Philips
Selektory CSS @ErikPhilips są analizowane od prawej do lewej, więc jest to w rzeczywistości najgorszy scenariusz.
dudewad
@dudewad Myślę, że czegoś brakuje. *to najgorszy scenariusz, po którym następuje, element *ale element + *nie jest blisko dwóch pierwszych.
Erik Philips,
Nie wiem ... Nie testowałem tego, to jest oparte tylko na tym, co wiem o tym, jak parsery CSS robią swoje.
dudewad