Was anstelle von :: ng-deep zu verwenden ist

97

Ich versuche, ein vom Router-Ausgang platziertes Element in einem Winkel zu gestalten und möchte sicherstellen, dass das generierte Element eine Breite von 100% erhält

Aus den meisten Antworten geht hervor, dass ich den ::ng-deepSelektor verwenden sollte, aber aus Angulars Dokumenten wird er nicht mehr empfohlen. Gibt es eine Alternative zu ::ng-deep?

Jacob Schwartz
quelle
2
::ng-deepgeht nirgendwo hin. Es wird immer eine Einstellung sein, die Sie aktivieren können. Es gibt absolut keine Möglichkeit, es jetzt ohne massive Community-Gegenreaktionen zu entfernen. Schauen Sie sich an, wie viele Ergebnisse für diese Suche zurückkommen. Github.com/search?q=%3A%3Ang-deep&type=Code - es ist, als würde man sagen, dass die CSS- !importantEigenschaft verschwinden wird
Simon_Weaver
Ich weiß nicht - ich habe aus Neugier eine projektweite Suche in unserem Mono-Repo (mehrere ziemlich große Unternehmensanwendungen) durchgeführt und nur 69 Referenzen herausgebracht. Ich bin der Meinung, dass dies definitiv ein akzeptabler Refaktor ist, um aus der Abwertung herauszukommen, und würde es gerne tun, wenn sie die Alternative herausbringen. Außerdem !importanthat es einen wichtigen Platz in der CSS-Spezifikation, während ::deepes immer nur ein Vorschlag war.
Dudewad

Antworten:

108

FWIW In meiner Forschung habe ich keinen Ersatz für ng-deep oder die anderen anwendbaren Alternativen gefunden. Dies liegt daran, dass das Angular-Team meines Erachtens auf die W3C-Spezifikation für den Schattendom zurückgreift, für die ursprünglich Selektoren wie z deep. Der W3c hat die Empfehlung jedoch inzwischen entfernt, aber nicht durch eine neue ersetzt. Bis dahin stelle ich mir vor, dass das Angular-Team ::ng-deepdie verfügbaren Alternativen beibehalten und verfügbar machen wird, jedoch aufgrund des anstehenden Zustands der W3C-Entwürfe in einem veralteten Zustand. Ich kann mir momentan nicht die Zeit nehmen, die Dokumentation zu finden, um dies zu sichern, aber ich habe sie kürzlich gesehen.

Lange Rede, kurzer Sinn: Verwenden Sie ::ng-deepund seine Alternativen weiter, bis ein Ersatz erstellt wird - die Abwertung ist nur eine frühe Benachrichtigung, damit die Leute nicht blind sind, wenn die tatsächliche Änderung eintritt.

- UPDATE -

https://drafts.csswg.org/css-scoping-1/ Hier ist der Entwurf des Vorschlags, wenn Sie interessiert sind. Es scheint, dass sie an einem robusten Satz von Selektoren für Elemente innerhalb eines Schattendom-Baums arbeiten. Es ist diese Spezifikation, die nach ihrer Genehmigung den Winkelklon informiert, falls es überhaupt eine gibt (dh Winkel muss möglicherweise keine eigenen Selektoren implementieren, sobald diese in Browsern verfügbar sind).

Dudewad
quelle
Ich bin damit einverstanden, würde jedoch nicht empfehlen, neuen Code gezielt mit veralteten Framework- (und Browser-) Funktionen zu schreiben.
MT_
7
Beides würde ich. Aber es gibt keine Alternative, die meiner Meinung nach hier fälschlicherweise klar umrissen ist. Haben Sie Vorschläge, um dabei zu helfen?
Dudewad
1
Die einzige Alternative, an die ich schnell denken kann, wäre die Umgestaltung der Verschachtelung von Komponenten.
Dies ist
35
Mit einer Bibliothek eines Drittanbieters ist es praktisch unmöglich, die gelegentliche Verwendung zu vermeiden ::ng-deep(wenn Sie sich überhaupt für das Aussehen Ihrer Website interessieren) - selbst bei etwas wie eckigem Material. Sie haben Fehler, die seit Monaten nicht mehr behoben wurden, und Problemumgehungen betreffen häufig ng-deep. Und verwechseln Sie nicht die verschiedenen veralteten "tiefen" Selektoren - es ::ng-deepist definitiv die am wenigsten veraltete.
Simon_Weaver
1
Ja, das ist einer der hässlichsten Teile des gesamten Systems. Aber Kapselung ist das, was Kapselung ist. Sie müssen die Grenze entweder durch explizite Verwendung von :: ng-deep in CSS durchbrechen oder Sie müssen dies programmgesteuert tun. Manchmal verwenden wir ein Attribut auf dem Komponenten-Tag, um anzugeben, in welchem ​​"Modus" sich eine Komponente befindet (dh im Kontext), und dann können die Stile in der untergeordneten Komponente w / o :: ng-deep über einen Attributselektor wie: :host[some-context] {}- it leben hängt davon ab, welche Art von Flexibilität / Portabilität Sie wünschen. Ich mag so oder so nicht super, aber das ist die Welt der Verkapselung.
Dudewad
22

Um das Veraltete zu umgehen ::ng-deep, deaktiviere ich normalerweise ViewEncapsulation. Obwohl dies nicht der beste Ansatz ist, hat er mir gute Dienste geleistet.

Gehen Sie zum Deaktivieren ViewEncapsulationin Ihrer Komponente wie folgt vor:

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

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

export class HeaderComponent {

}

Dadurch werden die .scss-Stile in dieser Komponente für die gesamte Anwendung global. Um nicht zuzulassen, dass die Stile die Kette zu übergeordneten und geschwisterlichen Komponenten hinaufgehen, wickeln Sie den gesamten scss wie folgt mit dem Selektor ein:

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

Die hier angegebenen Stile werden nun auf untergeordnete Komponenten übertragen, sodass Sie beim Hinzufügen von CSS besonders auf Ihre CSS-Selektoren achten und auf Ihre Ps und Qs achten müssen (fügen Sie möglicherweise die in Ihrer Angular-App angegebene untergeordnete Auswahl und dann deren Stile hinzu).

Ich sage, es ist aufgrund des obigen Absatzes nicht der beste Ansatz, aber das hat mir gute Dienste geleistet.

AliF50
quelle
12
Dies ist nur eine Problemumgehung. Wenn Sie ein großes Projekt haben, verursacht das Ausschalten ViewEncapsulationgroßen Schaden, da diese Stile in alle Komponenten eindringen können. Diese Funktion sollte mit Bedacht und mit vollem Verständnis verwendet werden
mpro
5
@mpro Ich verstehe, deshalb habe ich den Vorbehalt gegeben und gesagt, dies ist nicht der beste Ansatz, und Sie müssen auf Ihre Ps und Qs achten und besonders spezifisch sein. Für mich hat dieser Ansatz bisher gut funktioniert. :: ng-deep ist als veraltet markiert und dies ist eine Problemumgehung.
AliF50
1
Ehrlich gesagt denke ich, dass dies eine schreckliche Schlussfolgerung ist, wenn Sie dies wegen drohender Abwertung getan haben. Ja, ich weiß, dass Sie das anerkennen, aber ich denke wirklich, dass Sie sich damit in den Fuß schießen. Die Ansichtskapselung ist aus vielen Gründen so nützlich. Es ist jedoch bei weitem nicht so schlimm, wie wer auch immer im eckigen Team es ohne logische Problemumgehung ablehnte und viele zu viel Verwirrung führte. Am Ende des Tages schreiben Sie immer noch Code für einen Webbrowser - keine proprietäre Winkel-Engine.
Simon_Weaver
2
@ Simon_Weaver Ich respektiere Ihre Meinung und danke für das Teilen. Ich tauche nur auf, weil ich damit die Abwertung umgangen habe. Ich habe auch die Vorbehalte aufgetaucht.
AliF50
3
@ AliF50 "Umgehung der Korrektur" ist nicht wirklich eine Sache. Das eigentliche Problem hier ist, dass, und ich habe das noch nie in meinem Leben gesehen, sie es abgelehnt haben, ohne eine Alternative zu nennen . Meine Antwort (die oben akzeptierte) erklärt meine Hypothese, warum sie das (W3C veraltet) getan haben, um mit der Spezifikation übereinzustimmen. Wenn Sie jedoch die Vorschläge lesen, sieht es so aus, als würde :: ng-deep durch eine geeignete Alternative ersetzt. Wenn diese verfügbar ist, aktualisieren Sie einfach Ihre :: ng-deep-Referenzen und nicht Ihren Ansatz, der buchstäblich erforderlich ist Neuarchitektur der gesamten Anwendung.
Dudewad
17

Die einfache Alternative zu einem tiefen Stil ist ein gängiger Stil, bei dem die Elementauswahl der übergeordneten Komponente verwendet wird. Also, wenn Sie dies in hero-details.component.css hatten:

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

Es würde dies in styles.css werden:

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

Grundsätzlich ist ein tiefer Stil ein nicht gekapselter Stil, daher scheint er mir konzeptionell eher ein allgemeiner Stil als ein Komponentenstil zu sein. Persönlich würde ich keine tiefen Stile mehr verwenden. Brechende Änderungen sind bei wichtigen Versionsaktualisierungen normal und das Entfernen veralteter Funktionen ist ein faires Spiel.

J. Lenthe
quelle
1
Wow, ich fühle mich jetzt dumm. Vielen Dank! Aus anderen Front-End-Frameworks stammend, hielt ich dies für unmöglich
Rafael Vidaurre
1
Das ist wirklich nützlich. Es ist schade, dass :: ng-deep so lange ohne Ersatz veraltet war (: host :: ng-deep funktioniert wie erwartet, aber ich möchte keine veralteten Sachen verwenden).
Alexei
7

Wie bereits erwähnt, ist es bei Verwendung einer Bibliothek eines Drittanbieters praktisch unmöglich, die gelegentliche Verwendung zu vermeiden ::ng-deep. Aber was machen Sie mit Ihren vorherigen Projekten, wenn diese ::ng-deepvon Browsern nicht mehr unterstützt werden?

Um für diesen Moment bereit zu sein, werde ich Folgendes vorschlagen:

  1. Verwenden Sie ViewEncapsulation.None mit Bedacht. Dies gilt nur für diejenigen Komponenten, die auf tiefere Komponenten zugreifen müssen.
@Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.scss'],
      encapsulation: ViewEncapsulation.None
    })
  1. Um Kollisionen und CSS-Verrücktheiten zu vermeiden, sollten Sie die Vorlage Ihrer Komponente (in der Regel) immer mit einer Klasse umschließen. Beispiel.component.html sollte also wie folgt aussehen:
<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. Wiederum zielt die erste Zeile jeder einzelnen SCSS-Datei in der Regel auf den Komponentencontainer ab. Da es keine Kapselung gibt, können Sie die Komponente eines Drittanbieters ändern, indem Sie auf deren Klassen abzielen. Das heißt, example.component.scss sollte wie folgt aussehen:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}

Eine Selbstnotiz für die Zukunft: https://angular.io/guide/component-styles
Dies sollte der erste Ort sein, an dem nach offiziellen Alternativen / Wegen gesucht werden kann

guzmanoj
quelle
But what are you going to do about your previous projects when the ::ng-deep became no longer supported by browsers?Wird das nicht von Angular Cli kompiliert / polygefüllt, sodass keine Browserbeteiligung vorliegt? Tolle Antwort übrigens.
beppe9000
Das wird tatsächlich in die CSS-Datei gerendert, und dann wendet der Browser die Stile entsprechend an. Aliasing ist möglich (ich denke), :host /deep/ .mat-tab-labelwenn dies verwendet wird, sollte in umgewandelt werden ::ng-deep. Um ehrlich zu sein, scheint die Verwendung des Alias ​​bequemer zu sein, da die CLI ihn während der Kompilierungszeit ändern kann. Sie müssen ihn jedoch ng builderneut ausführen und erneut bereitstellen. Mein Vorsatz war es, ::ng-deepbei all meinen Projekten überhaupt zu vermeiden :)
guzmanoj
Ja, es ist sinnvoll, eine erneute Bereitstellung zu vermeiden
beppe9000
1

Dies ist kein allgemeiner Ersatz für :: ng-deep, sondern für den vom Fragesteller beschriebenen Anwendungsfall:

In dem speziellen Fall, in dem Sie das von einem Router-Ausgang eingefügte Element formatieren möchten, gibt es eine elegante Lösung, die den Selektor für benachbarte Nachbarn in CSS verwendet:

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

Dies gilt für alle Elemente, die direkte Nachbarn einer Router-Steckdose sind.

Weitere Informationen:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet

mrm1st3r
quelle
1
Ich würde die Verwendung dieses Selektors nicht empfehlen. Dies scheint, als würden Sie einen regelrechten Albtraum von Kollisionen auslösen, insbesondere wenn Ihre Anwendung wächst. Darüber hinaus ist der * Selektor buchstäblich der langsamste Selektor in der CSS-Existenz.
Dudewad
@dudewad Während der * Selektor der langsamste Selektor ist, wird er buchstäblich nur auf das nächste Geschwister (+) angewendet, nicht auf die gesamte Kette / den gesamten Baum, daher sollte er nur einen nominellen Unterschied machen.
Erik Philips
@ErikPhilips CSS-Selektoren werden von rechts nach links analysiert, sodass dies tatsächlich ein Worst-Case-Szenario ist.
Dudewad
@dudewad Ich denke, wir vermissen etwas. *ist das Worst-Case-Szenario, dicht gefolgt vonelement * aber element + *nicht , wo in der Nähe der ersten beiden.
Erik Philips
Ich weiß nicht ... Ich habe es nicht getestet, dies basiert nur auf dem, was ich darüber weiß, wie CSS-Parser ihr Ding machen.
Dudewad