|
1 | 1 | # Customizing Angular Material component styles
|
2 | 2 |
|
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. |
4 | 6 |
|
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 |
7 | 8 |
|
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. |
11 | 35 |
|
12 | 36 | ### View encapsulation
|
13 | 37 |
|
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 |
18 | 42 | [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 |
20 | 44 | [_The State of CSS in Angular_](https://blog.angular.io/the-state-of-css-in-angular-4a52d4bd2700)
|
21 | 45 | on the Angular blog.
|
22 | 46 |
|
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 |
24 | 72 |
|
25 | 73 | 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 | + |
28 | 78 | You can read more about specificity and how it is calculated on the
|
29 | 79 | [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity).
|
30 | 80 |
|
31 |
| -### Component location |
| 81 | +### Rendering location |
32 | 82 |
|
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. |
38 | 88 |
|
39 |
| -## Styling overlay components |
| 89 | +#### Styling overlay components |
40 | 90 |
|
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`. |
43 | 93 |
|
44 | 94 | ```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; |
48 | 98 | }
|
49 | 99 | ```
|
50 | 100 |
|
51 | 101 | ```ts
|
52 |
| -this.dialog.open(MyDialogComponent, {panelClass: 'myapp-no-padding-dialog'}) |
| 102 | +this.dialog.open(MyDialogComponent, {panelClass: 'my-outlined-dialog'}) |
53 | 103 | ```
|
54 | 104 |
|
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