Easy Way to Overwrite All Elements in an Array
3 Correct Ways To Overwrite Angular Material Styles
Create beautiful components for your web apps
In the initial stages of each project, every frontend developer always faces the question of whether or not to use the UI component library.
Nowadays, there are plenty of UI libraries available on the market that enhance and facilitate our development process. Among the most popular ones, we can identify Angular Material, Ngxbootstrap, Ngbootstrap, PrimeNG, Semantic UI, and more.
One day, I decided to use a library for my Angular project straight from the Google factory (i.e. Angular Material). I had to use a lot of components in the project, such as inputs, expansion panels, dialogues, tabs, etc.
Unfortunately, there was one downside: The appearance of the components that the UI designer prepared in high-fi mockups was a little bit different from those offered by Angular Material. However, this is obviously not a challenge for an experienced frontend developer. After all, this is what we are here for — to create the client's desired appearance and behaviour of the components.
But it's not that easy with the AM library.
In this article, we will overwrite some styles in a simple AM tab component. Let's try to change the background-color
of the tab indicator:
First, we inspect the DOM element that contains the styles responsible for background-color
:
Let's overwrite the styles as we usually would in our component's SCSS file:
//tabs.component.scss .mat-tab-group.mat-primary .mat-ink-bar {
background-color: red;
}
As you can see below, the background-color
hasn't changed. Why is this so?
The answer is quite simple: Angular uses the View Encapsulation mode, which attaches some extra attribute (_ng-content-***-***
) to each DOM element to wrap the whole SCSS code to the component's unique attribute.
To make it easier, let's take the default HTML button:
app.component.html <button>Example button</button>
And style it:
//app.component.scss button {
background-color: red;
}
What we see in the inspect mode:
The unique attribute has been added automatically by the View Encapsulation mode. If we come back to our example with the tabs, we see that AM doesn't always add a special attribute to each DOM element:
When we try to style our component in the scoped mode, we don't see any results because the browser reads our styles like this:
.mat-tab-group.mat-primary [_ng-content-***-***] .mat-ink-bar {
background-color: red;
} // -***-*** is unique numbers
So What Is the Correct Way To Overwrite AM Styles?
There are plenty of examples on the web of how to overwrite AM styles, but these methods are either risky to use or deprecated.
1. Turning off the View Encapsulation mode (removing a unique attribute)
The most common answer I came across is turning off the View Encapsulation mode.
How can we achieve this?
We import ViewEncapsulation
from "@angular/core"
, and inside the @Component
metadata, we set encapsulation: ViewEncapsulation.None
.
From now on, we will not have any unique attribute in the component's DOM elements and our styles will be global.
It works, but this is quite risky because now we affect the rest of the application. The isolations, scoping rules, and unique attributes discussed earlier don't work anymore. Every tab component will apply this rule. We don't want to do it like this.
2. :host & ::ng-deep pseudo-class (deprecated)
Another answer that appears very often is to implement the deprecated pseudo-class ::ng-deep
and overwrap the special selector :host
.
Let's try it out:
What happened here?
-
:host
— Adds unique attribute of host component[_nghost-sik-c77]
, which overwraps our styles so it will only affect our component. Great! -
:ng-deep
— Removes the unique attribute from the tab's DOM elements.
Oh, it works! But wait… on the Angular website, there is the following information:
"Applying the
::ng-deep
pseudo-class to any CSS rule completely disables view-encapsulation for that rule. Any style with::ng-deep
applied becomes a global style.""…we plan to drop support in Angular (for all 3 of
/deep/
,>>>
and::ng-deep
)."
Like in the example above, this solution turns off the view encapsulation, so your styles become global.
The other thing is that you are using ::ng-deep
in Angular 11, for example, but maybe a future Angular version will remove it. After some time, your client might like to update their project to the latest Angular version and you will find it difficult to overwrite all the styles that use this deprecated pseudo-selector.
3. Overwriting AM styles in separate global styles — not scoped!
After deep analysis, I found a way to overwrite AM styles with suitable SCSS structures without any risk or deprecated methods.
In each complex project, I use the SASS 7–1 Pattern to arrange my SCSS files.
| — scss
| — base
| — components
| — am-components
| — layout
| — pages
| - themes
| — utils
| — vendors
As you can see, a new folder called am-components
was added to the components
folder. Here, I will store all my .scss
files that are responsible only for AM components.
So let's create this:
I created the _ab-tabs.scss
file that is imported in the main styles.scss
file:
//styles.scss @import "scss/components/am-components/am-tabs";
So how can we overwrite our AM tab component styles?
Angular Material uses the least specific selectors possible for its components to make it easy to override them. More specific styles will take precedence over less specific styles. So in our case, we have to add more specificity to overwrite our AM styles. The best way to do so is to use the name of our component's selector.
//_am-tabs.scss mat-tab-group {
&.mat-tab-group.mat- primary .mat-ink-bar {
background-color: red;
}
}
At the moment, we have the same result as we had with the ::ng-deep
pseudo-selector, but this will never be deprecated!
What if we want to style another tab differently?
It's painless — just add a unique class to your component:
Now our AM tab component with the .my-tab-class
has a green indicator.
Conclusion
As you can see, there are a lot of options to overwrite our AM styles. Unfortunately, many of them can cause a few problems in your project (e.g. ::ng-deep
or turning off the view encapsulation mode). The best way to make our components beautiful is to use classic global styles with a solid and clear pattern, like 7–1, and overwrite them with more specific styles.
Source: https://betterprogramming.pub/best-way-to-overwrite-angular-materials-styles-e38dc8b84962
0 Response to "Easy Way to Overwrite All Elements in an Array"
Post a Comment