I create a file called my-mixins.html containing:
<link rel="import" href="../polymer/polymer.html">
<style is="custom-style">
:root {
--red: {
color: red;
};
}
// This won't work
.green: {
color: green;
}
</style>
Then I create an element my-element.html:
<link rel="import" href="bower_components/my-mixins/my-mixins.html">
<link rel="import" href="../polymer/polymer.html">
<dom-module is="my-element">
<style>
.red {
#apply(--red);
}
...
</style>
<p class="red">This is red</p>
<p class="green">This is not green</p>
<script>
Polymer({
is: 'my-element'
});
</script>
</dom-module>
While --red worked (as it's supposed to), .green didn't.
I realise this is to make sure that styling doesn't spill etc. But... what's the actual rule here? How come --red was set and it's available to the module, whereas green isn't?
The answer to my specific question was here:
https://www.polymer-project.org/1.0/docs/devguide/styling#custom-style
Specifically:
Polymer provides a custom element for defining styles in the main document that can take advantage of several special features of Polymer's styling system:
Document styles defined in a custom-style are shimmed to ensure they do not leak into local DOM when running on browsers without native Shadow DOM.
Custom properties used by Polymer's shim for cross-scope styling may be defined in an custom-style. Use the :root selector to define custom properties that apply to all custom elements.
So, the docs explain that the :root selector specifically is to be used to set cross-scope custom properties...
I believe it works that way to provide the option to tweak internal styles using CSS custom properties as style placeholders.
Whereas the reason .green is not leaking is due to the scoped CSS feature of Shadow DOM.
You can read more about stylehooks in Eric Bidelman's Shadow DOM v1 primer
Related
I want the css rules in my webcomponent to be global in my page, not only in this local dom.
<dom-module id="x-custom">
<template>
<style>
h1{
color: red;
}
<!-- I want not only this local h1 to be red but also all h1 in my page -->
</style>
<h1>Hello stackoverflow<h1>
</template>
<script>
Polymer({
is: 'x-custom'
});
</script>
</dom-module>
Any help?
Thanks
Here's an example on how you can do it. But this will work only in case of shady-dom it will fail for shadow-dom. For shadow dom one option is to bind color of h1 wherever to use it to same default CSS variable something like
h1{
color:var(--my-color,--default-color);
//or
color:var(--my-color,var(--default-color)); //if you are using polymer 1.7.
}
And then you can assign the value to --default-color in your app-theme or in index.html like
<style is="custom-style">
:root{ //you can use html instead of :root if you are using polymer 1.7
--default-color:red;
}
</style>
Second, option will be to create a shared-style and include it everywhere you use h1 tag.
Although not exactly what you are looking for, shared styles may be an option even though they will need to be explicitly included for all your components.
To share style declarations between elements, you can package a set of style declarations inside a element. In this section, a holding styles is called a style module for convenience.
https://www.polymer-project.org/1.0/docs/devguide/styling#style-modules
I'd like to my own HTML tags but I don't want new tags that might use the same name to cause them to break in the future.
Is this a good idea? Could I use a namespace to avoid conflicts?
Example:
HTML :
<b:HGroup>
<span>item 1</span><span>item 2</span><span>item 3</span>
</b:HGroup>
CSS:
#namespace b "library://ns.example.com/framework/1";
b|HGroup {
display:inline-block;
vertical-align: middle;
}
I read a related question and it suggests DTD. I'd rather not create a DTD but if it's necessary, then I'd like to define it inline. Also, I'd like it to be run as HTML5, not XHTML.
Note:
I do NOT want to use div plus a class.
As far as I understand it, it looks like custom elements I've written will not be overwritten by future elements of the same name if I explicitly register my custom element. Here is a quote from the W3:
Because element registration can occur at any time, a non-custom
element could be created that might in the future become a custom
element after an appropriate definition is registered. Such elements
are called undefined potentially-custom elements. If such a definition
is ever registered, the element will be upgraded, becoming a custom
element.
I've included a full page prototype based on the answers and I can't get it to attach any CSS to any element with a namespace. I've included some JS I found on one of the links but commented out part of it that was giving me errors. My main concern is getting elements with namespaces to be styled by the CSS with namespaces. From how I understand it that should work without JS.
<!DOCTYPE html>
<html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:s="http://www.w3.org/2002/spark"
xmlns:space="http://www.w3.org/2002/space"
xmlns:spaced="http://www.w3.org/2002/spaced">
<head>
<script>
"use strict";
const inDocument = document.querySelector("example-element");
const outOfDocument = document.createElement("example-element");
// Before the element definition, both are HTMLElement:
//console.assert(inDocument instanceof HTMLElement);
//console.assert(outOfDocument instanceof HTMLElement);
//class ExampleElement extends HTMLElement {};
//customElements.define("example-element", HTMLElement);
//class ExampleElement3 extends HTMLElement {}
//customElements.define("element3", ExampleElement3);
//document.body.appendChild(outOfDocument);
</script>
<style>
#namespace s url(http://www.w3.org/2000/spark);
#namespace space url(http://www.example.com/2000/spark-space);
#namespace spaced "http://www.example.com/2002/spark-spaced";
example-element {
color: red;
display:block;
}
element2 {
color:green;
font-weight:bold;
}
s|element3 {
color:yellow;
}
space-element {
color:yellow;
}
space|space-element {
display:block;
color:yellow;
}
spaced|spaced-element {
display:block;
color:yellow;
}
</style>
</head>
<body>
<example-element>example-element</example-element>
<element2>element 2</element2>
<space-element>space element</space-element>
<s:element3>s namespace element 3</s:element3>
<space:space-element>space namespace el</space:space-element>
<spaced:spaced-element>spaced namespace el</spaced:spaced-element>
</body>
</html>
Custom HTML elements are supported by HTML5, but according to the specs they should contain a - character :
The name must contain a dash (-). So for example, <x-tags>,
<my-element>, and <my-awesome-app> are all valid names, while <tabs>
and <foo_bar> are not. This restriction allows the parser to
distinguish custom elements from regular elements but also ensures
forward compatibility when new tags are added to HTML.
See this article for a good introduction.
Applying CSS to custom HTML elements works the same way as applying CSS to standard HTML elements :
custom-element {
font-weight: bold;
background-color: #ff0;
}
<custom-element>
This is a custom HTML element
</custom-element>
You have a well researched question here. In doing so, you've eliminated all of the "valid" solutions.
You can definitely do what you have proposed, which (harmlessly*) breaks the standards. To be future proof, all HTML standards allow for unknown elements, instructing browsers to ignore them (essentially, they all become <span> elements) since there's no indication of what to do with them, though CSS can indeed affect them. This will work in ALL browsers, even Mosaic and the original IE (though CSS won't work in such ancient browsers).
As you already noted, the "proper" way to do this would be to define your own Document Type Definition (DTD) that can then be included at the top of your ~HTML document with the <!DOCTYPE> tag. This is probably overkill, but it is technically the right approach.
Another solution (that you've also eliminated) would be to use <span class="HGroup"> for inline elements and <div class="HGroup"> for block elements since these elements don't actually do anything by default.
A variant of that solution is to override the action of some otherwise useless tag and disable its standard properties in CSS, <s> for example:
s {
text-decoration: none; /* remove line-through */
display: inline-block;
vertical-align: middle;
}
(* The "harm" you can run into with custom element names is that if you don't specify a DTD (your own or else an existing one with an exact version), a future version of the HTML standard could theoretically define some undesired property for your custom element.)
Question
Which method of placing the <script> tags is "best-practice?"
Inside the <dom-module>?
or
Outside the <dom-module>?
Also, please answer:
Why?
What is the source of your answer?
What downside risks are there by doing it the "wrong" way?
Polymer Starter Kit: OUTSIDE
In the Polymer Starter Kit, the my-list.html and my-greeting.html files place the <script> tag outside the <dom-module>.
Like this:
<dom-module>
<style>...</style>
<template>...</template>
<dom-module>
<script>...</script>
Other Experts: INSIDE
However, I have heard and seen several examples from Google employees and Google developers that suggest the <script> tags should go inside the <dom-module>.
Like this:
<dom-module>
<style>...</style>
<template>...</template>
<script>...</script>
<dom-module>
The correct answer is - it shouldn't matter. While the documentation is indeed as #Mowzer noted, this is just an example rather than a definition. At least some actual Polymer elements like e. g. iron-image have it outside dom-module.
The relationship between the dom-module and the object Polymer constructor defines is established through the 'is' property of the object passed to the Polymer constructor and the id attribute of the dom-module.
From Local DOM guide:
Give the <dom-module> an id attribute that matches its element’s is property and put a inside the <dom-module>. Polymer will automatically clone this template’s contents into the element’s local DOM.
As a side note, you can also successfully use <script src="external.js"></script> to separate the html from the JS - I'm just guessing this is one possible reason for this question. The only drawback to this (AFAIK) is that in this case a vulcanized version of your element will show incorrect (offset) code line numbers for JS errors.
Looks like <script> tags should go inside the <dom-module>.
Per this definition in the developer guide.
Element definition
<dom-module id="element-name">
<template>
<style>
/* CSS rules for your element */
</style>
<!-- local DOM for your element -->
<div>{{greeting}}</div> <!-- data bindings in local DOM -->
</template>
<script>
// element registration
Polymer({
is: "element-name",
// add properties and methods on the element's prototype
properties: {
// declare properties for the element's public API
greeting: {
type: String,
value: "Hello!"
}
}
});
</script>
</dom-module>
I'm tinkering around with Polymer again and there is something I want to do but it doesn't work and the workaround looks so messy. I want to style an element but take advantage of Data Binding. Basically I try to do this:
<dom-module id="proto-element">
<template>
<style>
#wrapper{
width:{{pixels}};
background: #e1e1e1;
}
#bar{
width:80%;
}
</style>
<div id="wrapper">
<div id="bar" style$={{barStyle}}>I'm the bar! <b>{{test}}</b></div>
</div>
</template>
</dom-module>
<script>
Polymer({
is: "proto-element",
ready: function() {
this.pixels = "300px";
this.test = "Fear me!"
}
});
</script>
The text bound to this.test works flawlessley. But the moustache tags that are inside of style get ignored. Is there a simple solution to this? Because using the inline style$= syntax is super messy when you are working with multiple css rules and also you always need to concatinate a string for it to work if the value you want is obtained elsewhere. Any ideas on a nice clean solution?
I'm afraid what you want is (at least currently) not possible. Data-binding works only inside <template> tags, either a <template is="auto-binding"> or the template inside a <dom-module>.
In the <style> tag, data-binding simply won't work. You could try putting another <style> tag INSIDE the <template> tag (which is messy), but you still won't get the data-bound property to work, since the curly brackets {{...}} must be inside an individual tag and can't be (currently) surrounded by whitespaces (spaces, newlines, ...), see docs:
String concatenation is not supported inside a tag, and the tag can’t contain any whitespace ...
tl;dr: There are two issues that prevent you from achieving what you want: 1) Data-binding only works inside a template tag and 2) if you want to print out data-bound properties, they must be enclosed inside a html tag.
You could try a different approach:
ready: function () {
this.$.wrapper.style.width = '300px';
}
this.$ allows you to easily access any DOM element with an id attribute (for example your #wrapper, which is accessed as this.$.wrapper) and from there, you can set any other attribute of the element (this.$.wrapper.style.width in this case).
EDIT: Also, I just noticed that you've actually put <style> tag inside the <template>, which is not advised. Since Polymer 0.8, this is the recommended structure for a custom element:
<dom-module>
<style> ... </style>
<template> ... </template>
</dom-module>
<script> ... </script>
Check out the Overview and Migration guide.
EDIT 2: As of Polymer 1.1 the suggested element structure (as pointed out by Max Waterman) has been updated to:
<dom-module>
<template>
<style> ... </style>
...
</template>
<script> ... </script>
</dom-module>
Is there a way to force a css link to a file to be the one that is used without relying on cascading order to determine what gets overwritten?
I am using a CMS where I can add new css links but cannot change the cascading order in the header tag:
<link rel="stylesheet" href="new.css" type="text/css" />
<link rel="stylesheet" href="old.css" type="text/css" />
I need "new.css" to overide "old.css" without overwriting the code of old.css. I do not have access to simply change the order of the header code, I so wish I could!
There's no way what you're looking for.
Your last stylesheet would override the previous stylesheet rules.
But if you can use javascript or jquery then you may shift the order like this:
jQuery:
$('link[ref="old.css"]').insertBefore($('link[ref="new.css"]'));
Actually you can if you make the selector more specific. You can do this by simply adding "body" before the actual selector.
Example:
.button {
color: blue;
}
Would be ignored by using
body .button {
color: green;
}
Quick fiddle: http://jsfiddle.net/4cbs5por/
If your CMS allows you to add new CSS links, it should be smart enough to put the new one the bottom. If it's putting it on the top and you don't want to mess with jQuery, you can just copy the content from the "old.css" and paste that into the "new.css" file and vise-versa. That way you'll have the correct content in the bottom file which will override the top link.