The following illustrates this issue with a trivial example I have prepared and pushed to a github repo.
I created a custom element "x-menu" (in /x-menu.html) with styling rules for the light DOM. In practice, my use case for doing so is to use CSS variables and mixins to define colors, font-stacks, etc. to be used in the document and custom elements.
I have a custom element defining document styling (in /demo/index.html) as described in the relevant part of the Polymer 1.0 dev guide, which defines some typography rules for my pages.
This works fine with native Shadow DOM in Chrome.
However, when using Shady DOM the document styling resolves to style definitions which have higher specificity than the styling in the x-menu element. This is now it appears in the Styles stack of Chrome's developer tools:
ul:not([style-scope]):not(.style-scope), p:not([style-scope]):not(.style-scope) {
font-size: 12px;
color: red;
}
.container.x-menu ul, .container.x-menu p {
font-size: 30px;
color: green;
}
I understand there are some limitations with Shady DOM and Shadow DOM polyfill (webcomponents.org simply says a known limitation is "CSS encapsulation is limited."),
There are two workarounds I can think of, neither of which is very practical:
Add a CSS class to every light DOM node (which you can see in the demo page)
This is not practical because a user of the custom element has to remember this and defeats the CSS encapsulation goal.
Apply a CSS mixin to the local style definition. When processed by Shady DOM, the CSS has higher specificity than "custom-style" at the document level.
This becomes more cumbersome and adds unnecessary overhead in developing, maintaining, and processing the CSS.
I am looking for any ideas for a suitable workaround for this issue. Worst-case, I would like to put the onus on the element developer rather than the user of the element.
Seems like a possible limitation of the style shim. Polyfilling CSS is hard! I'd recommend filing an issue on the Polymer repo with this demo.
Related
I just can ignore this property and I will get the same result, right?
If so, what is the meaning of using text-decoration: none; as a declaration in CSS.
This is my first question.
I'm trying to understand CSS and it's declaration's properties.
If the element you are applying the CSS to has no default text-decoration, then yes there is no immediate functional benefit to applying that CSS rule.
However, consider you are using the <a> HTML element (or anchor element). This has the default CSS style:
text-decoration: underline;
You may want to remove this underline (for whatever reason). This is a scenario when you could use the style rule a {text-decoration: none;}, to remove the underline.
CSS libraries like Bootstrap may also apply unwanted CSS rules that you wish to remove, or maybe you are already applying a CSS rule to an element, but want to remove that styling in specific cases.
You might also apply CSS rules of this nature as a preventative measure, to mitigate the risk of future CSS changes applying rules where you may not want them to.
In short, you use CSS rules like text-decoration: none; to remove existing CSS rules.
The MDN web docs is a great source to learn about CSS, and the other fundamental technologies of the web, If you want to learn more. Here is a link to their page on the text-decoration CSS rule.
Hope this helps.
One example of things affected by the none would be <a>/href=””links, that to most browsers, become blue once turned into links. using text-decoration: none; shows the browser that it should not add anything extra to the text, thus keeping it consistent with the other type on your page.
For more examples and documentation on the style, read MDN Docs on text-decoration
So I've got an Angular app that has pretty basic routing, and I'm using flexbox to layout my components. The issue I can't figure out is with code like this:
<div fxLayout="column"
fxFlex
class="layout__right">
<router-outlet></router-outlet>
</div>
The child component that is routed to contains the following in its SCSS:
:host {
#include make-flex-container(column);
flex: 1;
}
That make-flex-container just applies some flexbox related styles, and works fine in many places of the app. What's happening in my case though is when routing to this particular child component I see a style tag applied to the ng-component element created by Angular. What's causing my problem is for some reason the style includes flexbox items that are overriding what I'm putting in :host:
You can see in the screenshot that my :host styles are being applied, but the styles on the ng-component tag are simply overriding them. For the life of me I can't understand why there's a specific style tag added here, so where the content within it would come from. Does anyone know why Angular would put style tags on the HTML generated for router-outlets? When I navigate to other components at this same routing level this style tag isn't present.
I assume this is an issue with my code, but I just can't run down where to look given what I see.
UPDATE
Here's a minimal reproduction of the issue on Stackblitz:
https://so-48451609-routing-flex-issue.stackblitz.io
In that example you can see how the element created next to the router outlet has styles applied to it. The only dependency added there is #angular/flex-layout, so it's gotta be doing something to cause this.
The fxLayout directive applies styles to child elements. It does this on the element itself to not interfere with other styles.
The #angular/flex-layout library's static API has directives that work either on a DOM container or DOM elements. fxLayout is an example of the former, fxFlex is an example of the latter.
See the docs here, note the two sections for elements and containers: https://github.com/angular/flex-layout/wiki/Declarative-API-Overview#api-for-dom-containers
THEY COME FROM VIEW ENCAPSULATION
I believe that these classes are part of view encapsulation that prevents angular elements from being styled from outside and to prevent interference between view components. At least that is what they say in official docs #angular.io.
As suggested #this SO post the '_ngcontent-c0' is naming of the first component within the host.
ANGULAR MATERIAL IS CAUSING TROUBLES
I have found a bunch of issues related to encapsulation at GitHub and they often seem to be related to using Angular Material, which seems to have encapsulation turned off sometimes somehow. Such as described here. Hence I conclude that your implementation of Angular Material might be at fault. For in depth analysis of what the mechanism of this unwanted interaction is, you might probably like to start by reading joh04667's answer to your question since it provides links to the documentation of the particular material you use.
PROPER STYLING
Common solution to those issues is overriding styles with /deep/ selector as described in both above shared links. A number of unofficial articles on styling Angular app is available as well, such as this one.
IDEA
So the idea is to overwrite the styles in your component with /deep/ like this:
:host /deep/ .your_flex_class {
#include make-flex-container(column);
flex: 1;
}
CONSIDER VALID CSS
Since I think that you use Scss, using /deep/ selector should be ok and should be compiled successfully (I use it quite often to style inline SVGs). However, in a fact, this selector seems to be deprecated as a whole bunch of things related to the issue of Shadow DOM. I believe the correct universal approach would be to use 'shadow-piercing descendant combinator':
:host >>> .your_flex_class {
#include make-flex-container(column);
flex: 1;
}
It should does all the same as /deep/ selector. To explain the mechanism, let me cite from official docs for CSS Scoping Module Level 1
When a >>> combinator (or shadow-piercing descendant combinator) is encountered in a selector, replace every element in the selector match list with every element reachable from the original element by traversing any number of child lists or shadow trees.
Basically, it does not care about the wrapper and bites down to your target to style it. So you have even one more option to try ...
Ok, once I created a working example of this I eventually found the culprit and a suitable work-around. What is happening is within my router child component I'm using fxFlex from #angular/flex-layout to flex the element. I'm applying the flexbox container CSS in the :host{} section of the components CSS, but flex-layout doesn't see this in the rendered HTML and applies the style tag to do a flexbox row layout automatically.
Here's an issue on Github with my comments and a suitable workaround of using !important in my :host{} CSS:
https://github.com/angular/flex-layout/issues/496#issuecomment-360870510
Consider the following hierarchy in some Angular 2/4 project:
<parent-cmp [ngClass]="{ 'parent': condition }">
<child-cmp class="child"></child-cmp>
</parent-cmp>
Now in the child component's CSS file I would like to say:
.parent .child {
background-color: red;
}
In this scenario, I'm basing the child's design on parent's logic without knowing what that logic is at child level. But the problem is that, this is not going to work. And that's because, Angular compiles the the child CSS selectors to this:
.parent[_ngcontent-c9] .child[_ngcontent-c9] {
background-color: red;
}
And the parent part of the selector is not going to work anymore. So How can I pull this off? Also please bear in mind that I simplfied this example and the two components are not necessarily one after another (there might be arbitrary number of components in between).
In Angular this is called "view encapsulation" where the JavaScript, CSS styles, and HTML templates are all managed by Angular. There are a lot of advantages to this approach as it allows you to easily tree-shake a project and drop components that are not being used. You not only drop the Javascript code, but all the styles and HTML with it.
When it's turned on the styles are injected into the DOM as embedded styles. Angular keeps track of what styles are required on the document and adds or removes styles as needed. These styles can have strange names at run-time like those in your question.
You need to read up on the https://angular.io/guide/component-styles styles guide to see how to define a :host style. This is the style assigned to a component when view encapsulation is turned on. When using :host you can refer to the parent selector using a :host-context path, and you can also style inside other child components using the ::ng-deep selectors.
Keep in mind. This is all optional. It's turned on by default, but if you don't want to use it. You can turn it off.
You can change the view encapsulation mode when you define your component. To disable this feature just change the encapsulation option to native.
See the guide:
https://angular.io/guide/component-styles#view-encapsulation
Please note: I found this question as well as this one, but both of their answers involve writing and executing customized JS. My question here is about how to wield Chrome Dev Tools (or similar) to accomplish the same thing in real-time.
I have a quasi-legacy JVM app that serves (and creates as part of its build pipeline) all sorts of nasty and messy CSS files.
I'm wondering if Chrome Dev Tools (or any other modern OSS webdev tool for that matter) has a "reverse engineering" feature in it that allows you to click on an HTML element and get a list of all the CSS rules that apply to it. And, not only that, but which rules are overriding other rules.
This way, when I need to tweak my CSS, it's less of a wild goose chase to figure out which rules are coming from which CSS files and that are actually being applied to the live element at runtime.
Any ideas?
Yes, in Chrome DevTools (F12 in Windows / Option+Cmd+I in OSX) within the Elements panel you can click on an element and see the applied CSS rules on the right-hand side. The overridden styles or classes are crossed out, and you can see the file name in which the CSS rule comes from. See below:
element.style refers to inline styles. For example, if I modified the selected element to be <div class="container" style="background-color:#000">...</div>, background-color:#000 will show up in the that section.
#content refers to the div element with the associated id of 'content'. The checkboxes that are checked on the right indicate that they have been applied with no overriding. You can check and uncheck these to play around with the styles so that you can see what you should change in your source code.
The html, body, div, span etc. allows multiple selectors to use the same styles. All the selectors in that comma-separated list will have the styles, except some may be overridden by other CSS rules - in this case, margin and padding are overridden by the more specific #content selector.
The next block is for user agent styles. These are styles that are applied by the browser, and each browser may apply different ones. This can be a problem if you have more specific rules defined yourself. Many people use normalizers to make sure things remain consistent among browsers. Check out Normalize
The inherited section shows all the styles that are inherited from parent styles. In this example, the text-align: left style was applied from the .container class as that is the parent element and the #content element didn't override it explicitly.
Update
Added better quality screenshot (thanks to #SLaks)
Added keyboard shortcuts for access (thanks to #NKD)
Added simple explanations of the sections of the Styles panel on the right.
Modern browsers have an "inspector" option that allow you to select a piece of generated HTML and view the CSS applied to it. Each one varies slightly, but normally hitting F12 will get you going.
I tried my website (http://fnndsc.github.io/fnndsc.babymri.org/) on the latest canary and many things are messed up.
More importantly, the style is not propagated down to sub-elements anymore. I read around but couldn't find the best pratice to handle that.
How can I tell my polymer element to use the style from it parents.
Is there a special flag to turn on?
Up to Chrome 34 it works fine but 35/36 appear to be broken.
Thanks
Chrome 35 unprefixes the new Shadow DOM implementation (blog post) and turns it on by default. Some of what you're seeing could also be differences between native Shadow DOM and the polyfill shimming.
Without having the codebase to look at, there could be any number of things. There have been many updates to Shadow DOM's styling features in the last few months.
Things to note from what I saw on your site
#host { :scope {display: block;} } -> :host {display: block; }
move stylesheets an element relies on into the <polymer-element>.
applyAuthorStyles is gone. If you were using it, the only way to take on styles from the outer page is to use ::shadow, /deep/, or include shared styles in the <polymer-element> the needs it.
If you're using <content> and distributed nodes, make sure you're using the ::content pseudo element
Here are some up to date resources for styling:
http://www.polymer-project.org/docs/polymer/styling.html
http://www.polymer-project.org/articles/styling-elements.html