Relate CSS variables to each other in context - css

Background: trying to create an element for easily embedding Font Awesome 5.10.2 Duotone icons into any piece of HTML.
This icon element uses HTML attributes which should map to a specific icon where the mapping is purely controlled by the CSS author.
<x pay></x> <!-- <- icon value for pay should be customizable by CSS author -->
Below is my solution but I wonder ...
Can one reduce
x {
position: relative;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-style: normal;
font-variant: normal;
text-rendering: auto;
white-space: nowrap;
font-family: var(--fa-5-d);
font-weight: var(--fa-d);
background: var(--x-background);
line-height: 1em !important;
}
x::after { position: absolute; left: 0; bottom: 0; }
x::before { color: var(--fa-primary-color, inherit); opacity: 1; opacity: var(--fa-primary-opacity, 1.0); }
x::after { color: var(--fa-secondary-color, inherit); opacity: var(--fa-secondary-opacity, 0.4); }
x:before { --fa-credit-card: "\f09d"; }
x:after { --fa-credit-card: "\10f09d"; }
<x pay></x>
this ↓
x[pay]:before,
x[pay]:after { content: var(--fa-credit-card); }
to this ↓ (avoiding x[pay]:before, x[pay]:after repetition)
x[pay] { --content: var(--fa-credit-card); }
in essence
set a CSS variable once on a parent to a value v
that diverges into different child values v₁ and v₂ related to v?
?

A convenience improvement using web components / custom elements:
<link href='//cdn.blue/{fa-5.10.2}/css/all.css' rel=stylesheet>
<link href='//cdn.blue/{fa+}/var.css' rel=stylesheet>
<link href='//cdn.blue/{fa+}/x-i.css' rel=stylesheet>
<script src='//cdn.blue/<shin>/shin-element.js'></script>
<script>
class XI extends ShinElement {
constructor() {
super(`<style></style>`);
ShinElement.IPA(this, 'jsUpdate', { a: 'js-update', t: ShinElement.Number0 });
}
connectedCallback() { XI.css(this); }
static css(t) {
const c = getComputedStyle(t);
const i = c.getPropertyValue('--i').trim();
const s = t._.QS("style");
s.textContent = `:host:before, :host:after { content: var(${i}); }`;
}
static get observedAttributes() { return [ 'js-update' ]; }
attributeChangedCallback(a, o, n) {
switch (a) {
case "js-update":
const u = this.jsUpdate;
if (u > 0) this._jsu = setInterval(XI.css, u, this);
else { clearInterval(this._jsu); delete this._jsu; }
break;
}
}
}
XI.define();
</script>
<style>x-i[pay] { --i: --fa-user-edit; }</style>
<x-i pay js-update=200 id=x></x-i>
https://cdn.blue/<shin>/docs/ShinElement.html
https://codepen.io/cetinsert/pen/QWLZgwZ?editors=1000
The need for js-update (HTML), jsUpdate (JS) for doing live CSS edits is unfortunate.
x.jsUpdate = 0; // to disable getComputedStyle updates
Thus I still wonder if there is a better solution - be it CSS-only or using web components.

Related

Can't do JS-in-CSS for css-houdini paint?

I'm trying to copy this example; I have a scss file that I'm using with modular CSS in a React/Electron project. I want to define the function to be used by paint in the same file, as in the example:
.container {
--background-canvas: (ctx, geom) => {
// left blank for minimal example
};
background-image: paint(background-canvas);
display: flex;
margin: 4px;
border-radius: 12px;
height: 75px;
}
However, this fails to compile with CssSyntax error: Expected a pseudo-class or pseudo-element. (2:23). What am I not doing that the demo is?
Alright, I got it mostly working. The only part that isn't working is the transition which I'm not sure why it isn't.
-- Edit: I got that working via: https://css-houdini.rocks/animating-gradient
CSS.registerProperty({
name: '--multiplier',
syntax: '<number>',
inherits: false,
initialValue: 0
})
I couldn't find a way to get the CSS in JS parser to treat { } as a part of a string rather than special characters, so I used an array to allow me to run the relevant function calls in the background-canvas function.
--background-canvas: (ctx, geom) => [ ctx.moveTo(0, 0),
ctx.lineTo(
var(--pad) + (geom.width - var(--slant) - var(--pad)) * var(--multiplier),
0
),
ctx.lineTo(
var(--pad) + (geom.width - var(--slant) - var(--pad)) * var(--multiplier) +
var(--slant),
geom.height
),
ctx.lineTo(0, geom.height), ctx.fillStyle = \`var(--color)\`, ctx.fill() ];
The real fun part about this solution is that you still need to actually register the paint function.
I did that in a similar way as a previous answer I have: https://stackoverflow.com/a/61966697/13175138 which uses this https://twitter.com/DasSurma/status/983305990731894785
As a note, this solution from that example uses eval as part of it's registerPaint function, so this could be problematic from a security standpoint, though the paint code should theoretically be sandboxed from the main runtime.
const Demo = styled.div`
background: #1108a0;
padding: 50px 0;
`;
const Test = styled.div`
--color: cyan;
--multiplier: 0.24;
--pad: 30;
--slant: 20;
--background-canvas: (ctx, geom) => [ ctx.moveTo(0, 0),
ctx.lineTo(
var(--pad) + (geom.width - var(--slant) - var(--pad)) * var(--multiplier),
0
),
ctx.lineTo(
var(--pad) + (geom.width - var(--slant) - var(--pad)) * var(--multiplier) +
var(--slant),
geom.height
),
ctx.lineTo(0, geom.height), ctx.fillStyle = \`var(--color)\`, ctx.fill() ];
background: paint(background-canvas);
transition: --multiplier 0.4s;
font: bold 6em sans-serif;
color: yellow;
text-shadow: 0 3px 1px cyan;
line-height: 1.5em;
width: max-content;
padding-left: 30px;
padding-right: 50px;
isolation: isolate;
&:hover {
--multiplier: 1;
}
& span {
mix-blend-mode: exclusion;
}
`;
const App = () => (
<Demo>
<Test className="el" right={'right'}>
<span>JS-in-CSS</span>
</Test>
</Demo>
);
ReactDOM.render(<App />, document.getElementById('root'));
/*if ("paintWorklet" in CSS) {
console.log('here')
const src = document.querySelector('script[language$="paint"]').innerHTML;
const blob = new Blob([src], {
type: 'text/javascript'
});
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
}*/
#media (max-width: 900px) {
.el {
font-size: 4em;
}
}
#media (max-width: 500px) {
.el {
font-size: 2.4em;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react-is#17.0.1/umd/react-is.production.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="root"/>
<script language="javascript+paint">
registerPaint('background-canvas', class {
static get inputProperties() {
return ['--background-canvas'];
}
paint(ctx, geom, properties) {
eval(properties.get('--background-canvas').toString())(ctx, geom, properties);
}
})
</script>
<script>
// Register the property so it become animatable
CSS.registerProperty({
name: '--multiplier',
syntax: '<number>',
inherits: false,
initialValue: 0
})
if ("paintWorklet" in CSS) {
const src = document.querySelector('script[language$="paint"]').innerHTML;
const blob = new Blob([src], {
type: 'text/javascript'
});
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
}
</script>

Clarifying the status of custom attributes in HTML Custom Elements in WebComponents

Until recently, whenever I've needed a custom attribute in my HTML, I've always used an HTML5 data-* custom attribute.
Having recently started experimenting with WebComponents and, specifically, Custom Elements, I have started thinking in terms of custom attributes which are not HTML5 data-* custom attributes.
Before inadvertently adopting any non-recommended practices, I would like to clarify the following...
In the list below we have 4 elements:
Element i is a standard element with a data-* attribute
Element ii is a standard element with a custom attribute
Element iii is a custom element with a data-* attribute
Element iv is a custom element with a custom attribute
const toggleDataAttribute = (e) => {
e.target.dataset.inverted = (e.target.dataset.inverted === 'true') ? 'false' : 'true';
}
const toggleCustomAttribute = (e) => {
if (e.target.getAttribute('inverted') === 'true') {
e.target.setAttribute('inverted', 'false');
}
else {
e.target.setAttribute('inverted', 'true');
}
}
const toggleInvert = (e) => {
if (e.target.dataset.inverted) {
toggleDataAttribute(e);
}
else {
toggleCustomAttribute(e);
}
}
// Attach click event TO <div> elements
let divs = [...document.getElementsByTagName('div')];
divs.forEach((div) => div.addEventListener('click', toggleInvert, false));
// Attach click event TO <my-circle> elements
let myCircles = [...document.getElementsByTagName('my-circle')];
myCircles.forEach((myCircle) => myCircle.addEventListener('click', toggleInvert, false));
// Define <my-circle> element
class myCircle extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: "open"});
}
connectedCallback() {
this.root.appendChild(document.createElement('slot'));
}
}
customElements.define('my-circle', myCircle);
aside {
position: absolute;
top: 0;
right: 0;
width: 280px;
line-height: 24px;
}
div {
float: left;
margin: 0 12px 12px 0;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 36px;
border-radius: 50%;
cursor: pointer;
}
my-circle {
display: block;
float: left;
margin: 0 12px 12px 0;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 36px;
background: radial-gradient(#fff, #000);
border-radius: 50%;
cursor: pointer;
}
my-circle:first-of-type {
clear: left;
}
div:nth-of-type(1) {
background: radial-gradient(rgb(255, 255, 0), rgb(255, 0, 0));
}
div:nth-of-type(2) {
background: radial-gradient(rgb(255, 255, 0), rgb(0, 163, 0));
}
my-circle:nth-of-type(1) {
background: radial-gradient(rgb(255, 255, 0), rgb(223, 163, 0));
}
my-circle:nth-of-type(2) {
background: radial-gradient(rgb(255, 127, 127), rgb(255, 0, 0));
}
div[data-inverted="true"],
div[inverted="true"],
my-circle[data-inverted="true"],
my-circle[inverted="true"] {
filter: hue-rotate(180deg);
}
<div data-inverted="false">i</div>
<div inverted="false">ii</div>
<my-circle data-inverted="false">iii</my-circle>
<my-circle inverted="false">iv</my-circle>
<aside>
<p><strong>Click</strong> on each of the circles on the left to invert their backgrounds.</p>
</aside>
Although the set up above works technically, which of the following is true:
A) Custom attributes may be used universally, in standard elements and custom elements.
Conclusion: Elements i, ii, iii & iv are all valid
B) Custom attributes may only be used in custom elements. They are invalid elsewhere.
Conclusion: Elements i, iii & iv are valid, while ii is invalid
C) Data-* attributes are for standard elements, custom attributes are for custom elements.
Conclusion: Elements i & iv are valid, while ii & iii are invalid
D) Custom attributes are not even a thing. Where did you get this idea from?
Conclusion: Elements i & iii are valid, while ii & iv are invalid
Added:
To illustrate my question above, I'd like to give an example of where custom attributes appear not to be valid:
Go to: https://validator.w3.org/nu/#textarea
Select text input
Enter:
<!DOCTYPE html>
<html lang="">
<head>
<title>Test</title>
</head>
<body>
<div data-inverted="false">i</div>
<div inverted="false">ii</div>
</body>
</html>
Check the markup
The validator returns the error:
Error: Attribute inverted not allowed on element div at this point.
From line 10, column 1; to line 10, column 22
i</div>↩↩<div inverted="false">ii</di
Though... I'm not sure if the tool at https://validator.w3.org/nu/ is outdated and / or abandoned and the Error returned should no longer be regarded as an error in 2020 (?)
All 4 usages work, so why should they be invalid?
data- prefix gives the added bonus they are available in element.dataset.
-- Attributes are Attributes -- , nothing special in the Custom Elements API,
apart from observedAttributes(). Yes, you can use data-* attributes there to.
note
class myCircle extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: "open"});
}
connectedCallback() {
this.root.appendChild(document.createElement('slot'));
}
}
can be written as:
class myCircle extends HTMLElement {
constructor() {
super()
.attachShadow({mode: "open"})
.append(document.createElement('slot'));
}
}
because super() returns 'this'
and attachShadow both sets and returns this.shadowRoot for free
you are not doing anything with appendChild() return value, so append() (which can take multiple parameters) is enough.
Also note there is a toggleAttribute method.
https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append
https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute

CSS codes does not work in component CSS but works in style.css in Angular

I have one file that use nested checkbox in angular. I have created one component and put the below code in ngOnInit() body
const mainUl = document.getElementById('siteDetail');
mainUl.classList.add('ulClassStyle');
const names = ['Laptops', 'TVs', 'Microphones'];
const secondLi = document.createElement('li');
secondLi.classList.add('liClassStyle');
const secondSpan = document.createElement('span');
secondSpan.classList.add('caret');
const secondMaincheckbox = document.createElement('input');
secondMaincheckbox.type = 'checkbox';
secondMaincheckbox.id = 'secondOption';
secondMaincheckbox.checked = true;
const secondMainlbl = document.createElement('label');
secondMainlbl.id = 'label';
secondMainlbl.htmlFor = 'secondOption';
secondMainlbl.classList.add('labelClassStyle');
secondMainlbl.appendChild(document.createTextNode('Electronics'));
secondSpan.appendChild(secondMainlbl);
secondLi.appendChild(secondMaincheckbox);
secondLi.appendChild(secondSpan);
const secondSubUl = document.createElement('ul');
secondSubUl.classList.add('ulClassStyle');
for (let i = 0; i < names.length; i++) {
const name = names[i];
const secondSubLi = document.createElement('li');
secondSubLi.classList.add('liClassStyle');
const secondSubCheckbox = document.createElement('input');
secondSubCheckbox.type = 'checkbox';
secondSubCheckbox.name = 'name' + i;
secondSubCheckbox.value = 'value';
secondSubCheckbox.id = 'secondSubCheckboxid' + i;
secondSubCheckbox.checked = true;
secondSubCheckbox.onclick = function() { secondMyfunction(this); };
secondSubCheckbox.classList.add('secondSubOption');
secondSubLi.appendChild(secondSubCheckbox);
secondSubLi.appendChild(document.createTextNode(name));
secondSubUl.appendChild(secondSubLi);
secondSubUl.classList.add('nested');
}
secondLi.appendChild(secondSubUl);
mainUl.appendChild(secondLi);
const secondCheckboxes = document.querySelectorAll('input.secondSubOption');
const secondCheckall = document.getElementById('secondOption');
secondCheckall.onclick = function() {
for (let i = 0; i < secondCheckboxes.length; i++) {
secondCheckboxes[i].checked = this.checked;
}
};
function secondMyfunction(checkBox) {
const secondCheckedCount = document.querySelectorAll('input.secondSubOption:checked').length;
secondCheckall.checked = secondCheckedCount > 0;
secondCheckall.indeterminate = secondCheckedCount > 0 && secondCheckedCount < secondCheckboxes.length;
}
const secondToggler = document.getElementsByClassName('caret');
for (let i = 0; i < secondToggler.length; i++) {
secondToggler[i].addEventListener('click', function() {
this.parentElement.querySelector('.nested').classList.toggle('active');
this.classList.toggle('caret-down');
});
}
and then I wrote this in the CSS code:
body {
color: #555;
font-size: 1.25em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
hr {
margin: 50px 0;
}
.ulClassStyle
{
list-style: none;
}
.container {
margin: 40px auto;
max-width: 700px;
}
.liClassStyle {
margin-top: 1em;
}
.labelClassStyle {
font-weight: bold;
}
.nested {
display: none;
}
.caret {
cursor: pointer;
user-select: none;
}
.caret::before {
content: "\25B6";
color: black;
display: inline-block;
margin-right: 6px;
}
.caret-down::before {
transform: rotate(90deg);
}
.active {
display: block;
}
If I put this CSS code in main css file that: style.css, it works fine without any problem as expected. But, If I put in the CSS for the component it does not work. Any idea why it is like this?!
Set encapsulation to None in the component in which style.css not working like this >
#Component({
selector: 'app-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss'],
encapsulation: ViewEncapsulation.None
})
Angular is working in the way that it's suppose to working if your write styles in component.css those will get applied to that particular component only.style.css contains global styles so they will get applied thoughout the application you have two option to make you style global here one can be encapsulation: ViewEncapsulation.None but that will make all styles in this component global and will affect other components as well other is use ::ng-deep to a particular style only eg
::ng-deep .liClassStyle {
margin-top: 1em;
}
So you should use styles applied to body etc in style.css and component related style in component.css
I found that this problem is happening because I am adding these elements dynamically at the run the time. So, it must be added in the general style.css or write:
encapsulation: ViewEncapsulation.None
which will do the same as it make css general
Thanks for guide.

How to change CSS classes according to time received by API

I'm building a weather app in React and so far so good. The problem is now I want to have a "lightmode" and "darkmode" which should be CSS classes that change according to sunrise/sunset times received by an API. When I did it in vanilla JS I used a function that converted the timestamps into hours and compared the current hour to sunrise/sunset and then decided which class to present, like so
function getMode(response) {
let today = response.data.dt;
let timezone = response.data.timezone;
let difference = today + timezone - 3600;
let hours = timeConverter(difference);
let mode = document.getElementById("app");
let sunrise = response.data.sys.sunrise;
let difference2 = sunrise + timezone - 3600;
let currentSunrise = timeConverter(difference2);
let sunset = response.data.sys.sunset;
let difference3 = sunset + timezone - 3600;
let currentSunset = timeConverter(difference3) - 1;
if (hours > currentSunset) {
mode.classList.add("darkmode").remove("lightmode");
}
else if (hours < currentSunrise) {
mode.classList.add("darkmode").remove("lightmode");
} else {
mode.classList.remove("darkmode").add("lightmode");
}
}
axios.get(apiUrl).then(getMode)
<body>
<div id="app" class="lightmode">
The CSS then looked like this
.lightmode h1 {
font-family: "Josefin Sans", sans-serif;
text-align: right;
color: #06384d;
font-size: 32px;
font-weight: 700;
}
.lightmode {
font-family: "Josefin Sans", sans-serif;
background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
border-style: solid;
border-radius: 30px;
border-color: #096386;
}
#app {
margin: 10px 400px;
padding: 10px 10px;
}
(...)
.darkmode h1 {
font-family: "Josefin Sans", sans-serif;
text-align: right;
color: #fff;
font-size: 32px;
font-weight: 700;
}
.darkmode {
font-family: "Josefin Sans", sans-serif;
background-image: linear-gradient(to top, #30cfd0 0%, #330867 100%);
border-style: solid;
border-radius: 30px;
border-color: #096386;
}
And that worked fine. Now in React (novice here) I don't know how to approach the problem. I've been reading about dynamically changing CSS classes in React with state but I can't figure out how to incorporate that with the API response. Any suggestions?
You can store className in state and change it in your function.
class Demo extends Component {
constructor(props) {
super(props);
this.state = {
stClass: "lightmode"
}
}
state = {
stClass: "lightmode"
}
componentDidMount = () => {
[call your function here and change the state of stClass]
}
render() {
return (
<div className={`${this.state.stClass}`}>
[your code here]
</div>
)
}
}
The key part of dynamically changing CSS classes in React would be:
<div className={`App ${this.state.displayMode}`}>
The class name of the container will be updated anytime the state for displayMode is changed and in this example, appended to the class App, resulting in App darkmode and rendered as such.
<div class="App darkmode">
Sample code / use case:
class App extends Component {
state = {
displayMode: "lightmode"
};
getMode = response => {
let _displayMode;
// Logic for determining the mode
return _displayMode;
}
componentDidMount() {
// Make API call here and run your logic to determine the mode
axios.get(apiUrl).then(getMode).then(displayMode => {
// As a callback to your function, set the state for displayMode
this.setState({
displayMode: displayMode
})
});
}
render() {
return (
<div className={`App ${this.state.displayMode}`}>
</div>
);
}
}

How to flip iron-icon vertically in css

I'm using iron-icon components for my Polymer 2 application, and I want to know how to flip these icons vertically or horizontally? I've tried the transform attribute and equivalent for other browsers, but it didn't work for me. as below:
.my-icon-class {
color: #55555A;
margin-top: 10px;
width: 30px;
height: 50px;
transform: scale(-1);
}
I've even tried ´filter´ attributte on IE:
.my-icon-class {
color: #55555A;
margin-top: 10px;
width: 30px;
height: 50px;
filter: FLipH;
}
And my icon instantiation looks like:
<iron-icon class="my-icon-class" icon="icons:room"></iron-icon>
The imports statement goes like this:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
You can find a snippest here below:
// Load webcomponents.js polyfill if browser doesn't support native Web Components.
var webComponentsSupported = (
'registerElement' in document
&& 'import' in document.createElement('link')
&& 'content' in document.createElement('template')
);
if (webComponentsSupported) {
// For native Imports, manually fire WebComponentsReady so user code
// can use the same code path for native and polyfill'd imports.
if (!window.HTMLImports) {
document.dispatchEvent(
new CustomEvent('WebComponentsReady', {bubbles: true})
);
}
} else {
// Load webcomponents.js polyfill
var script = document.createElement('script');
script.async = true;
script.src = 'https://cdn.rawgit.com/StartPolymer/cdn/1.8.1/components/webcomponentsjs/webcomponents-lite.min.js';
document.head.appendChild(script);
}
h1 {
font-size: 24px;
font-weight: 500;
line-height: 32px;
margin: 24px 0;
}
.my-icon-class {
color: #55555A;
margin-top: 10px;
width: 50px;
height: 70px;
}
<!-- <base href="https://gitcdn.xyz/cdn/StartPolymer/cdn/v1.11.0/components/"> -->
<!-- <base href="https://cdn.rawgit.com/StartPolymer/cdn/v1.11.0/components/"> -->
<base href="https://rawcdn.githack.com/StartPolymer/cdn/v1.11.0/components/">
<link rel="import" href="iron-icon/iron-icon.html">
<link rel="import" href="iron-icons/iron-icons.html">
<style is="custom-style">
body {
#apply(--layout-vertical);
#apply(--layout-center-center);
}
</style>
<h1>Polymer Icon to Flip</h1>
<p>And I want to flip it vertically and/or horizontally, need only the css. Thanks</p>
<iron-icon class="my-icon-class" icon="icons:room"></iron-icon>
icon to flip
<script>
window.addEventListener('WebComponentsReady', function() {
// Async call needed here for IE11 compatibility.
Polymer.Base.async(function() {
});
});
</script>
If need more info plz ask in comments.
I found a solution by using:
.my-class {
transform: rotate(180deg);
}
Hi please have a look in updated snippet.
// Load webcomponents.js polyfill if browser doesn't support native Web Components.
var webComponentsSupported = (
'registerElement' in document
&& 'import' in document.createElement('link')
&& 'content' in document.createElement('template')
);
if (webComponentsSupported) {
// For native Imports, manually fire WebComponentsReady so user code
// can use the same code path for native and polyfill'd imports.
if (!window.HTMLImports) {
document.dispatchEvent(
new CustomEvent('WebComponentsReady', {bubbles: true})
);
}
} else {
// Load webcomponents.js polyfill
var script = document.createElement('script');
script.async = true;
script.src = 'https://cdn.rawgit.com/StartPolymer/cdn/1.8.1/components/webcomponentsjs/webcomponents-lite.min.js';
document.head.appendChild(script);
}
h1 {
font-size: 24px;
font-weight: 500;
line-height: 32px;
margin: 24px 0;
}
.my-icon-class {
color: #55555A;
margin-top: 10px;
width: 50px;
height: 70px;
transform: rotateX(180deg);
}
.my-icon-class:hover {
transform: rotateY(180deg);
}
<!-- <base href="https://gitcdn.xyz/cdn/StartPolymer/cdn/v1.11.0/components/"> -->
<!-- <base href="https://cdn.rawgit.com/StartPolymer/cdn/v1.11.0/components/"> -->
<base href="https://rawcdn.githack.com/StartPolymer/cdn/v1.11.0/components/">
<link rel="import" href="iron-icon/iron-icon.html">
<link rel="import" href="iron-icons/iron-icons.html">
<style is="custom-style">
body {
#apply(--layout-vertical);
#apply(--layout-center-center);
}
</style>
<h1>Polymer Icon to Flip</h1>
<p>And I want to flip it vertically and/or horizontally, need only the css. Thanks</p>
<iron-icon class="my-icon-class" icon="icons:room"></iron-icon>
icon to flip
<script>
window.addEventListener('WebComponentsReady', function() {
// Async call needed here for IE11 compatibility.
Polymer.Base.async(function() {
});
});
</script>

Resources