Why do I need to write ::shadow after :host? - polymer

I'm looking for an explanation as to why I would need to write :host::shadow in order for my inherited element to style elements in the shadow tree of my base element.
In the following sample code, I would like to be able to style the label for the complete element:
<polymer-element name="my-foo">
<template>
<style>
:host label {
color: red;
}
</style>
<label>My label: </label>
</template>
<script>
Polymer('my-foo');
</script>
</polymer-element>
<polymer-element name="my-bar" extends="my-foo">
<template>
<style>
:host label {
font-weight: bold;
}
</style>
<shadow></shadow>
<input />
</template>
<script>
Polymer('my-bar');
</script>
</polymer-element>
<my-bar></my-bar>
http://jsfiddle.net/Lz0Lcrx3/
The above example makes the label appear red but not bold. In order to fix it I need to change the style on my inherited element to include ::shadow.
<style>
:host::shadow label {
font-weight: bold;
}
</style>
http://jsfiddle.net/Lz0Lcrx3/1/
I know I'm dealing with two shadowroots in this case and I guess the ::shadow is to make sure we are applying the style to all of them, but I figured that :host would've been enough.
Can someone offer an explanation?

After some more searching I found the following article that I think explains this:
http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-301/
From what I understand, the <shadow></shadow> insertion point will make it necessary to use ::shadow from another shadowDOM tree since we are in fact crossing boundaries. Shadow boundaries that is, not element boundaries.

Related

How to set styles to a slotted element in a template tag

<template id="element-details-template">
<link href="./src/components/lit-button/button.scss" rel="stylesheet">
<svg ..</svg>
<span slot="buttonLabel">span1</span>
<span class="name" slot="buttonSubLabel">span2</span>
</template>
I want to style just the second span in an external css file. But the styles are not getting affected/reflected. I am confused as to what the problem might be?
The below code is my css:
:host {
#element-details-template {
span.name {
text-transform:lowercase;
}
}
If the class is in an external css file (like the global one styles.css, or a parent one) just try removing the :host directive. To be sure it should affect the span element, use also !important directive. You can also specify the only class/classes you want to affect with the css class like:
(if the class were there's the html code is called for example "test.html")
app-test{
#element-details-template{
span.name {
text-transform:lowercase !important;
}
}
}
While if you want this class to affect the entire application (if you put this css class in the styles.css) when you use those id and class name, you can remove the app-test block:
#element-details-template{
span.name {
text-transform:lowercase !important;
}
}
I tried and with the :host block it didn't work but in this way it should work. Hope it's helpful :)

HTML Element being ignored while applying CSS on it

I've been using Bootstrap's vue form-group in order to create input fields.
I'm trying to apply certain CSS on the 'legend' Element for the following code:
<fieldset id="__BVID__59" class="form-group" required="required">
<legend class="col-form-label pt-0">Login</legend>
<div tabindex="-1" role="group">
<input type="text" class="form-control">
<!----><!----><!---->
</div>
</fieldset>
My goal is to add required asterisks to the labels, therefore my suggestion would be:
.form-group[required] legend::after {
content: '*';
color: red;
}
but my CSS doesn't seem to recognise the legend element, no matter what I do or how I write it.
it's the same if I use label instead of legend.
I've tried also using nth-child(0) of fieldset (the parent) but it seems like it's just ignoring this child and nothing really happens. I thought it has something to do with the CSS configurations of the bootstrap i'm using, but also using !important doesn't seem to do anything.
any help would be highly appreciated.
In Vue if you use a scoped style tag <style scoped> you wont be able to select subcomponents by default. To do so you need to use a deep selector
<style scoped>
.form-group[required] ::v-deep legend::after {
content: '*';
color: red;
}
</style>
Without scoped your css should work as expected, but i don't recommend doing so as it can mess with other components and be messy to debug.
<style>
.form-group[required] legend::after {
content: '*';
color: red;
}
</style>

HTML Element styling not working in scoped style

For some reason my element styling isn't working when using scoped. When inspecting the element the styling is not applied when using scoped. I need to use scoped because I want the styling only be applied within this component. I'm using nuxt.js, no idea if this has anything to do with the problem.
Not working:
<style scoped>
a {
color: red !important;
text-decoration: underline !important;
}
</style>
Working:
<style>
a {
color: red !important;
text-decoration: underline !important;
}
</style>
Any ideas?
As explained in the relevant documentation, scoped CSS applies a data- attribute to all selectors in the provided CSS so that it only applies to the elements of the component, not outside of it, nor to nested sub-components.
For example, with this markup:
<app>
<a>outside link</a>
<Parent>
<a>parent link</a>
<Child>
<a>child link</a>
</Child>
</Parent>
</app>
scoped CSS of <Parent> will only affect parent link and will not affect the outside link nor the child link.
From what you're describing, you are trying to style a sub-component link.
To make your scoped CSS selectors affect deeply (apply to sub-components as well) you have to use the deep >>> combinator:
<style scoped>
* >>> a {
color: red;
text-decoration: underline;
}
</style>
To see it in action, consider this example.

The proper way to restyle a core paper element globally in Polymer

The easy answer is, just include
paper-button{
background: black;
}
, but that wouldn't restyle the element if it is contained in another element. The solution used to be
html /deep/ paper-button{
background: black;
}
which still works fine, but is deprecated from the Shadow DOM spec. So what is the proper solution?
PS. Purely to be complete in case it somehow matters: What I actually want to reproduce properly is
html /deep/ paper-button.main{
[...]
}
You can use CSS custom properties to change the paper-button style globally.
Since paper-button exposes the --paper-button mixin, you can try the following inside your document -
<style is="custom-style">
simple-dialog, paper-button {
--paper-button: {
background-color: black;
color: white;
};
}
</style>
Have a look at this plunker.

Apply <style> rules to another element instead

I have a <style> element that applies some global styles, like A { color: red } as opposed to my stylesheet that styles A { color: green } (purely as an example).
How can I modify all of the styling in my <style> element so that are "contained" and only apply the styling to children of a parent element I specify.
A { color: red } becomes #myelem A { color: red }
.myclass { display: none; } becomes #myelem .myclass { display: none }
Would I have to find the <style> element, parse the contents, replace each selector then update the element contents with it fixed?
Is there an alternative to modifying the contents of my <style> element?
Why am I doing this? I have HTML that is stored in a database that I want to edit (this is a CMS). The HTML can contain <style> elements, and I cannot trust who writes the CSS to write it in scope. I could prevent users from using the <style> element, but I'd rather not. I have no control over the original CSS. Only what I get back in my server/clientside code.
If all else fails, I might have to load it into an iFrame... :(
Ooooooo Firefox supportes <style scoped> which only applies to the parent where the <style> element is located in the DOM. Too bad it's not supported in any other browser. :(
As you mentioned, you can use:
<style scoped>
...
</style>
Although it is only supported natively in Firefox, you can use this jQuery polyfill to get it to work in other browsers.
Use the child selector:
#yourElement > a { color: green; }
JQuery:
$( "parent_type > children_type" ).css("param","value");
example
$( "#myid > div" ).css("display","none");
here's a link
JSFiddle