diff --git a/aio/content/examples/component-styles/src/app/quest-summary.component.ts b/aio/content/examples/component-styles/src/app/quest-summary.component.ts index 418937182b42..c50bee777f55 100644 --- a/aio/content/examples/component-styles/src/app/quest-summary.component.ts +++ b/aio/content/examples/component-styles/src/app/quest-summary.component.ts @@ -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 -*/ diff --git a/aio/content/guide/view-encapsulation.md b/aio/content/guide/view-encapsulation.md index c4a12073f4bc..e531edd7139d 100644 --- a/aio/content/guide/view-encapsulation.md +++ b/aio/content/guide/view-encapsulation.md @@ -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. +
-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. - +
-`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: - + <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> -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 `` section of the DOM: +They are targeted by the generated component styles, which are injected in the `` section of the DOM: - + [_nghost-pmm-5] { display: block; border: 1px solid black; @@ -72,25 +61,29 @@ h3[_ngcontent-pmm-6] { } -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 `` 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 `` 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 `` 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 `` 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.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. +
### 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 `` 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. component with no encapsulation @@ -116,14 +109,12 @@ The second example shows a component that has `ViewEncapsulation.Emulated`. This > -Similar to `ViewEncapsulation.None`, Angular adds the styles for this component to the `` 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 `` 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. 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 `

` element in the `NoEncapsulationComponent` is colored blue rather than red, which may not be what the component author intended. +The result is that the `

` element in the `NoEncapsulationComponent` is colored blue rather than red, which may not be what the component's author intended. component with no encapsulation -@reviewed 2021-09-17 +@reviewed 2021-11-10 diff --git a/packages/compiler/src/render3/partial/api.ts b/packages/compiler/src/render3/partial/api.ts index 3009c773715b..03f5428d1629 100644 --- a/packages/compiler/src/render3/partial/api.ts +++ b/packages/compiler/src/render3/partial/api.ts @@ -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; diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 64c7cc29efe8..c12ec91acf20 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -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; diff --git a/packages/core/src/metadata/directives.ts b/packages/core/src/metadata/directives.ts index 660b1d72d795..25f8103aef38 100644 --- a/packages/core/src/metadata/directives.ts +++ b/packages/core/src/metadata/directives.ts @@ -517,18 +517,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. - * - * If not supplied, the value is taken from `CompilerOptions`. The default compiler option is - * `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`. + * 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 the `CompilerOptions` + * which defaults to `ViewEncapsulation.Emulated`. + * + * 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; diff --git a/packages/core/src/metadata/view.ts b/packages/core/src/metadata/view.ts index 5cc72c69662c..04838345b191 100644 --- a/packages/core/src/metadata/view.ts +++ b/packages/core/src/metadata/view.ts @@ -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 }