Skip to content

Commit 52ac1e4

Browse files
authored
docs(material/theming): revise customizing-component-styles (#22466)
This change updates the customizing-component-styles doc to give more specific guidance on overriding component styles. In particular: * Much stronger language to make it clear that this is not supported or recommended. * Reorganize content such that topics have a bit more cohesion/flow * Call out that layout/positioning styles on host elements are the only safe styles to apply. * Emphasize the perils of overrides in general
1 parent 3e4e6d0 commit 52ac1e4

File tree

1 file changed

+79
-46
lines changed

1 file changed

+79
-46
lines changed
Lines changed: 79 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,106 @@
11
# Customizing Angular Material component styles
22

3-
## Styling concepts
3+
Angular Material supports customizing component styles via Sass API as described in the [theming
4+
guide][]. This document provides guidance on defining custom CSS rules that directly style
5+
Angular Material components.
46

5-
There are 3 questions to keep in mind while customizing the styles of Angular Material
6-
components:
7+
[theming guide]: https://material.angular.io/guide/theming
78

8-
1. Are your styles encapsulated?
9-
2. Are your styles more specific than the defaults?
10-
3. Is the component a child of your component, or does it exist elsewhere in the DOM?
9+
## Targeting custom styles
10+
11+
### Component host elements
12+
13+
For any Angular Material component, you can safely define custom CSS for a component's host element
14+
that affect the positioning or layout of that component, such as `margin`, `position`, `top`,
15+
`left`, `transform`, and `z-index`. You should apply such styles by defining a custom CSS
16+
class and applying that class to the component's host element.
17+
18+
Avoid defining custom styles that would affect the size or internal layout of the component, such as
19+
`padding`, `height`, `width`, or `overflow`. You can specify `display: none` to hide a component,
20+
but avoid specifying any other `display` value. Overriding these properties can break components
21+
in unexpected ways as the internal styles change between releases.
22+
23+
### Internal component elements
24+
25+
Avoid any custom styles or overrides on internal elements within a Angular Material components.
26+
The DOM structure and CSS classes applied for each component may change at any time, causing custom
27+
styles to break.
28+
29+
## Applying styles to Angular Material components
30+
31+
While Angular Material does not support defining custom styles or CSS overrides on components'
32+
internal elements, you might choose to do this anyway. There are three points to consider while
33+
customizing styles for Angular Material components: view encapsulation, CSS specificity, and
34+
rendering location.
1135

1236
### View encapsulation
1337

14-
By default, Angular component styles are scoped to affect the component's view. This means that
15-
the styles you write will affect all the elements in your component template. They will *not*
16-
affect elements that are children of other components within your template. You can read more
17-
about view encapsulation in the
38+
By default, Angular scopes component styles to exclusively affect that component's view. This means
39+
that the styles you author affect only the elements directly within your component template.
40+
Encapsulated styles do *not* affect elements that are children of other components within your
41+
template. You can read more about view encapsulation in the
1842
[Angular documentation](https://angular.io/guide/component-styles#view-encapsulation). You may
19-
also wish to take a look at
43+
also wish to review
2044
[_The State of CSS in Angular_](https://blog.angular.io/the-state-of-css-in-angular-4a52d4bd2700)
2145
on the Angular blog.
2246

23-
### Selector specificity
47+
#### Bypassing encapsulation
48+
49+
Angular Material disables style encapsulation for all components in the library. However, the
50+
default style encapsulation in your own components still prevents custom styles from leaking into
51+
Angular Material components.
52+
53+
If your component enables view encapsulation, your component styles will only
54+
affect the elements explicitly defined in your template. To affect descendants of components used
55+
in your template, you can use one of the following approaches:
56+
57+
1. Define custom styles in a global stylesheet declared in the `styles` array of your `angular.json`
58+
configuration file.
59+
2. Disable view encapsulation for your component. This approach effectively turns your component
60+
styles into global CSS.
61+
3. Apply the deprecated `::ng-deep` pseudo-class to a CSS rule. Any CSS rule with `::ng-deep`
62+
becomes a global style. [See the Angular documentation for more on `::ng-deep`][ng-deep].
63+
64+
All of these approaches involve creating global CSS that isn't affected by style encapsulation.
65+
Global CSS affects all elements in your application. Global CSS class names may collide with class
66+
names defined by components. Global CSS is often a source of hard-to-diagnose bugs and is generally
67+
difficult to maintain.
68+
69+
[ng-deep]: https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep
70+
71+
### CSS specificity
2472

2573
Each CSS declaration has a level of *specificity* based on the type and number of selectors used.
26-
More specific styles will take precedence over less specific styles. Angular Material uses the
27-
least specific selectors possible for its components in order to make it easy to override them.
74+
More specific styles take precedence over less specific styles. Angular Material generally attempts
75+
to use the least specific selectors possible. However, Angular Material may change component style
76+
specificity at any time, making custom overrides brittle and prone to breaking.
77+
2878
You can read more about specificity and how it is calculated on the
2979
[MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity).
3080

31-
### Component location
81+
### Rendering location
3282

33-
Some Angular Material components, specifically overlay-based one's like MatDialog, MatSnackbar, etc.,
34-
do not exist as children of your component. Often they are injected elsewhere in the DOM. This is
35-
important to keep in mind, since even using high specificity and shadow-piercing selectors will
36-
not target elements that are not direct children of your component. Global styles are recommended
37-
for targeting such components.
83+
Some Angular Material components render elements that are not direct DOM descendants of the
84+
component's host element. In particular, overlay-based components such as `MatDialog`, `MatMenu`,
85+
`MatTooltip`, etc. render into an overlay container element directly on the document body. Because
86+
these components render elements outside of your application's components, component-specific styles
87+
will not apply to these elements. You can define styles for these elements as global styles.
3888

39-
## Styling overlay components
89+
#### Styling overlay components
4090

41-
Overlay-based components have a `panelClass` property (or similar) that can be used to target the
42-
overlay pane. For example, to remove the padding from a dialog:
91+
Overlay-based components have a `panelClass` property, or similar, that let you target the
92+
overlay pane. The following example shows how to add an `outline` style with `MatDialog`.
4393

4494
```scss
45-
// Add this to your global stylesheet after your theme setup
46-
.myapp-no-padding-dialog .mat-dialog-container {
47-
padding: 0;
95+
// Add this to your global stylesheet after including theme mixins.
96+
.my-outlined-dialog {
97+
outline: 2px solid purple;
4898
}
4999
```
50100

51101
```ts
52-
this.dialog.open(MyDialogComponent, {panelClass: 'myapp-no-padding-dialog'})
102+
this.dialog.open(MyDialogComponent, {panelClass: 'my-outlined-dialog'})
53103
```
54104

55-
Since you are adding the styles to your global stylesheet, it is a good practice to scope
56-
them appropriately. Try prefixing your selector with your app name or "custom". Also note that
57-
the `mat-dialog-container`'s padding is added by default via a selector with specificity of 1. The
58-
customizing styles have a specificity of 2, so they will always take precedence.
59-
60-
## Styling other components
61-
62-
If your component has view encapsulation turned on (default), your component styles will only
63-
affect the top level children in your template. HTML elements belonging to child components cannot
64-
be targeted by your component styles unless you do one of the following:
65-
66-
- Add the overriding style to your global stylesheet. Scope the selectors so that it only affects
67-
the specific elements you need it to.
68-
- Turn view encapsulation off on your component. If you do this, be sure to scope your styles
69-
appropriately, or else you may end up incidentally targeting other components elsewhere in your
70-
application.
71-
- Use a deprecated shadow-piercing descendant combinator to force styles to apply to all the child
72-
elements. Read more about this deprecated solution in the
73-
[Angular documentation](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep).
105+
You should always apply an application-specific prefix to global CSS classes to avoid naming
106+
collisions.

0 commit comments

Comments
 (0)