css variables - declare variable if not already defined - css

I have a project which is split up into the parent app, and several reusable child components in separate repositories. I'd like to define default CSS variables in these child components, which can be overridden by the parent app, however I can't find the right syntax for this. Here's what I've tried:
/* parent */
:root {
--color: blue;
}
/* child */
:root {
--color: var(--color, green);
}
.test {
width: 200px;
height: 200px;
background: var(--color, red);
}
https://codepen.io/daviestar/pen/brModx
The color should be blue, but when the child :root is defined, the color is actually red, at least in Chrome.
Is there a correct approach for this? In SASS you can add a !default flag to your child variables which basically means 'declare if it's not already declared'.

CSS stands for cascading style sheets,
so you cannot override anything by a parent...
The only way is to create a stronger rule.
look at .c1 and .p1
.parent {
--background: red;
}
.child {
--size: 30px;
--background: green; /* this wins */
background-color: var(--background);
width: var(--size);
height: var(--size);
}
.p1 .c1 {
--background: red; /* this wins */
}
.c1 {
--size: 30px;
--background: green;
background-color: var(--background);
width: var(--size);
height: var(--size);
}
<div class="parent">
<div class="child"></div>
</div>
<hr />
<div class="p1">
<div class="c1"></div>
</div>

Thanks to #Hitmands hint I have a neat solution:
/* parent */
html:root { /* <--- be more specific than :root in your parent app */
--color: blue;
}
/* child */
:root {
--color: green;
}
.test {
width: 200px;
height: 200px;
background: var(--color);
}

I would suggest an approach by aliasing the variables in the component and using "parent" or root variables as main value while local value is by !default.
.parent {
--background: red;
}
.child {
--child_size: var(--size, 30px); /* !default with alias */
--child_background: var(--background, green); /* !default with alias */
background-color: var(--child_background);
width: var(--child_size);
height: var(--child_size);
}
<div class="parent">
<div class="child"></div>
</div>
<hr>
<div class="child"></div>

Related

Changing an unrelated div on hover [duplicate]

This question already has answers here:
Is there a CSS parent selector?
(33 answers)
Is there a "previous sibling" selector?
(30 answers)
Closed 1 year ago.
Is there a purely (S)CSS solution to change an unrelated (i.e. not a sibling or a child) div on hover, as I am trying to do in the code below?
.blue,.green {
width: 5rem;
height: 3rem;
margin: 1rem;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
&:hover {
background-color: lightgreen;
}
&:hover .blue {
background-color: lightblue; // trying to effect this change
}
}
<div>
<div class="blue" />
</div>
<div>
<div class="green" />
</div>
Here is the CodePen.
Update: the reply by #alekskorovin is outstanding and deserves many upvotes!
In CSS there are possibilities to use the same parent and common classes and :not selector together with CSS variables. As far as I could understand the thing is to set some common properties when you hover on some of the items. If it's possible to have a common parent element you could consider that example (https://codepen.io/alekskorovin/pen/bGobvzG):
:root {
--bg: rgba(255, 255, 255, 0.3);
}
.one {
background: blue;
}
.two {
background: green;
}
.common {
margin: 1rem;
border: solid 0.1rem grey;
position: relative;
}
.common:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: var(--bg);
}
.parent:not(div:hover) {
--bg: rgba(255, 255, 255, 0);
}
<div class="parent">
<article><div class="one common">One</div></article>
<article><div class="two common">Two</div></article>
</div>

how to select root class variable into another class in css

<style>
:root product6 {
--width:435px;
}
:root .size1 {
--scale: 0.8;
}
:root .size2 {
--scale: 0.7;
}
.productDiv {transform:scale(--scale);}
</style>
<div class="product6 size1"></div>
This is working well if I give classes inside div class attr...showing my div scaled 0.8 and width 435px
But how can I select size1 class inside css syntax under stylesheet
.productDivResponsive {width:435px;transform:scale(???)}
Thanks.
Define your variables in root element (:root), so that they are available everywhere. Then define classes and ids, that use those variables in any way you see fit.
(If you want a narrower scope, you can also define your vars for another element. You do not necessarily have to use :root. Have a look at the special section in my example.)
/* define vars for everywhere, as everything inherits from root */
:root {
--width: 100px;
--height: 100px;
--scale-1: 0.8;
--scale-2: 0.6;
--scale-3: 0.4;
--c-green: #3d9970;
--c-red: #ff4136;
--c-blue: #0074d9;
}
/* define vars for a specific part of your page, overriding root in this example */
#special {
--c-green: #01FF70;
--c-red: #f012be;
--c-blue: #7fdbff;
border: 1px solid #ccc;
}
section {
margin: 10px;
}
main {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
}
.product {
width: var(--width);
height: var(--height);
box-shadow: inset 0 0 1em rgba(0, 0, 0, 0.4);
color: rgba(60, 60, 60, 0.7);
font-family: sans-serif;
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: 700;
text-align: center;
background-image: linear-gradient(rgba(255, 255, 255, 0.4), rgba(0, 0, 0, 0.3))
}
.scale-1 {
transform: scale(var(--scale-1));
}
.scale-2 {
transform: scale(var(--scale-2));
}
.scale-3 {
transform: scale(var(--scale-3));
}
#product-2 {
background-color: var(--c-green);
}
#product-3 {
background-color: var(--c-red);
}
#product-4 {
background-color: var(--c-blue);
}
#product-5 {
background-color: var(--c-green);
}
#product-6 {
background-color: var(--c-red);
}
#product-7 {
background-color: var(--c-blue);
}
/* within scope of #special, colors are different: */
#product-10 {
background-color: var(--c-blue);
}
#product-11 {
background-color: var(--c-red);
}
#product-12 {
background-color: var(--c-green);
}
<main>
<section>
<div id="product-1" class="product">1</div>
<div id="product-2" class="product scale-1">2</div>
<div id="product-3" class="product scale-2">3</div>
<div id="product-4" class="product scale-3">4</div>
</section>
<section>
<div id="product-5" class="product scale-3">5</div>
<div id="product-6" class="product scale-2">6</div>
<div id="product-7" class="product scale-1">7</div>
<div id="product-8" class="product">8</div>
</section>
<section id="special">
<div id="product-9" class="product scale-2">9</div>
<div id="product-10" class="product scale-2">10</div>
<div id="product-11" class="product scale-2">11</div>
<div id="product-12" class="product scale-2">12</div>
</section>
</main>
This is working well if I give classes inside div class attr...showing my div scaled 0.8 and width 435px
The code provided cannot possibly work, it's syntactically erroneous.
But how can I select size1 class inside css syntax under stylesheet?
Addition of question mark was my edit.
CSS is static, hard coded, so just write it in just as you have with the rest of your CSS. I hope you are not asking how to dynamically manipulate CSS on the stylesheet because you need to grasp the advanced concepts dealing with CSS and working knowledge of JavaScript.
Demo
Note: Details are commented in demo
/*
Declare CSS variables
:root is the best selector to use because all descendants
will have access to them.
--=These are VALUES ONLY=--
They cannot be assigned to a selector directly
They can only be assigned to a property
propert: value is assigned to a selector
*/
:root {
--w435: 435px;
--scX070: 0.7;
--scX120: 1.2;
}
.box {
background: gold;
color: blue;
outline: 3px solid blue;
margin: 20px auto;
min-height: 30px;
/*
This is the proper syntax when assigning the value of a
CSS variable to a property
${selector} {${property}: var(--${CSSVar});}
.box { width: var(--w435); }
*/
width: var(--w435);
}
.size1 {
transform: scaleX(var(--scX070));
}
.size2 {
transform: scaleX(var(--scX120));
}
<div class='box'></div>
<div class="box size1"></div>
<div class="box size2"></div>
If I use this code I can make that I need...but I don't want to write classes twice...Problem is I want to use divs somewhere static somewhere responsive...
<style>
:root .product6 {
--width:435px;
}
:root .size1 {
--scale: 0.8;
}
:root .size2 {
--scale: 0.7;
}
.productDiv {transform:scale(--scale);}
#media (min-width: 1600px) {
:root {
--scale:0.8;
}
.productDivResponsive {transform:scale(var(--scale));}
}
#media (max-width: 1600px) and (min-width: 1360px) {
:root {
--scale:0.7;
}
.productDivResponsive {transform:scale(var(--scale));}
}
</style>
<div class="product6 productDiv"></div> <!-- This one static and scaling my div 0.8 -->
and want to make it responsive somewhere in my page with writing code something like that;
<div class="productDivResponsive"></div>
my productDivResponsive div must be scaled according to my media queries...
how can I remove repeating root class variables?
I hope I can explain what I need...Possible??

Accessing global variable in css

:root {
--color: blue;
}
div {
--color: green;
color: var(--color)
}
#alert {
--color: red;
color: var(--color)
}
<p>What's my color?</p>
<div>and me?</div>
<div id='alert'>
What's my color too?
<p>color?</p>
</div>
In the above code, how can I access the global value of --color in div with id='alert'?
Or in other words is there any way in CSS to access the global variable like the :: (scope resolution operator) in c++??
You Can't do that with CSS.
If You'll repeat the declaration of the same variable, it'll use the locally declared variable.
See this-
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id='alert'>
While I got red set directly on me!
<p>I’m red too, because of inheritance!</p>
</div>
Source: Example 5 CSSWG
This is a possibility
:root {
--color: blue;
}
div {
color: var(--color);
}
#alert {
color: var(--color);
}
<p>What's my color?</p>
<div style="--color:green">and me?</div>
<div id="alert" style="--color:red">
What's my color too?
<p>color?</p>
</div>
Or:
:root {
--color: blue;
}
div {
--color: green;
color: var(--color);
}
#alert {
--color: red;
color: var(--color);
}
<p>What's my color?</p>
<div>and me?</div>
<div id="alert">
What's my color too?
<p>color?</p>
</div>
CSS Custom variables are inheritable, that means when you define a variable in :root, it is applicable to all elements.
When you applied it to div it changed for all div and everything inside the div.
And because they have been inherited, their parent's/root's value can't be accessed.
Check out this pen for some trials.
One method hack to do is to make a copy of the variable and use it.
:root {
--color: blue;
--colorRoot: var(--color);
color: var(--color);
}
div {
--color: green;
color: var(--color);
}
#inside {
color: var(--colorRoot);
}
<div> I am inside a div.<br><span id="inside">I am inside</span></div>
I am ouuuuuutside
Pretty sure that's not you would like to do.

Is it possible to pass a class as parameter to a mixin in Stylus?

I’m trying to reduce some Stylus code using its mixins.
In some particular cases I need a class as a parameter. Let’s we’ve got:
.parent:hover .child
color: lighten(red, -25%)
.child
color red
I’d like to have a mixin which gets both classes as parameters.
I can’t find a way from the docs. ((
You can achieve this with interpolation: http://stylus-lang.com/docs/interpolation.html
Here's an example codepen: https://codepen.io/webdevdani/pen/POVLpr
Code example from codepen:
/* Stylus */
.box {
height: 2rem;
width: #height;
background-color: blue;
padding: 1rem;
}
.red-box {
background-color: red;
}
$blockColor(parentClass, childClass) {
{parentClass} {
background-color: green;
{childClass} {
background-color: yellow;
}
}
}
$blockColor('.box', '.red-box');
<div class="box">
<div class="box red-box"></div>
</div>

Is there a way to reproduce currentColor with var(--current-color)?

I don't use currentColor very often but when I do, it's extremely useful.
So I've been a little excited about the arrival of CSS Variables.
Let's take a traffic light.
N.B. Please take it on trust from me that Japanese traffic lights go red to amber to blue. I know it's hard to believe. I know the blue light looks sort-of green. But it isn't, it's blue.
div {
float: left;
width: 200px;
}
div div {
float: none;
}
.top {
color: rgb(255,0,0);
}
.middle {
color: rgb(255,227,0);
}
.bottom {
color: rgb(63,255,63);
}
.jp .bottom {
color: rgb(0,255,191);
}
.light {
text-align: center;
}
.light::before {
content: '';
display: block;
margin: 6px auto 0;
width: 25px;
height: 25px;
border-radius: 15px;
background-color: currentColor;
}
<div class="uk">
<h2>UK Traffic Lights</h2>
<div class="top light">Red</div>
<div class="middle light">Amber</div>
<div class="bottom light">Green</div>
</div>
<div class="jp">
<h2>JP Traffic Lights</h2>
<div class="top light">Red</div>
<div class="middle light">Amber</div>
<div class="bottom light">Blue</div>
</div>
Now, the clever thing about
background-color: currentColor;
is that it just reads whatever the current value for color is and uses that.
By contrast...
background-color: var(--current-color);
That can't reference the current value of another style declaration, can it?
So, you'd need to set up 4 variables (just like you need to declare color: 4 times in the styles above):
.top {
--color-top: rgb(255,0,0);
}
.middle {
--color-middle: rgb(255,227,0);
}
.bottom {
--color-bottom: rgb(63,255,63);
}
.jp .bottom {
--color-bottom-jp: rgb(0,255,191);
}
And then... you need to reference each of those different variables later on. Which means a different background-color declaration for each variable:
.top::before {
color: var(--color-top);
background-color: var(--color-top);
}
.middle::before {
color: var(--color-middle);
background-color: var(--color-middle);
}
.bottom::before {
color: var(--color-bottom);
background-color: var(--color-bottom);
}
.jp .bottom::before {
color: var(--color-bottom-jp);
background-color: var(--color-bottom-jp);
}
Really?!
That can't be right. Have I missed something?
Is there no way to reproduce currentColor with var(--current-color) ?
Is there no way for CSS variables to represent the current value of another style declaration?
Actually, you can set a CSS custom property instead of setting directly the color property, and use it for color and background-color.
/* Set global variable inside the :root scop */
:root {
--color-top: rgb(255,0,0);
}
div {
float: left;
width: 200px;
}
div div {
float: none;
}
/* Set the local --color variable, according to your need */
.top {
--color: var(--color-top);
}
.middle {
--color: rgb(255,227,0);
}
.bottom {
--color: rgb(63,255,63);
}
.jp .bottom {
--color: rgb(0,255,191);
}
.light {
color: var(--color);
text-align: center;
}
.light::before {
content: '';
display: block;
margin: 6px auto 0;
width: 45px;
height: 45px;
border-radius: 15px;
background-color: var(--color);
}
<div class="uk">
<h2>UK Traffic Lights</h2>
<div class="top light">Red</div>
<div class="middle light">Amber</div>
<div class="bottom light">Green</div>
</div>
<div class="jp">
<h2>JP Traffic Lights</h2>
<div class="top light">Red</div>
<div class="middle light">Amber</div>
<div class="bottom light">Blue</div>
</div>
I do not really understand why you are not using background-color: currentColor, because it works well in your own example.
If you are using SASS (which is compiled into css), then you can use SASS variables. The code will look like :
$font-stack: Helvetica;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
more informations on the SASS official website

Resources