-
Notifications
You must be signed in to change notification settings - Fork 27.2k
docs(core): improve viewEncapsulation documentation #44151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,37 @@ | ||
| # View encapsulation | ||
|
|
||
| In Angular, component CSS styles are encapsulated into the component's view and don't | ||
| affect the rest of the application. | ||
| In Angular, a component's styles can be encapsulated within the component's host element so that they don't affect the rest of the application. | ||
|
|
||
| The `Component`'s decorator provides the [`encapsulation`](api/core/Component#encapsulation) option which can be used to control how the encapsulation is applied on a _per component_ basis. | ||
|
|
||
| To control how this encapsulation happens on a _per | ||
| component_ basis, set the _view encapsulation mode_ in the component metadata. | ||
| Choose from the following modes: | ||
|
|
||
| - `ShadowDom` view encapsulation uses the browser's built-in shadow DOM implementation (see | ||
| [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)) | ||
| to attach a shadow DOM to the component's host element, and then puts the component | ||
| view inside that shadow DOM. The component's styles are included within the shadow DOM. | ||
| - `ViewEncapsulation.ShadowDom`, Angular uses the browser's built-in [Shadow DOM API](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)) to enclose the component's view inside a ShadowRoot (used as the component's host element) and apply the provided styles in an isolated manner. | ||
|
|
||
| - `ViewEncapsulation.Emulated`, Angular modifies the component's CSS selectors so that they are only applied to the component's view and do not affect other elements in the application (_emulating_ Shadow DOM behavior). For more details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css). | ||
|
|
||
| - `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing | ||
| (and renaming) the CSS code to effectively scope the CSS to the component's view. | ||
| For details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css). | ||
| - `ViewEncapsulation.None`, Angular does not apply any sort of view encapsulation meaning that any styles specified | ||
| for the component are actually globally applied and can affect any HTML element present within the application. | ||
| This mode is essentially the same as including the styles into the HTML itself. | ||
|
|
||
| - `None` means that Angular does no view encapsulation. | ||
| Angular adds the CSS to the global styles. | ||
| The scoping rules, isolations, and protections discussed earlier don't apply. | ||
| This mode is essentially the same as pasting the component's styles into the HTML. | ||
| <div class="alert is-important"> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe it should be
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't all browsers that we officially support have ShadowDOM support now?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the real reason we are still defaulting to emulated is that is makes it hard to pierce theming into the components because there is not a well lit path for how to do this with ShadowDOM. I think @jelbourn has more context here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes I wrote something similar in my comment below, happy to change this to whatever is preferred 🙂
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is fine unless @jelbourn (or anyone else has a view). |
||
|
|
||
| To set the component's encapsulation mode, use the `encapsulation` property in the component metadata: | ||
| `ViewEncapsulation.ShadowDom` only works on browsers that have built-in support | ||
| for the shadow DOM (see [Can I use - Shadow DOM v1](https://caniuse.com/shadowdomv1)). | ||
| Not all browsers support it, which is why the `ViewEncapsulation.Emulated` is the recommended and default mode. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed "The support is still limited" to "Not all browsers support it" because as you can see in the caniuse link the support is actually pretty good I think |
||
|
|
||
| <code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.shadow" header="src/app/quest-summary.component.ts"></code-example> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've removed the example as it didn't seem beneficial to me as:
|
||
| </div> | ||
|
|
||
| `ShadowDom` view encapsulation only works on browsers that have built-in support | ||
| for shadow DOM (see [Can I use - Shadow DOM v1](https://caniuse.com/shadowdomv1)). | ||
| The support is still limited, which is why `Emulated` view encapsulation is the default mode and recommended in most cases. | ||
|
|
||
| {@a inspect-generated-css} | ||
|
|
||
| ## Inspecting generated CSS | ||
|
|
||
| When using emulated view encapsulation, Angular preprocesses | ||
| all component styles so that they approximate the standard shadow CSS scoping rules. | ||
| When using the emulated view encapsulation, Angular pre-processes all the component's styles so that they are only applied to the component's view. | ||
|
|
||
| In the DOM of a running Angular application with emulated view | ||
| encapsulation enabled, each DOM element has some extra attributes | ||
| attached to it: | ||
| In the DOM of a running Angular application, elements belonging to components using emulated view encapsulation have some extra attributes attached to them: | ||
|
|
||
| <code-example format=""> | ||
| <code-example format="html" language="html"> | ||
| <hero-details _nghost-pmm-5> | ||
| <h2 _ngcontent-pmm-5>Mister Fantastic</h2> | ||
| <hero-team _ngcontent-pmm-5 _nghost-pmm-6> | ||
|
|
@@ -49,18 +40,16 @@ attached to it: | |
| </hero-detail> | ||
| </code-example> | ||
|
|
||
| There are two kinds of generated attributes: | ||
| There are two kinds of such attributes: | ||
|
|
||
| - `_nghost` attributes are added to elements that enclose a component's view and that would be ShadowRoots in a native Shadow DOM encapsulation. This is typically the case for components' host elements. | ||
| - `_ngcontent` attributes are added to child element within a component's view, those are used to match the elements with their respective emulated ShadowRoots (host elements with a matching `_nghost` attribute). | ||
|
|
||
| - An element that would be a shadow DOM host in native encapsulation has a | ||
| generated `_nghost` attribute. This is typically the case for component host elements. | ||
| - An element within a component's view has a `_ngcontent` attribute | ||
| that identifies to which host's emulated shadow DOM this element belongs. | ||
| The exact values of these attributes are a private implementation detail of Angular. They are automatically generated and you should never refer to them in application code. | ||
|
|
||
| The exact values of these attributes aren't important. They are automatically | ||
| generated and you should never refer to them in application code. But they are targeted | ||
| by the generated component styles, which are in the `<head>` section of the DOM: | ||
| They are targeted by the generated component styles, which are injected in the `<head>` section of the DOM: | ||
|
|
||
| <code-example format=""> | ||
| <code-example format="css" language="css"> | ||
| [_nghost-pmm-5] { | ||
| display: block; | ||
| border: 1px solid black; | ||
|
|
@@ -72,25 +61,29 @@ h3[_ngcontent-pmm-6] { | |
| } | ||
| </code-example> | ||
|
|
||
| These styles are post-processed so that each selector is augmented | ||
| with `_nghost` or `_ngcontent` attribute selectors. | ||
| These extra selectors enable the scoping rules described in this page. | ||
| These styles are post-processed so that each CSS selector is augmented with the appropriate `_nghost` or `_ngcontent` attribute. These modified selectors make sure the styles to be applied to components' views in an isolated and targeted fashion. | ||
|
|
||
| ## Mixing encapsulation modes | ||
|
|
||
| Avoid mixing components that use different view encapsulation. Where it is necessary, you should be aware of how the component styles will interact. | ||
| As previously mentioned you specify the encapsulation mode in the Component's decorator on a _per component_ basis, this means that within your application you can have different components using different encapsulation strategies. | ||
|
|
||
| Although possible, this is not recommended. If it is really needed you should be aware of how the styles of components using different encapsulation modes will interact with each other: | ||
|
|
||
| - The styles of components with `ViewEncapsulation.Emulated` are added to the `<head>` of the document, making them available throughout the application, but their selectors only affect elements within their respective components' templates. | ||
|
|
||
| - The styles of components with `ViewEncapsulation.None` are added to the `<head>` of the document, making them available throughout the application, so are completely global and affect any matching elements within the document. | ||
|
|
||
| - The styles of components with `ViewEncapsulation.Emulated` are added to the `<head>` of the document, making them available throughout the application, but are "scoped" so they only affect elements within the component's template. | ||
| - The styles of components with `ViewEncapsulation.ShadowDom` are only added to the shadow DOM host, ensuring that they only affect elements within their respective components' views. | ||
|
|
||
| - The styles of components with `ViewEncapsulation.None` are added to the `<head>` of the document, making them available throughout the application, and are not "scoped" so they can affect any element in the application. | ||
| <div class="alert is-helpful"> | ||
|
dario-piotrowicz marked this conversation as resolved.
|
||
|
|
||
| - The styles of components with `ViewEncapsulation.ShadowDom` are only added to the shadow DOM host, ensuring that they only affect elements within the component's template. | ||
| Styles of `ViewEncapsulation.Emulated` and `ViewEncapsulation.None` components are also added to the shadow DOM host of each `ViewEncapsulation.ShadowDom` component. | ||
|
|
||
| **All the styles for `ViewEncapsulation.Emulated` and `ViewEncapsulation.None` components are also added to the shadow DOM host of each `ViewEncapsulation.ShadowDom` component.** | ||
| This means that styles for components with `ViewEncapsulation.None` will affect matching elements within shadow DOMs. | ||
|
|
||
| The result is that styling for components with `ViewEncapsulation.None` will affect matching elements within the shadow DOM. | ||
| This approach may seem counter-intuitive at first, but without it a component with `ViewEncapsulation.None` would be rendered differently within a component using `ViewEncapsulation.ShadowDom`, since its styles would not be available. | ||
|
|
||
| This approach may seem counter-intuitive at first, but without it a component with `ViewEncapsulation.None` could not be used within a component with `ViewEncapsulation.ShadowDom`, since its styles would not be available. | ||
| </div> | ||
|
|
||
| ### Examples | ||
|
|
||
|
|
@@ -106,7 +99,7 @@ The first example shows a component that has `ViewEncapsulation.None`. This comp | |
|
|
||
| Angular adds the styles for this component as global styles to the `<head>` of the document. | ||
|
|
||
| **Angular also adds the styles to all shadow DOM hosts.** Therefore, the styles are available throughout the application. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was already mentioned above so I don't think there is a need to emphasise it |
||
| As already mentioned Angular also adds the styles to all shadow DOM hosts. Therefore, the styles are available throughout the whole application. | ||
|
|
||
| <img src="generated/images/guide/view-encapsulation/no-encapsulation.png" alt="component with no encapsulation"> | ||
|
|
||
|
|
@@ -116,14 +109,12 @@ The second example shows a component that has `ViewEncapsulation.Emulated`. This | |
|
|
||
| <code-example path="view-encapsulation/src/app/emulated-encapsulation.component.ts" header="src/app/emulated-encapsulation.component.ts"></code-example>> | ||
|
|
||
| Similar to `ViewEncapsulation.None`, Angular adds the styles for this component to the `<head>` of the document, and to all the shadow DOM hosts. | ||
| But in this case, the styles are "scoped" by the attributes described in ["Inspecting generated CSS"](#inspecting-generated-css). | ||
| Similar to `ViewEncapsulation.None`, Angular adds the styles for this component to the `<head>` of the document, but with "scoped" styles. | ||
|
|
||
| Therefore, only the elements directly within this component's template will match its styles. | ||
| Since the "scoped" styles from the `EmulatedEncapsulationComponent` are very specific, they override the global styles from the `NoEncapsulationComponent`. | ||
|
|
||
| In this example, the `EmulatedEncapsulationComponent` contains a `NoEncapsulationComponent`. | ||
| The `NoEncapsulationComponent` is styled as expected because the scoped styles do not match elements in its template. | ||
| In this example, the `EmulatedEncapsulationComponent` contains a `NoEncapsulationComponent`, but `NoEncapsulationComponent` is still styled as expected since the `EmulatedEncapsulationComponent`'s "scoped" styles do not match elements in its template. | ||
|
|
||
| <img src="generated/images/guide/view-encapsulation/emulated-encapsulation.png" alt="component with no encapsulation"> | ||
|
|
||
|
|
@@ -144,8 +135,8 @@ The styles added by the `ShadowDomEncapsulationComponent` component are availabl | |
| The `EmulatedEncapsulationComponent` has specific "scoped" styles, so the styling of this component's template is unaffected. | ||
|
|
||
| But since styles from `ShadowDomEncapsulationComponent` are added to the shadow host after the global styles, the `h2` style overrides the style from the `NoEncapsulationComponent`. | ||
| The result is that the `<h2>` element in the `NoEncapsulationComponent` is colored blue rather than red, which may not be what the component author intended. | ||
| The result is that the `<h2>` element in the `NoEncapsulationComponent` is colored blue rather than red, which may not be what the component's author intended. | ||
|
|
||
| <img src="generated/images/guide/view-encapsulation/shadow-dom-encapsulation.png" alt="component with no encapsulation"> | ||
|
|
||
| @reviewed 2021-09-17 | ||
| @reviewed 2021-11-10 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed this because as mentioned in this comment I feel like it is an unnecessary example