How to style :root without !important using proper specificity - css

Inside a Custom Element because border-color is set on the parent page, I can not make border-color work without resorting to !important
:host([player="O"]) {
color: var(--color2);
border-color: var(--color2) !important;
}
The selector works fine, the color is set,
so it is a Specificity issue
Question: Is it possible without !important ?
Working snipppet:
window.customElements.define('game-toes', class extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({
mode: 'open'
});
shadowRoot.innerHTML = 'Toes';
shadowRoot.appendChild(document.querySelector('#Styles').content.cloneNode(true));
}
});
:root {
--boardsize: 40vh;
--color1: green;
--color2: red;
}
game-toes {
width: var(--boardsize);
height: var(--boardsize);
border: 10px solid grey;
background: lightgrey;
display: inline-block;
}
<TEMPLATE id="Styles">
<STYLE>
:host {
display: inline-block;
font-size:2em;
}
:host([player="X"]) {
color: var(--color1);
border-color: var(--color1);
}
:host([player="O"]) {
color: var(--color2);
border-color: var(--color2) !important;
}
</STYLE>
</TEMPLATE>
<game-toes player="X"></game-toes>
<game-toes player="O"></game-toes>
qomponents

You are using CSS variable so you can still rely on them like this:
window.customElements.define('game-toes', class extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({
mode: 'open'
});
shadowRoot.innerHTML = 'Toes';
shadowRoot.appendChild(document.querySelector('#Styles').content.cloneNode(true));
}
});
:root {
--boardsize: 40vh;
--color1: green;
--color2: red;
}
game-toes {
width: var(--boardsize);
height: var(--boardsize);
border: 10px solid var(--playercolor,grey);
color:var(--playercolor,#000);
background: lightgrey;
display: inline-block;
}
<TEMPLATE id="Styles">
<STYLE>
:host {
display: inline-block;
font-size:2em;
}
:host([player="X"]) {
--playercolor: var(--color1);
}
:host([player="O"]) {
--playercolor: var(--color2);
}
</STYLE>
</TEMPLATE>
<game-toes player="X"></game-toes>
<game-toes player="O"></game-toes>
<game-toes ></game-toes>

As a complement to #Temani excellent answer: it happened because the element CSS style for <games-toes> will supersede the shadow root :host style.
According to Google's presentation:
Outside styles always win over styles defined in shadow DOM. For example, if the user writes the selector fancy-tabs { width: 500px; }, it will trump the component's rule: :host { width: 650px;}

Related

CSS Module with ClassNames Emotion migration

An example react file
const classNames = {
...defaultClassNames,
disabled: 'MyComponent--disabled',
selected: 'MyComponent--selected',
container: classnames('MyComponent', 'MyComponent-v2'),
};
return (
<MyComponent
classNames={classNames}
/>
An example CSS module file
.MyComponent-v2 {
.MyComponent-wrapper {
padding-bottom: 0;
}
.MyComponent:not(.MyComponent--disabled){
&:hover {
background: none !important;
.MyComponent-v2 {
background-color: red;
border-radius: 50%;
}
}
}
.MyComponent:focus,
}
How do I migrate this css module to emotion 10, all the examples I can find are using inline emotion with just a single css property like,
css={css`
background-color: hotpink;
&:hover {
color: ${color};
}
`}

Emotion JS: How to apply styles to child when hover parent?

Seems like this question has been asked and answered many different ways, but the answers I've seen either don't apply to Emotion or the Emotion-related answered haven't worked for me. I'm on #emtion/core#10.0.28 and #emtion/styled#10.0.27.
Essentially I want to apply styles to a child component when the parent is hovered/active/focused. The parent is a button and the child is an optional icon. The following styles are added to the (parent) button via the styled syntax.
const iconWrapperStyles = (props) => {
return css`
${props.IconWrapper} {
width: ${iconSizeMedium};
height: ${iconSizeMedium};
margin-left: ${spacingSizeSmall};
color: ${textColor};
fill: ${textColor};
background: ${backgroundColor};
border-color: ${borderColor};
}
&:hover:not(:disabled),
&:focus:not(:disabled),
&:active:not(:disabled) ${props.IconWrapper} {
outline: none;
color: ${textColorHover};
fill: ${textColorHover};
background: ${backgroundColorHover};
border-color: ${borderColorHover};
}
`;
};
The first block of styles is successfully applied. Therefore, at first blush, the button and child icon appear properly styled. However, when you hover/focus/make active the button, the icon does not change. I've tried the implementation above, along with ... + ${IconWrapper} and ... & ${IconWrapper}; all three fail for me. Official docs indicate that the & should work.
Regardless of the JS framework, the following should always work.
button {
background: darkblue;
color: white;
border: none;
padding: 5px;
}
button:hover i {
color: red;
}
<link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
<button>
<i class='icon-edit'></i> Click to edit
</button>
In your case, that becomes
${props.IconWrapper} {
width: ${iconSizeMedium};
height: ${iconSizeMedium};
margin-left: ${spacingSizeSmall};
color: ${textColor};
fill: ${textColor};
background: ${backgroundColor};
border-color: ${borderColor};
}
&:hover:not(:disabled) ${props.IconWrapper},
&:focus:not(:disabled) ${props.IconWrapper},
&:active:not(:disabled) ${props.IconWrapper} {
outline: none;
color: ${textColorHover};
fill: ${textColorHover};
background: ${backgroundColorHover};
border-color: ${borderColorHover};
}
I failed because my CSS is weak. Comma-separated CSS decorators do not iterate against the finally-declared element.
From this...
&:hover:not(:disabled),
&:focus:not(:disabled),
&:active:not(:disabled) ${props.IconWrapper} {
outline: none;
color: ${textColorHover};
fill: ${textColorHover};
background: ${backgroundColorHover};
border-color: ${borderColorHover};
}
To this...
&:hover:not(:disabled) ${props.IconWrapper}, // include child el
&:focus:not(:disabled) ${props.IconWrapper}, // include child el
&:active:not(:disabled) ${props.IconWrapper} {
outline: none;
color: ${textColorHover};
fill: ${textColorHover};
background: ${backgroundColorHover};
border-color: ${borderColorHover};
}

How to override styles from another css file

I have a css file (main.css) and I'd like to override it using another css file (overrides.css). But I have problem doing it as they are in different files and they get different hashes.
This is my css:
/* main.css */
.mainContainer {
padding: 16px;
margin: 16px;
background-color: palevioletred;
border-radius: 5px;
}
.mainContainer h1{
color: white;
}
/* overrides.css */
.mainContainer h1{
color: blue;
}
From here, I used Object.assign() to combine css files but it didn't help. This is my component:
import React from 'react';
import Main from './main.css';
import Overrides from './overrides.css';
const Style = Object.assign({}, Overrides, Main);
class Sample extends React.Component{
render(){
return (
<div className={Style.mainContainer}>
<h1>Hello</h1>
<p>Hello CSS modules!</p>
</div>
);
}
}
export default Sample;
I expect my h1 to become blue but it won't. This is my compiled css:
/* main.css */
._1pXpG {
padding: 16px;
margin: 16px;
background-color: palevioletred;
border-radius: 5px;
}
._1pXpG h1{
color: white;
}
/* overrides.css */
.Wmy0p h1{
color: blue;
}
I expect .Wmy0p h1 to be ._1pXpG h1 so it can override. But it won't. Note that if you just paste the content of overrides.css at the bottom of the main css it will work but I need my override css file to be in a separate file.
Thanks in advance
To over ride styles from other file can be made by giving one more specificity from parent div. Mostly specificity solves to override other files CSS.
class Sample extends React.Component{
render(){
return (
<div className={Style.mainContainerDetails}>
<div className={Style.mainContainer}>
<h1>Hello</h1>
<p>Hello CSS modules!</p>
</div>
</div>
);
}
}
/* main.css */
.mainContainer {
padding: 16px;
margin: 16px;
background-color: palevioletred;
border-radius: 5px;
}
.mainContainer h1{
color: white;
}
/* overrides.css */
.mainContainerDetails .mainContainer h1{
color: blue;
}
You can just use vanilla JavaScript to replace that specific css link on the webpage.
I also suggest using an event listener to wait until the page is loaded & then make the replacement.
Here is an example:
function overrideCommonCss() {
var webpageCurrentLink = "main.css", webpageNewLink = "overrides.css", webpageFoundLink, webpageCssTags = 0,webpageAllCssLinks = document.getElementsByTagName("LINK");
if (webpageAllCssLinks) {
for (webpageCssTags = 0;webpageCssTags < webpageAllCssLinks.length;webpageCssTags++) {
webpageFoundLink = webpageAllCssLinks[webpageCssTags].href;
if (webpageFoundLink.indexOf(webpageCurrentLink) !== -1) {
webpageAllCssLinks[webpageCssTags].href = webpageAllCssLinks[webpageCssTags].href.replace(webpageCurrentLink, webpageNewLink);
break;
}
}
}
}
if(window.attachEvent) {
window.attachEvent("onload", overrideCommonCss);
}
else {
window.addEventListener("load", overrideCommonCss, false);
}
have you tried using the !important in css? I believe that seems to be the problem. Below is an example, in plain html:
/* main.css */
.mainContainer {
padding: 16px;
margin: 16px;
background-color: palevioletred;
border-radius: 5px;
}
.mainContainer h1{
color: white;
}
/* overrides.css */
.mainContainer h1{
color: blue;
}
<div class="mainContainer">
<h1>Hello World!</h1>
</div>
As you can see, using !important works pretty well for me...

Revert css value to value before pseudo classes

<style>
div {
color: red;
}
button {
color: yellow;
}
button:hover {
color: green;
}
button:disabled {
color: inherit; /* This sets the color to red but I want yellow */
/* could do this but it's less flexible */
color: yellow;
}
</style>
<div>
<button disabled>Yo</button>
</div>
Above explains the problem that I have. I've tried using inherit, unset, initial but none of them achieve what I want. "inherit" is close but is uses the parent color. I would like to revert the color back to the original cover when an item is disabled even when its hovered without having to explicitly declare the color in the disabled pseudoclass.
You can use CSS variable to define your colors and avoid the change inside the pseudo class:
:root {
--main-color: yellow;
}
div {
color: red;
}
button {
color: var(--main-color);
}
button:hover {
color: green;
}
button:disabled {
color: var(--main-color);
}
<div>
<button disabled>Yoooooo</button>
</div>
Or make some changes to your selectors. Avoid the hover to be applied to the disabled button and this one will by default keep the initial color:
div {
color: red;
}
button {
color: yellow;
}
button:not([disabled]):hover {
color: green;
}
<div>
<button disabled>Yoooooo</button>
</div>
<div>
<button >Yoooooo yooo</button>
</div>
Why not using this?
The :not() CSS pseudo-class represents elements that do not match a list of selectors.
button, button:disabled {
color: yellow;
}
button:not(:disabled):hover {
color: green;
}
Or
button {
color: yellow;
}
button:not(:disabled):hover {
color: green;
}
https://codepen.io/anon/pen/XZepyB
div {
color: red;
}
button,
button:disabled {
/* assign the default colors together */
color: yellow;
}
button:hover {
color: green;
}
button:disabled:hover {
/* then override the disable state separately as needed */
color: #cc00cc;
}
Not sure if I understand you correctly, but this basic CSS mechanism would be:
div {
color: red;
}
button, button:hover:disabled {
color: yellow;
}
button:hover {
color: green;
}
<div>
<button>Yo</button>
</div>
<div>
<button disabled>Yo</button>
</div>
<div>
<button disabled>Yo</button>
</div>
Just add ":disabled:hover" to the "button" selector and remove the ":disabled" one:
button,
button:hover:disabled {
color: yellow;
}

How to style paper-input with certain mixins (polymer 2)?

I'm trying to style a paper-input based on a design I got. I used some of the custom proprieties described here , but not all of them work.
I have problems using --paper-input-container-label and --paper-input-container-input-focus.
Maybe I try to use them the wrong way or it requires some extra steps.
Here is my code
<link rel="import" href="../polymer/polymer-element.html">
<link rel="import" href="../paper-input/paper-input.html">
<link rel="import" href="../paper-input/paper-input-container.html">
<link rel="import" href="../iron-icons/iron-icons.html">
<link rel="import" href="../iron-icon/iron-icon.html">
<dom-module id="first-element">
<template>
<style>
paper-input {
--paper-input-container-color: rgb(64, 64, 64);
--paper-input-container-focus-color: rgb(64, 64, 64);
--paper-input-container: {
border: none;
padding: 0px;
}
--paper-font-subhead: {
font-size: 100%;
}
--paper-input-container-underline-focus: {
display: none;
}
--paper-input-container-underline: {
display: none;
}
--paper-input-container-input: {
height: 24px;
line-height: 20px;
padding: 0 4px;
border: 1px solid rgb(194, 198, 199);
}
--paper-input-container-input-focus: {
border-color:red;
}
--paper-input-container-label {
font-weight: bold;
}
--paper-input-container-invalid-color: red;
}
:host {
display: block;
}
</style>
<paper-input always-float-label label="Floating label"></paper-input>
<paper-input label="username">
<iron-icon icon="icons:accessible" slot="prefix"></iron-icon>
<div slot="suffix">#email.com</div>
</paper-input>
</template>
<script>
class FirstElement extends Polymer.Element {
static get is() { return 'first-element'; }
static get properties() {
return {
prop1: {
type: String,
value: 'first-element'
}
};
}
}
window.customElements.define(FirstElement.is, FirstElement);
</script>
</dom-module>
I am not sure what result you are expecting so it is hard to help you, but one thing I am sure it's your style tag is so messy. And you need to write a semi-colon after mixins because they are like css properties and every css properties are semi-colon separated.
Try your code like that :
<style>
:host {
display: block;
}
paper-input {
--paper-input-container-color: rgb(64, 64, 64);
--paper-input-container-focus-color: rgb(64, 64, 64);
--paper-input-container: {
border: none;
padding: 0px;
};
--paper-font-subhead: {
font-size: 100%;
};
--paper-input-container-underline-focus: {
display: none;
};
--paper-input-container-underline: {
display: none;
};
--paper-input-container-input: {
height: 24px;
line-height: 20px;
padding: 0 4px;
border: 1px solid rgb(194, 198, 199);
};
--paper-input-container-input-focus: {
border-color: red;
};
--paper-input-container-label: {
font-weight: bold;
};
--paper-input-container-invalid-color: red;
}
</style>
Another thing, you are trying to style the border color of the input on focus but also you are setting display to none which doesn't make sense. You have to remove display: none and add border-color: red; to --paper-input-container-underline-focus if you want to style the color.

Resources