docs(core): improve viewEncapsulation documentation (#44151)

Slighlty improve the `viewEncapsulation` documentation (both in code
comments and content files) to make it more clear and understandable.

See https://github.com/angular/angular/pull/44099#discussion_r745890903

PR Close #44151
This commit is contained in:
dario-piotrowicz 2021-11-10 21:38:52 +00:00 committed by Jessica Janiuk
parent 2bf131a8a0
commit 6ae38584b0
6 changed files with 72 additions and 85 deletions

View file

@ -10,9 +10,3 @@ import { Component } from '@angular/core';
})
export class QuestSummaryComponent { }
// #enddocregion
/*
// #docregion encapsulation.shadow
// warning: not all browsers support shadow DOM encapsulation at this time
encapsulation: ViewEncapsulation.ShadowDom
// #enddocregion encapsulation.shadow
*/

View file

@ -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.
- `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.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).
- `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.
- `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.
To set the component's encapsulation mode, use the `encapsulation` property in the component metadata:
<div class="alert is-important">
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.shadow" header="src/app/quest-summary.component.ts"></code-example>
`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.
</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">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
@ -49,18 +40,16 @@ attached to it:
&lt;/hero-detail>
</code-example>
There are two kinds of generated attributes:
There are two kinds of such attributes:
- 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.
- `_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).
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:
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.
<code-example format="">
They are targeted by the generated component styles, which are injected in the `<head>` section of the DOM:
<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.
- 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.
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.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.
- 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.ShadowDom` are only added to the shadow DOM host, ensuring that they only affect elements within the component's template.
- 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.
**All the styles for `ViewEncapsulation.Emulated` and `ViewEncapsulation.None` components are also added to the shadow DOM host of each `ViewEncapsulation.ShadowDom` component.**
- 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 result is that styling for components with `ViewEncapsulation.None` will affect matching elements within the shadow DOM.
<div class="alert is-helpful">
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.
Styles of `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.
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.
</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.
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

View file

@ -177,7 +177,7 @@ export interface R3DeclareComponentMetadata extends R3DeclareDirectiveMetadata {
changeDetection?: ChangeDetectionStrategy;
/**
* An encapsulation policy for the template and CSS styles.
* An encapsulation policy for the component's styling.
* Defaults to `ViewEncapsulation.Emulated`.
*/
encapsulation?: ViewEncapsulation;

View file

@ -206,11 +206,12 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata {
styles: string[];
/**
* An encapsulation policy for the template and CSS styles. One of:
* - `ViewEncapsulation.Emulated`: Use shimmed CSS that emulates the native behavior.
* - `ViewEncapsulation.None`: Use global CSS without any encapsulation.
* - `ViewEncapsulation.ShadowDom`: Use the latest ShadowDOM API to natively encapsulate styles
* into a shadow root.
* An encapsulation policy for the component's styling.
* Possible values:
* - `ViewEncapsulation.Emulated`: Apply modified component styles in order to emulate
* a native Shadow DOM CSS encapsulation behavior.
* - `ViewEncapsulation.None`: Apply component styles globally without any sort of encapsulation.
* - `ViewEncapsulation.ShadowDom`: Use the browser's native Shadow DOM API to encapsulate styles.
*/
encapsulation: ViewEncapsulation;

View file

@ -516,18 +516,19 @@ export interface Component extends Directive {
animations?: any[];
/**
* An encapsulation policy for the template and CSS styles. One of:
* - `ViewEncapsulation.Emulated`: Use shimmed CSS that
* emulates the native behavior.
* - `ViewEncapsulation.None`: Use global CSS without any
* encapsulation.
* - `ViewEncapsulation.ShadowDom`: Use Shadow DOM v1 to encapsulate styles.
* An encapsulation policy for the component's styling.
* Possible values:
* - `ViewEncapsulation.Emulated`: Apply modified component styles in order to emulate
* a native Shadow DOM CSS encapsulation behavior.
* - `ViewEncapsulation.None`: Apply component styles globally without any sort of encapsulation.
* - `ViewEncapsulation.ShadowDom`: Use the browser's native Shadow DOM API to encapsulate styles.
*
* If not supplied, the value is taken from `CompilerOptions`. The default compiler option is
* `ViewEncapsulation.Emulated`.
* If not supplied, the value is taken from the `CompilerOptions`
* which defaults to `ViewEncapsulation.Emulated`.
*
* If the policy is set to `ViewEncapsulation.Emulated` and the component has no `styles`
* or `styleUrls` specified, the policy is automatically switched to `ViewEncapsulation.None`.
* If the policy is `ViewEncapsulation.Emulated` and the component has no
* {@link Component#styles styles} nor {@link Component#styleUrls styleUrls},
* the policy is automatically switched to `ViewEncapsulation.None`.
*/
encapsulation?: ViewEncapsulation;

View file

@ -7,7 +7,8 @@
*/
/**
* Defines template and style encapsulation options available for Component's {@link Component}.
* Defines the CSS styles encapsulation policies for the {@link Component} decorator's
* `encapsulation` option.
*
* See {@link Component#encapsulation encapsulation}.
*
@ -23,10 +24,9 @@ export enum ViewEncapsulation {
// https://github.com/angular/angular/issues/44119 for additional information.
/**
* Emulate `Native` scoping of styles by adding an attribute containing surrogate id to the Host
* Element and pre-processing the style rules provided via {@link Component#styles styles} or
* {@link Component#styleUrls styleUrls}, and adding the new Host Element attribute to all
* selectors.
* Emulates a native Shadow DOM encapsulation behavior by adding a specific attribute to the
* component's host element and applying the same attribute to all the CSS selectors provided
* via {@link Component#styles styles} or {@link Component#styleUrls styleUrls}.
*
* This is the default option.
*/
@ -35,16 +35,16 @@ export enum ViewEncapsulation {
// Historically the 1 value was for `Native` encapsulation which has been removed as of v11.
/**
* Don't provide any template or style encapsulation.
* Doesn't provide any sort of CSS style encapsulation, meaning that all the styles provided
* via {@link Component#styles styles} or {@link Component#styleUrls styleUrls} are applicable
* to any HTML element of the application regardless of their host Component.
*/
None = 2,
/**
* Use Shadow DOM to encapsulate styles.
*
* For the DOM this means using modern [Shadow
* DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) and
* creating a ShadowRoot for Component's Host Element.
* Uses the browser's native Shadow DOM API to encapsulate CSS styles, meaning that it creates
* a ShadowRoot for the component's host element which is then used to encapsulate
* all the Component's styling.
*/
ShadowDom = 3
}