-
Notifications
You must be signed in to change notification settings - Fork 6.8k
docs(material/theming): revise customizing-component-styles #22466
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,73 +1,106 @@ | ||||||
# Customizing Angular Material component styles | ||||||
|
||||||
## Styling concepts | ||||||
Angular Material supports customizing component styles via Sass API as described in the [theming | ||||||
guide][]. This document provides guidance on defining custom CSS rules that directly style | ||||||
Angular Material components. | ||||||
|
||||||
There are 3 questions to keep in mind while customizing the styles of Angular Material | ||||||
components: | ||||||
[theming guide]: https://material.angular.io/guide/theming | ||||||
|
||||||
1. Are your styles encapsulated? | ||||||
2. Are your styles more specific than the defaults? | ||||||
3. Is the component a child of your component, or does it exist elsewhere in the DOM? | ||||||
## Targeting custom styles | ||||||
|
||||||
### Component host elements | ||||||
|
||||||
For any Angular Material component, you can safely define custom CSS for a component's host element | ||||||
that affect the positioning or layout of that component, such as `margin`, `position`, `top`, | ||||||
`left`, `transform`, and `z-index`. You should apply such styles by defining a custom CSS | ||||||
class and applying that class to the component's host element. | ||||||
|
||||||
Avoid defining custom styles that would affect the size or internal layout of the component, such as | ||||||
`padding`, `height`, `width`, or `overflow`. You can specify `display: none` to hide a component, | ||||||
but avoid specifying any other `display` value. Overriding these properties can break components | ||||||
in unexpected ways as the internal styles change between releases. | ||||||
|
||||||
### Internal component elements | ||||||
|
||||||
Avoid any custom styles or overrides on internal elements within a Angular Material components. | ||||||
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.
Suggested change
Removed stray word. |
||||||
The DOM structure and CSS classes applied for each component may change at any time, causing custom | ||||||
styles to break. | ||||||
|
||||||
## Applying styles to Angular Material components | ||||||
|
||||||
While Angular Material does not support defining custom styles or CSS overrides on components' | ||||||
internal elements, you might choose to do this anyway. There are three points to consider while | ||||||
customizing styles for Angular Material components: view encapsulation, CSS specificity, and | ||||||
rendering location. | ||||||
|
||||||
### View encapsulation | ||||||
|
||||||
By default, Angular component styles are scoped to affect the component's view. This means that | ||||||
the styles you write will affect all the elements in your component template. They will *not* | ||||||
affect elements that are children of other components within your template. You can read more | ||||||
about view encapsulation in the | ||||||
By default, Angular scopes component styles to exclusively affect that component's view. This means | ||||||
that the styles you author affect only the elements directly within your component template. | ||||||
Encapsulated styles do *not* affect elements that are children of other components within your | ||||||
template. You can read more about view encapsulation in the | ||||||
[Angular documentation](https://angular.io/guide/component-styles#view-encapsulation). You may | ||||||
also wish to take a look at | ||||||
also wish to review | ||||||
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.
Suggested change
The developer documentation style guide says to avoid this term. |
||||||
[_The State of CSS in Angular_](https://blog.angular.io/the-state-of-css-in-angular-4a52d4bd2700) | ||||||
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. We're probably due for an update on The State of CSS in Angular with these new changes, this article is a bit dated (both date and content). 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. Yeah, we should probably update our guidance once we drop IE11 support and we can throw our weight behind css variables (and maybe constructible stylesheets will be a thing by then, too) |
||||||
on the Angular blog. | ||||||
|
||||||
### Selector specificity | ||||||
#### Bypassing encapsulation | ||||||
|
||||||
Angular Material disables style encapsulation for all components in the library. However, the | ||||||
default style encapsulation in your own components still prevents custom styles from leaking into | ||||||
Angular Material components. | ||||||
|
||||||
If your component enables view encapsulation, your component styles will only | ||||||
affect the elements explicitly defined in your template. To affect descendants of components used | ||||||
in your template, you can use one of the following approaches: | ||||||
|
||||||
1. Define custom styles in a global stylesheet declared in the `styles` array of your `angular.json` | ||||||
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.
Suggested change
Two words |
||||||
configuration file. | ||||||
2. Disable view encapsulation for your component. This approach effectively turns your component | ||||||
styles into global CSS. | ||||||
3. Apply the deprecated `::ng-deep` pseudo-class to a CSS rule. Any CSS rule with `::ng-deep` | ||||||
becomes a global style. [See the Angular documentation for more on `::ng-deep`][ng-deep]. | ||||||
|
||||||
All of these approaches involve creating global CSS that isn't affected by style encapsulation. | ||||||
Global CSS affects all elements in your application. Global CSS class names may collide with class | ||||||
names defined by components. Global CSS is often a source of hard-to-diagnose bugs and is generally | ||||||
difficult to maintain. | ||||||
|
||||||
[ng-deep]: https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep | ||||||
|
||||||
### CSS specificity | ||||||
|
||||||
Each CSS declaration has a level of *specificity* based on the type and number of selectors used. | ||||||
More specific styles will take precedence over less specific styles. Angular Material uses the | ||||||
least specific selectors possible for its components in order to make it easy to override them. | ||||||
More specific styles take precedence over less specific styles. Angular Material generally attempts | ||||||
to use the least specific selectors possible. However, Angular Material may change component style | ||||||
specificity at any time, making custom overrides brittle and prone to breaking. | ||||||
|
||||||
You can read more about specificity and how it is calculated on the | ||||||
[MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity). | ||||||
|
||||||
### Component location | ||||||
### Rendering location | ||||||
|
||||||
Some Angular Material components, specifically overlay-based one's like MatDialog, MatSnackbar, etc., | ||||||
do not exist as children of your component. Often they are injected elsewhere in the DOM. This is | ||||||
important to keep in mind, since even using high specificity and shadow-piercing selectors will | ||||||
not target elements that are not direct children of your component. Global styles are recommended | ||||||
for targeting such components. | ||||||
Some Angular Material components render elements that are not direct DOM descendants of the | ||||||
component's host element. In particular, overlay-based components such as `MatDialog`, `MatMenu`, | ||||||
`MatTooltip`, etc. render into an overlay container element directly on the document body. Because | ||||||
these components render elements outside of your application's components, component-specific styles | ||||||
will not apply to these elements. You can define styles for these elements as global styles. | ||||||
|
||||||
## Styling overlay components | ||||||
#### Styling overlay components | ||||||
|
||||||
Overlay-based components have a `panelClass` property (or similar) that can be used to target the | ||||||
overlay pane. For example, to remove the padding from a dialog: | ||||||
Overlay-based components have a `panelClass` property, or similar, that let you target the | ||||||
overlay pane. The following example shows how to add an `outline` style with `MatDialog`. | ||||||
|
||||||
```scss | ||||||
// Add this to your global stylesheet after your theme setup | ||||||
.myapp-no-padding-dialog .mat-dialog-container { | ||||||
padding: 0; | ||||||
// Add this to your global stylesheet after including theme mixins. | ||||||
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.
Suggested change
Two words |
||||||
.my-outlined-dialog { | ||||||
outline: 2px solid purple; | ||||||
} | ||||||
``` | ||||||
|
||||||
```ts | ||||||
this.dialog.open(MyDialogComponent, {panelClass: 'myapp-no-padding-dialog'}) | ||||||
this.dialog.open(MyDialogComponent, {panelClass: 'my-outlined-dialog'}) | ||||||
``` | ||||||
|
||||||
Since you are adding the styles to your global stylesheet, it is a good practice to scope | ||||||
them appropriately. Try prefixing your selector with your app name or "custom". Also note that | ||||||
the `mat-dialog-container`'s padding is added by default via a selector with specificity of 1. The | ||||||
customizing styles have a specificity of 2, so they will always take precedence. | ||||||
|
||||||
## Styling other components | ||||||
|
||||||
If your component has view encapsulation turned on (default), your component styles will only | ||||||
affect the top level children in your template. HTML elements belonging to child components cannot | ||||||
be targeted by your component styles unless you do one of the following: | ||||||
|
||||||
- Add the overriding style to your global stylesheet. Scope the selectors so that it only affects | ||||||
the specific elements you need it to. | ||||||
- Turn view encapsulation off on your component. If you do this, be sure to scope your styles | ||||||
appropriately, or else you may end up incidentally targeting other components elsewhere in your | ||||||
application. | ||||||
- Use a deprecated shadow-piercing descendant combinator to force styles to apply to all the child | ||||||
elements. Read more about this deprecated solution in the | ||||||
[Angular documentation](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep). | ||||||
You should always apply an application-specific prefix to global CSS classes to avoid naming | ||||||
collisions. |
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.