Angular2 - adding [_ngcontent-mav-x] to styles - css

I'm setting up a basic angular app, and I'm trying to inject some css to my views. This is an example of one of my components:
import { Component } from 'angular2/core';
import { ROUTER_PROVIDERS, ROUTER_DIRECTIVES, RouteConfig } from 'angular2/router';
import { LandingComponent } from './landing.component';
import { PortfolioComponent } from './portfolio.component';
#Component({
selector: 'portfolio-app',
templateUrl: '/app/views/template.html',
styleUrls: ['../app/styles/template.css'],
directives: [ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS]
})
#RouteConfig([
{ path: '/landing', name: 'Landing', component: LandingComponent, useAsDefault: true },
{ path: '/portfolio', name: 'Portfolio', component: PortfolioComponent }
])
export class AppComponent { }
Now the .css file is requested from my server, and when I inspect the page source, I can see it was added to the head. But something weird is happening:
<style>#media (min-width: 768px) {
.outer[_ngcontent-mav-3] {
display: table;
position: absolute;
height: 100%;
width: 100%;
}
.mainContainer[_ngcontent-mav-3] {
display: table-cell;
vertical-align: middle;
}
.appContainer[_ngcontent-mav-3] {
width: 95%;
border-radius: 50%;
}
.heightElement[_ngcontent-mav-3] {
height: 0;
padding-bottom: 100%;
}
}</style>
gets generated from this file:
/* Small devices (tablets, 768px and up) */
#media (min-width: 768px) {
/* center the mainContainer */
.outer {
display: table;
position: absolute;
height: 100%;
width: 100%;
}
.mainContainer {
display: table-cell;
vertical-align: middle;
}
.appContainer {
width: 95%;
border-radius: 50%;
}
.heightElement {
height: 0;
padding-bottom: 100%;
}
}
Can somebody please explain where the _ngcontent-mav tag comes from, what does it stand for and how to get rid of it?
I think this is the reason why my style is not getting applied to my templates.
If you need more info about the app structure, please checkout my gitRepo, or ask and I'll add the code to the question.
Thanks for the help.

update2
::slotted is now supported by all new browsers and can be used with `ViewEncapsulation.ShadowDom
https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
update
/deep/ and >>> are deprecated.
::ng-deep replaces them. ::-deep is also marked deprecated in source and the docs, but this means that it will also be removed eventually.
I think it depends on what W3C comes up with for theming the shadow DOM (like https://tabatkins.github.io/specs/css-shadow-parts/)
It's basically a workaround until all browsers support that natively and ViewEncapsulation.Emulated can be removed entirely.
::ng-deep is also supported in SASS (or will be, depending on the SASS implementation)
original
View encapsulation helps to prevent styles bleeding into or out of components. The default encapsulation is ViewEncapsulation.Emulated where classes like _ngcontent-mav-x are added to component tags and also styles are rewritten to only apply to matching classes.
This emulates to some degree the default behavior of the shadow DOM.
You can disable this encapsulation adding encapsulation: ViewEncapsulation.None to the #Component() decorator.
Another way is the recently (re-)introduced shadow piercing CSS combinators >>>, /deep/, and ::shadow. These combinators were introduced for styling shadow DOM but are deprecated there. Angular introduce them recently until other mechanisms like CSS variables are implemented.
See also https://github.com/angular/angular/pull/7563 (https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta10-2016-03-17)
>>> and /deep/ are equivalent and using this combinators makes the styles ignore the the added helper classes (_ngcontent-mav-x)
* >>> my-component, /* same as */
* /deep/ my-component {
background-color: blue;
}
applies to all my-component tags not matter how deep they are nested in other components.
some-component::shadow * {
background-color: green;
}
applies to all elements in the template of some-component, but not further descendants.
They can also be combined
* /deep/ my-component::shadow div {
background-color: blue;
}
this applies to all div elements in the template of all my-component templates no matter how deep my-component is nested in other components.
/deep/, >>>, and ::shadow can only be used with
encapsulation: ViewEncapsulation.None
encapsulation: ViewEncapsulation.Emulated
encapsulation: ViewEncapsulation.Native when the browser supports them natively (Chrome does but prints a warning in the console that they are deprecated) or
when the browser doesn't native support shadow DOM and the
web_components polyfills are loaded.
For a simple example see also the Plunker from this question https://stackoverflow.com/a/36226061/217408
See also this presentation from ng-conf 2016 https://www.youtube.com/watch?v=J5Bvy4KhIs0

You should try this,
import {ViewEncapsulation} from 'angular2/core';
#Component({
...
encapsulation: ViewEncapsulation.None,
...
})

Related

overriding body background color in angular 7 [duplicate]

This question already has answers here:
How to change <body> tag style from child component?
(3 answers)
Closed 2 years ago.
I have been trying to override the background body of my login and register components but it's not working
I tried adding a div with a CSS class setting its background color but the bottom part of the page isn't set to the color I picked.
I would appreciate any suggestion on the best way to solve it.
.login-page{
height: 100% !important;
background-color: #e40134 !important;
}
If you want change the class of body in some components you use ngOnInit and ngOnDestroy
//inject in the constructor the "document"
constructor(#Inject(DOCUMENT) private _document) { }
//in init you add a class to de body
ngOnInit() {
this._document.body.classList.add('new-body-class');
}
//in destroy remove the class
ngOnDestroy() {
this._document.body.classList.remove('new-body-class');
}
And
.new-body-class{
background-color: #e40134;
}
The new-body-class can be a class defined in styles.css or you can use ViewEncapsulation.None. Be Carefull, ViewEncapsulation.None makes that the .css of the componet is common to all the aplication, so if you write, e.g.
h5{color:red}
.new-body-class{
background-color: #e40134;
}
futhermore change the background, all yours h5 in your application becomes red
Use encapsulation key at #Component
import {Component, ViewEncapsulation} from "#angular/core";
#Component({
selector: 'login-page',
templateUrl: './login-page.component.html',
encapsulation: ViewEncapsulation.None
})
and use ::ng-deep in css => https://blog.angular-university.io/angular-host-context/
for example:
::ng-deep .login-page {
height: 100% !important;
background-color: #e40134 !important;
}
These are the different ways of encapsulation:
I think this is actually a problem because your has a margin by default.
So in styles.scss, I would just add this:
body: {
margin: 0
}
Try with
.login-page{
height: 100vh !important;
background-color: #e40134 !important;
}
If with this you still do not have the expected result you can add position: absolute.
In any case you can always reset the body by applying a margin: 0. It would be very helpful to know what you see if you inspect it with the browser.

ng-bootstrap - Typeahead dropdown width

I started using the ng-bootstrap Typeahead component and I'm pretty happy with that.
One thing I would like to achieve is to get the dropdown items to have the same width as the input field, while the default behavior applies a width accordingly to the text length. It should be basic CSS...
I created a basic Example in Plunker.
As you can note, the applied style is ignored:
.dropdown-menu { width: 100%;}
While if I use browser dev tools, and apply the same it is applied.
Any idea on how to achieve the result, by using CSS?
Add encapsulation: ViewEncapsulation.None to the component
import {Component, ViewEncapsulation} from '#angular/core';
#Component({
selector: 'ngbd-typeahead-template',
templateUrl: 'src/typeahead-template.html',
styleUrls: ['src/typeahead-template.css'],
encapsulation: ViewEncapsulation.None
})
See updated plunker
Without ViewEncapsulation.None, the styles applied in this component will only effect this component and not any other component on this page.
Read this for more information
For me works ng-deep. Looks more safe and scoped:
::ng-deep .dropdown-menu { width: 100%; }
This is how I made it work within responsive col :
::ng-deep ngb-typeahead-window.dropdown-menu {
width: calc(100% - 30px);
}
or
::ng-deep .dropdown-menu.show {
width:calc(100% - 30px);
}
Not sure which one is the best option but I tend to think of the first one.
#Nandita's answer is correct, directly apply a width to dropdown menu won't affect.
And you want the dropdown menu to have same width as input, so you should add below CSS to her answer:
.dropdown-menu { width: 300px;}
Check result:
https://next.plnkr.co/edit/YvOymCLAwYgU3VmJ
This code 100% work, but with the class .dropdown-menu any other dropdown will be changed
::ng-deep .dropdown-menu { width: 100%; }
So I just used this code with ngb-typeahead- as the ID:
::ng-deep [id^="ngb-typeahead-"]{
width: 100%!important;
white-space: nowrap!important;
overflow: hidden!important;
text-overflow: ellipsis!important;}
Expanding on Nandita Sharma's answer, when turning off ViewEncapsulation in Angular it's probably a good idea to scope any CSS rules to the component. This will avoid generically named classes from leaking out in the global CSS scope.
A really simple way of doing that is to scope everything inside of the component's selector:
// Name of the component containing the typeahead
app-parent-selector {
// Rules added here won't leak out into the global CSS scope
.dropdown-menu {
width: 400px;
}
}
It would also be wise to avoid any approach that uses shadow-piercing descendant combinators (::ng-deep, /deep/ or >>>) because support for them is gradually being removed from all major browsers and will eventually be removed from Angular.
The best thing to do would be adding this globally, provided you plan to use the type-ahead field the same way in all your pages. If you have a styles.scss which can hold all the global styles, add this there:
ngb-typeahead-window {
width:calc(100% - 30px);
.dropdown-item {
overflow: hidden;
text-overflow: ellipsis;
}
}
Using scss should do the trick. Find the parent div in your dom, and give it a class 'dropdown-wrapper'.
.dropdown-wrapper {
.dropdown-menu {
width: 90%;
}
}
Add this to your global scss. Cheers!

How can i build a custom angular component with the width settable in CSS?

This site states, that I can change the width of the side-nav with CSS like this:
md-sidenav {
width: 200px;
}
This arouses the following question for me: Can I apply the standard CSS properties like width, position, etc... to custom components without to define them in my component?
Example:
my-component {
width: 500px;
}
I tried it out and it does not work. So I think, that the answer is no, am I right?
To find out how they set width with CSS I have read through the sources on github. But I can't figure out how they did that. The component has no width property. So, how did they make width accessible with CSS?
EDIT:
To clarify the question I will give you the following example:
I have programmed the following component:
test.component.html:
<p>test works!</p>
test.component.css:
p {
border: 2px solid red;
}
test.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
constructor() { }
ngOnInit() { }
}
This is my app root, that gets bootstrapped by angular:
app.component.html:
<app-test>
</app-test>
app.component.css
app-test {
height: 100px;
width: 200px;
}
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Test App';
constructor() { }
}
The _app.component.css_ shows what I want to do. I want to set the size of the _app-test_ component with CSS. I saw this working with the _side-nav_ component of the angular material and I want to understand how they have enabled the _side-nav_ to get its width from the parent components CSS file.
UPDATE After OP's edit:
Change your app.component.css to this:
:host {
display:block;
height: 100px;
width: 200px;
}
This will apply the styles on the <app-test> selector. Here is the plunker demo.
ORIGINAL Answer:
You can override the default styles of Material 2 components by setting encapsulation: ViewEncapsulation.None in the component.
Then you'll have to define the styles in your component.css file.
.mat-sidenav {
width: 250px;
}
See this plunker demo with user defined width.
Update after OP's comments:
Suppose you have a component file, my.component.ts and it has styles in my.component.css, you can define the styles of the component in the css file and apply then on the component selector using :host.
my.component.ts :
#Component({
selector: 'my-comp',
templateUrl: 'my.component.html',
styleUrls: ['my.component.css']
})
export class MyComponent{
}
my.component.css :
:host {
width: 500px;
background-color: red;
}
my.component.html:
<h2>Some Heading in the Template </h2>
My Question was answered with the comment of Will howel beneath my question. This post should recap what I have learnered through the comments of the other users, so that people with a similar question could learn from it.
The template of every component is wrapped in a host element. In the sidenav example, this element is the md-sidenav tag. The host element is a regular dom-element, wherefore you can add standard css rules to that element. That means that you can apply css rules like width to every custom angular component out of the box. But you have to take into account that you need to set the display property of the host element to block. If you don't do that, the width rule has no effect to the element.
To accomplish that in case of the md-sidenav component they applied the class mat-drawer within the component-decorator to the element.
exerpt from sidenav.ts:
host: {
'class': 'mat-drawer mat-sidenav',
...
},
Then they set the rule in the stylesheet.
Exerpt of drawer.scss:
.mat-drawer {
#include mat-drawer-stacking-context();
display: block;
}

Angular2 2.4.3 and responsive web-design: using media queries seem not to work

When using Angular2 2.4.3 in combination with CSS3 media query features either:
directly embedded within the Angular2 component (see below example)
or
centrally referenced in "index.html" using a "styles.css"
the html component in both cases is not formatted according to the media query specifications. Instead, only the non-media-query CSS parts are rendered.
import {Component} from '#angular/core';
#Component({
/* necessary for using relative paths (only works in combination with
* 'commonjs'-transpiled modules, see:
* https://angular.io/docs/ts/latest/cookbook/component-relative-paths.html
*/
moduleId: module.id,
selector: 'login',
templateUrl: '../templates/login.component.html',
styles: [`
#media only screen and (min-width: 840px)
.layout {
font-size: 58px;
}
.layout { background: green; }
`]
})
export class LoginComponent {
}
Hint: for sure, I'm using a desktop monitor with a width-resolution >840px ;)
Am I doing something wrong or are media queries not yet supported by Angular2? Maybe, I have to do additional stuff to let Angular2 detect the used media correctly?
#Holger, the problem is not with Angular but in your style implementation. You have omitted curly brackets around the styles within your media query. It should look like below and I think it should solve your problem.
styles: [`
#media only screen and (min-width: 840px) {
.layout {
width: 368px;
}
}
.layout { background: green; }
`]
Have you tried this:
styles: [`
#media only screen and (min-width: 840px) {
.layout {
font-size: 58px;
}
}
.layout { background: green; }
`]

Angular2 css :host applying but not visible in browser

I am having a bizarre issue whilst creating my first Angular2 app.
I am applying some CSS to a component host (example-component) yet it doesn't appear in the browser?
This is my first time posting for Angular in SO, so hopefully I include everything needed to attain some help.
example.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'crate',
templateUrl: './app/folderA/folderAB/crate.html',
styleUrls: ['./app/folderA/folderAB/crate.css']
})
export class MyComponent {}
index.html
crate.html
<div class="background">
<div class="content">
<p>Content</p>
</div>
</div>
crate.css
:host-context(.lg){
width: 100%;
background-color: #000;
border-radius: 25px;
}
What I don't understand, is that I open this in chrome & firefox, and I see the following CSS stated under rules for example.component.
.lg[_nghost-ims-2], .lg [_nghost-ims-2] {
width: 100%;
background-color: #000;
border-radius: 25px;
}
It is correctly applying the CSS to example-component, but it is not being displayed / rendered in browser. What am I doing wrong / missing?
EDIT
The exact same issue applies even if I change crate.css to:
crate{
width: 100%;
background-color: #000;
border-radius: 25px;
}
Any component with an unrecognized tagName like <crate></crate> is created as a HTMLUnknownElement and has empty values for all the style properties, if you want it to behave like a div then add display: block; to your stylesheet.
See Browsers' default CSS for HTML elements for additional resources on the default css for different browsers.

Resources