Can I make a template style external? - css

In Google Polymer lesson 1, they have an example that includes an inline stylesheet.
I'd like to move it to a css file, but the style is inside a template tag.
To make matters worse, it says it's
Used inside a shadow DOM tree, the :host pseudo-class matches the
element that hosts the tree. In this case, it matches the
element.
Q: Can I move this style to a css file?

If you download the seed element from this page (or just look at the listed contents), you'll see that it uses an external css file. You can examine the element html to see how it is used, but it's very simple:
<polymer-element name="seed-element" attributes="notitle author">
<template>
<link rel="stylesheet" href="seed-element.css" />
<h1>Hello from seed-element</h1>
<content></content>
</template>
<script>
Polymer('seed-element', {
//...
}
</script>
</polymer-element>
Then in seed-element.css by default you have the following:
:host {
display: block;
}
The way I understand it (in my limited knowledge) is that if you were to rename seed-element to my-element, this would be the same as doing
my-element {
display: block;
}

If you want to style the elements that are part of a custom elements Shadow DOM you have to use the ::shadow selector, or /deep/ selector if you want to select elements regardless how many levels deep they sit inside of Shadow DOM.
So from the outside, you would style a p element that's inside x-foo's Shadow DOM like this:
x-foo::shadow p {
}
You can read about all that stuff here: http://www.polymer-project.org/articles/styling-elements.html

Related

How to refer to an Angular component's full template setting CSS without referring to any tags?

My usual setup for each view is an outer DIV that I style as the base background etc.
<div class="outer">
<!-- Actual stuff in here -->
</div>
Then, in the SASS, I refer to it like so.
div.outer { ... }
That adds one lever of indent and seems like an unnecessary (though minor) increment in complexity. So I wonder if it's possible to add a style to the template itself. Partly, to lower the complexity. Partly, because I'm going to have text-only elements with no tags at all.
Is it possible to set the style of template from SASS files if there are no tags, only text in it?
You can apply styling to the component host element with the :host selector:
:host {
color: red;
}
See this stackblitz for a demo.

Writing styled-jsx without selector

Without specifying/wrapping with a selector (button {}), the following styled-jsx style declarations will work. The button is properly styled which is great. However, usage like this is not documented in website so i wonder if this syntax is officially supported and safe to use?
<button>
<style jsx>{`
background-color: red;
:hover {
background-color: #ccc;
}
`}
</style>
Test
</button>
Another example, using resolve tag that works too:
const { className, styles } = css.resolve`
font-weight: bold;
`;
styled-jsx uses stylis css preprocessor under the hood. This is how styled-jsx transforms content of a style tag:
transformedCss = transform(
isGlobal ? '' : getPrefix(dynamic, staticClassName),
plugins(css, pluginsOptions),
{ splitRules, vendorPrefixes }
)
Note, that transform here is a wrapper function around stylis.
Thus styles declared inside <style jsx> tag will be wrapped with dynamically generated class and then transformed with stylis.
In your case styled-jsx will produce this css:
If you use global selector no class selector will be added to the generated code and so produced css wont be applied to any elements on the page.
From my point of view it won't be a mistake to use styles without a selector, however, you should do it carefully with a <style jsx> tag because in this case styles will be applied to every element inside a component.
Using this feature with css.resolve looks much more safe since you may manually pick the elements to apply css.
As far as I know, the official documentation misses the explanation of such an important detail.

Overriding the encapsulated CSS of external component

I was wondering how to override the encapsulated CSS of an external component.
So I am using material2 in my project and the tabs component has a the attribute overflow set on tab-body. Is it possible to override the overflow value?
You can use the special css /deep/ instruction. See the documentation
So, if you have
app
sub-component
target-component
<div class="target-class">...</div>
You can put in your apps css (or less):
/deep/ .target-class {
width: 20px;
background: #ff0000;
}
Obviously, you can put this css fragment in sub-component as well.
From this article
Although the style of a component is well isolated, it can still be easily overridden if necessary. For that, we just need to add an attribute to the body of the page:
<body override>
<app></app>
</body>
The name of the attribute can be anything. No value is needed and the name override makes it apparent what its being used for. To override component styles, we can then do the following:
[override] hello-world h1 {
color:red;
}
Where override is the attribute, hello-world is the target component, and h1 is whatever you are trying to restyle. (get this right or it wont work).
Your component hello-world would be
selector: 'hello-world',
styles: [`
h1 {
color: blue;
}
`],
template: ` <h1>Hello world</h1> `
I think this is the most elegant way.
Alternatively if you are building a library of some sort, you can reset the styling altogether by doing something fancy in your css like:
:host-context(.custom-styles) {
//.. css here will only apply when there is a css class custom-styles in any parent elem
}
So then to use your component you'd use
<hello-world class="custom-styles">
But this is way less convenient than the first option.
::ng-deep .tag-or-css-class-you-want-to-override {
/* Add your custom css property value. */
}
The syntax ::ng-deep is used to override outside css class or tags without using ViewEncapsulation.None.
I see variations of this question a lot and since this is the top question on the subject I want to give the simplest answer. ng-deep and similar functionality is deprecated, so it's best to just rely on vanilla CSS.
Simply create a CSS selector with a higher specificity.
Most people (including myself) get hung up trying to do that because they don't understand two things:
Angular View Encapsulation
CSS Specificity
Angular View Encapsulation
View Encapsulation ensures CSS within a component only affects that component. To affect other components, you need some global CSS. You can do this by using a global style file like styles.css or by disabling View Encapsulation on a component.
#Component({
...
encapsulation: ViewEncapsulation.None
})
CSS Specificity
When two selectors select the same element, the CSS that actually gets applied is based on specificity: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
You can increase specificity by simply adding more elements to your CSS selector. For example p.className is more specific than just .className. If you're lazy, you can just repeat a class name to increase specificity. .className.className is more specific than .className.
So to override any CSS in an Angular project, go into styles.css and repeat the class selector until your CSS has a higher specificity than the original.
.className.className.className {
color: red;
}
Didn't work? Add another .className.
Just check the class that is being applied to the tabs by the external component (use Inspector or any other tool). In your style css file, add the same name of the class for the tabs and set the overflow property along with adding !important to it to make sure it overwrites the previous one. Also make sure your css link to the page is added after the external component css link if any.
Hope this helps.
::ng-deep .css-class-you-want-to-override{
/*your custom css property value. like below */
background: white !important;
}

Issue with upgrade to Polymer 0.5.1 and styling paper-dialog

So I just updated my project from Polymer v0.4.2 to v0.5.1 of the Polymer library. One thing that seemed to have changed is how the paper-dialog element is implemented.
In v0.4.2, when I had a paper-dialog inside of my custom element, I could customize it with CSS inside of my element using core-style elements.
In v0.5.1, if I understand correctly, the paper-dialog is no longer implemented inside my component, but instead it's implemented in the core-overlay-layer element which is in the html page outside of my component.
So does that mean that I now have to add a CSS style sheet to the html page that contains my component? If so, then I can no longer use core-style along with the benefits of the CoreStyle.g object. It also means that everything related to my component is no long all encapsulated inside of my component.
Please tell me that I am wrong and that there is a way for me to style the paper-dialog from within my component still.
Thanks!
In Polymer 0.5.1 the layered property (doc: https://www.polymer-project.org/docs/elements/core-elements.html#core-overlay) defaults to true which allows it to always display above page content. If layered is false, the dialog may not display on top if there is something after it in DOM with a higher stacking context.
However because layered reparents the dialog to a global core-overlay-layer it's not possible to style it from an outer scope. There are a couple options for styling:
If you know you don't have any DOM with a higher stacking context than the dialog, set layered="false" to get the non-layered behavior and you can style it from the outer scope.
Style the dialog with a /deep/ rule in a global style. You can still use core-style by referencing the style in the global scope. You can also include it in the same file as your element definition, e.g.
<core-style id="x-dialog">
html /deep/ #dialog {
color: red;
}
</core-style>
<core-style ref="x-dialog"></core-style>
<polymer-element name="my-element" noscript>
<template>
<paper-dialog id="dialog"></paper-dialog>
</template>
</polymer-element>
Extend paper-dialog and style the new element:
<polymer-element name="my-paper-dialog" extends="paper-dialog" noscript>
<template>
<!-- or use core-style -->
<style>
:host {
color: red;
}
</style>
</template>
</polymer-element>
Live examples: http://jsbin.com/subanakuna/1/edit?html,output

Is it bad practice to style element directly in polymer?

For example I could do the next thing:
<polymer-element name="hello-world">
<template>
<div style="background-color: red">
hello world!
</div>
</template>
</polymer-element>
Furthermore, I could also style the element dynamically doing the next:
HelloWorld.create() : super.create() {
createShadowRoot().children = [
new DivElement()
..style.color = SOME_GLOBAL_COLOR
..text = 'Hello World!'
];
}
Instead of:
<polymer-element name="hello-world">
<template>
<style>
.somediv {
background-color: red;
}
</style>
<div class="somediv">
hello world!
</div>
</template>
</polymer-element>
It is considered good practice. It provides encapsulation.
The selectors like /deep/ can reach into the element, that makes it easy to override styles from the outside for example for theming or customization.
Styles from the outside have higher priority too, to make this easy.
Styles using the /deep/ combinator can cause performance problems especially on browsers that don't support shadowDOM natively but use the polyfills.
I would provide basic/default styling inside the component and site-specific customization outside the element.
The verbosity (and indirectly complexity) of the component style is the criteria to keep an eye on. I personnally find one-file components easier to maintain.
Aside this organizational consideration, as style elements are part of the template, observable (hence published) properties can be put directly inside the css. This is quite handy especially to:
provide handles to external customization.
dynamically update some css properties, like element box height.

Resources