I have the following CSS:
.form-search {
.form-control {
border-color: rgba(var(--shade-l6), .5);
background-color: rgba(var(--shade-l6), .5);
}
}
The variable is defined as follows:
:root {
--shade-l6: #{lighten($light, 6)};
}
.dynamic {
#media all and (prefers-color-scheme: dark) {
--shade-l6: #{lighten($dark, 6)};
}
}
.dark {
--shade-l6: #{lighten($dark, 6)};
}
The expected result would be for the background and border to take on the same color. However, when I take a look at this the endresult is as follows:
The background takes on a light color as expected, but the border is dark. The border will be light in dark mode.
When applying the variables through SCSS directly like shown below, the expected result is given.
.form-search {
.form-control {
border-color: rgba(lighten($light, 6), .5);
background-color: rgba(lighten($light, 6), .5);
}
}
What am I doing wrong here?
The sass rgba function does not work with CSS vars. You can do as you've posted at the end of your question and use a SCSS variable. Alternatively, you can define your CSS variable as the 3 RGB values that rgba would normally be looking for
:root {
--shade-l6: 235, 239, 243;
}
.form-search {
.form-control {
border-color: rgba(var(--shade-l6), .5);
background-color: rgba(var(--shade-l6), .5);
}
}
This is a bit more complex than it looks because it is easy to mix up the CSS and the SCSS color functions.
CSS rgb takes a r,g,b color value but not a hex value
SCSS rgba takes a color value but not a CSS variable
To make this work you need to
Convert the color to r,g,b format
Trick SCSS function to render the CSS rgba function
Something like this:
SCSS
// SCSS color variables
$light: orange;
$dark : orangered;
// Function to convert a color to rgb format r,g,b
#function rgb-format($color){
#return red($color), green($color), blue($color);
}
// Create CSS variables as rgb format
// e.g --shade-l6: 255, 176, 31;
:root {
--shade-l6: #{rgb-format(lighten($light, 6))};
}
.dynamic {
#media all and (prefers-color-scheme: dark) {
--shade-l6: #{rgb-format(lighten($dark, 6))};
}
}
.dark {
--shade-l6: #{rgb-format(lighten($dark, 6))};
}
// Pass the CSS vars to the CSS rgba function bypassing the
// SCSS function by uppercasing the first letter...
// SCSS will not understand this and simply render what is there
// - in this case the CSS rgba function
.form-search {
.form-control {
border-color: Rgba(var(--shade-l6), .5);
background-color: Rgba(var(--shade-l6), .5);
}
}
CSS Output
:root {
--shade-l6: 255, 176, 31;
}
#media all and (prefers-color-scheme: dark) {
.dynamic {
--shade-l6: 255, 91, 31;
}
}
.dark {
--shade-l6: 255, 91, 31;
}
.form-search .form-control {
border-color: Rgba(var(--shade-l6), 0.5);
background-color: Rgba(var(--shade-l6), 0.5);
}
Related
I'm looking a way of modifying a CSS variable as you would in SCSS
Define a color like primary - and automatically I would get shades for focus and actives states.
Basically, would like to change one variable in css variables and get 3 shades of the same color.
What Id like to achieve in CSS
$color-primary: #f00;
.button {
background: $color-primary;
&:hover,
&:focus {
background: darken($color-primary, 5%);
}
&:active {
background: darken($color-primary, 10%);
}
}
trying to achieve:
:root {
--color-primary: #f00;
--color-primary-darker: #f20000 // var(--color-primary) * 5% darker
--color-primary-darkest: #e50000 // var(--color-primary) * 10% darker
}
.button {
background: var(--color-primary);
}
.button:hover,
.button:focus {
background: var(--color-primary-darker);
}
.button:active {
background: var(--color-primary-darkest);
}
The new Specification introduces "relative color syntax" where you can do the following
:root {
--color-primary: #f00; /* any format you want here */
--color-primary-darker: hsl(from var(--color-primary) h s calc(l - 5%));
--color-primary-darkest: hsl(from var(--color-primary) h s calc(l - 10%));
}
The idea is to convert the main color to hsl format and using calc() you adjust the lightness.
There is still no support for this to date so consider the below solution.
You can consider hsl() colors and simply control the lightness:
:root {
--color:0, 100%; /*the base color*/
--l:50%; /*the initial lightness*/
--color-primary: hsl(var(--color),var(--l));
--color-primary-darker: hsl(var(--color),calc(var(--l) - 5%));
--color-primary-darkest: hsl(var(--color),calc(var(--l) - 10%));
}
.button {
background: var(--color-primary);
display:inline-block;
padding:10px 20px;
color:#fff;
cursor:pointer;
}
.button:hover,
.button:focus {
background: var(--color-primary-darker);
}
.button:active {
background: var(--color-primary-darkest);
}
<span class="button">some text</span>
As a side note, darken() is also doing the same thing:
Makes a color darker. Takes a color and a number between 0% and 100%, and returns a color with the lightness decreased by that amount.
How about this (pure sass/scss):
First, we need to split a color into hsla values and save each one in a separate custom property. Luckily sass has some functions to do the job.
#mixin define-color($title, $color) {
--#{$title}-h: #{hue($color)};
--#{$title}-l: #{lightness($color)};
--#{$title}-s: #{saturation($color)};
--#{$title}-a: #{alpha($color)};
}
Now we can put it back together, making some adjustments on the way.
#function color($title, $hue: 0deg, $lightness: 0%, $saturation: 0%, $alpha: 0) {
#return hsla(
calc(var(--#{$title}-h) + #{$hue}),
calc(var(--#{$title}-s) + #{$saturation}),
calc(var(--#{$title}-l) + #{$lightness}),
calc(var(--#{$title}-a) + #{$alpha}),
);
}
Now we are ready to define some color variables...
:root {
#include define-color("primary", #696969);
#include define-color("secondary", blue);
}
override them (to dynamically switch between themes for example)...
:root.theme-light {
#include define-color("primary", #424242);
#include define-color("secondary", red);
}
use and adjust them!
.example-class {
color: color("primary");
background: color("secondary", $lightness: +20%, $alpha: -0.3);
border: 1px solid color("primary", $hue: -30deg, $saturation: 5%);
}
If you are willing to take a different approach to your problem, using masks with the pseudo ":before" element would solve your problem. Although if you use this, i would advice you to put any content in the button inside a span or something, to give it a "z-index:1", so the content is not behind the mask.
:root {
--color-primary: #f00;
}
.button {
position:relative;
background: var(--color-primary);
&:before {
content:'';
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
}
}
.button:hover:before,
.button:focus:before {
background:rgba(0,0,0,0.05) /* black mask with 5% opacity */
}
.button:active:before {
background:rgba(0,0,0,0.1) /* black mask with 10% opacity */
}
Expanding on Temanis answer:
I use a gradient - from black to a dynamic color to white - and expand the background 100 times. Now its only a question of positioning the background.
In the CSS
.dynamic-color {
--lighten: 80%;
--darken: 45%;
--original-color: 50%;
--color-intensity: var(--original-color);
--color-variable: blue;
background-image: linear-gradient(90deg,black, var(--color-variable),white);
background-repeat: no-repeat;
background-size: 10000% 100%;
background-position-x: var(--color-intensity);
}
.dynamic-color:hover{
--color-intensity: var(--lighten);
}
.dynamic-color.active{
--color-intensity: var(--darken);
}
And in the HTML
<btn class="dynamic-color" style="--color-variable: green">Hover me</btn>
I'm looking a way of modifying a CSS variable as you would in SCSS
Define a color like primary - and automatically I would get shades for focus and actives states.
Basically, would like to change one variable in css variables and get 3 shades of the same color.
What Id like to achieve in CSS
$color-primary: #f00;
.button {
background: $color-primary;
&:hover,
&:focus {
background: darken($color-primary, 5%);
}
&:active {
background: darken($color-primary, 10%);
}
}
trying to achieve:
:root {
--color-primary: #f00;
--color-primary-darker: #f20000 // var(--color-primary) * 5% darker
--color-primary-darkest: #e50000 // var(--color-primary) * 10% darker
}
.button {
background: var(--color-primary);
}
.button:hover,
.button:focus {
background: var(--color-primary-darker);
}
.button:active {
background: var(--color-primary-darkest);
}
The new Specification introduces "relative color syntax" where you can do the following
:root {
--color-primary: #f00; /* any format you want here */
--color-primary-darker: hsl(from var(--color-primary) h s calc(l - 5%));
--color-primary-darkest: hsl(from var(--color-primary) h s calc(l - 10%));
}
The idea is to convert the main color to hsl format and using calc() you adjust the lightness.
There is still no support for this to date so consider the below solution.
You can consider hsl() colors and simply control the lightness:
:root {
--color:0, 100%; /*the base color*/
--l:50%; /*the initial lightness*/
--color-primary: hsl(var(--color),var(--l));
--color-primary-darker: hsl(var(--color),calc(var(--l) - 5%));
--color-primary-darkest: hsl(var(--color),calc(var(--l) - 10%));
}
.button {
background: var(--color-primary);
display:inline-block;
padding:10px 20px;
color:#fff;
cursor:pointer;
}
.button:hover,
.button:focus {
background: var(--color-primary-darker);
}
.button:active {
background: var(--color-primary-darkest);
}
<span class="button">some text</span>
As a side note, darken() is also doing the same thing:
Makes a color darker. Takes a color and a number between 0% and 100%, and returns a color with the lightness decreased by that amount.
How about this (pure sass/scss):
First, we need to split a color into hsla values and save each one in a separate custom property. Luckily sass has some functions to do the job.
#mixin define-color($title, $color) {
--#{$title}-h: #{hue($color)};
--#{$title}-l: #{lightness($color)};
--#{$title}-s: #{saturation($color)};
--#{$title}-a: #{alpha($color)};
}
Now we can put it back together, making some adjustments on the way.
#function color($title, $hue: 0deg, $lightness: 0%, $saturation: 0%, $alpha: 0) {
#return hsla(
calc(var(--#{$title}-h) + #{$hue}),
calc(var(--#{$title}-s) + #{$saturation}),
calc(var(--#{$title}-l) + #{$lightness}),
calc(var(--#{$title}-a) + #{$alpha}),
);
}
Now we are ready to define some color variables...
:root {
#include define-color("primary", #696969);
#include define-color("secondary", blue);
}
override them (to dynamically switch between themes for example)...
:root.theme-light {
#include define-color("primary", #424242);
#include define-color("secondary", red);
}
use and adjust them!
.example-class {
color: color("primary");
background: color("secondary", $lightness: +20%, $alpha: -0.3);
border: 1px solid color("primary", $hue: -30deg, $saturation: 5%);
}
If you are willing to take a different approach to your problem, using masks with the pseudo ":before" element would solve your problem. Although if you use this, i would advice you to put any content in the button inside a span or something, to give it a "z-index:1", so the content is not behind the mask.
:root {
--color-primary: #f00;
}
.button {
position:relative;
background: var(--color-primary);
&:before {
content:'';
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
}
}
.button:hover:before,
.button:focus:before {
background:rgba(0,0,0,0.05) /* black mask with 5% opacity */
}
.button:active:before {
background:rgba(0,0,0,0.1) /* black mask with 10% opacity */
}
Expanding on Temanis answer:
I use a gradient - from black to a dynamic color to white - and expand the background 100 times. Now its only a question of positioning the background.
In the CSS
.dynamic-color {
--lighten: 80%;
--darken: 45%;
--original-color: 50%;
--color-intensity: var(--original-color);
--color-variable: blue;
background-image: linear-gradient(90deg,black, var(--color-variable),white);
background-repeat: no-repeat;
background-size: 10000% 100%;
background-position-x: var(--color-intensity);
}
.dynamic-color:hover{
--color-intensity: var(--lighten);
}
.dynamic-color.active{
--color-intensity: var(--darken);
}
And in the HTML
<btn class="dynamic-color" style="--color-variable: green">Hover me</btn>
Here's my LESS statements:
#colorWhite: #FFFFFF;
#colorBlack : #000000;
#opacityNormalFill: 0.2;
#opacityNormalLabel: 0.75;
.colorWithAlpha(#color, #alpha)
{
#colorWithAlpha: rgba( red(#color), green(#color), blue(#color), #alpha );
}
if I write both background-color and color as this:
.button {
.colorWithAlpha(#colorBlack, #opacityNormalFill);
background-color: #colorWithAlpha;
.colorWithAlpha(#colorWhite, #opacityNormalLabel);
color: #colorWithAlpha;
}
The output will be:
.button {
background-color: rgba(0, 0, 0, 0.2);
color: rgba(0, 0, 0, 0.2);
}
I have to write it like this:
.button {
.colorWithAlpha(#colorBlack, #opacityNormalFill);
background-color: #colorWithAlpha;
}
.button {
.colorWithAlpha(#colorWhite, #opacityNormalLabel);
color: #colorWithAlpha;
}
It will output correctly:
.button {
background-color: rgba(0, 0, 0, 0.2);
}
.button {
color: rgba(255, 255, 255, 0.75);
}
How to resolve it?
Ok, your var #colorWithAlpha is limitted to your function .colorWithAlpha. If you try to use a global var, it will modifie all your code. You should pass the part to set this color in the function params like this :
#colorWhite: #FFFFFF;
#opacityNormalFill: 0.2;
#opacityNormalLabel: 0.75;
#colorBlack : #000000;
.colorWithAlpha(#color, #alpha, #property)
{
#{property} : rgba( red(#color), green(#color), blue(#color), #alpha );
}
And when you use it :
.button {
.colorWithAlpha(#colorBlack, #opacityNormalFill, background-color);
.colorWithAlpha(#colorWhite, #opacityNormalLabel, color);
}
less doesn't set global variables. You should be using the mixin as a nested style, not as a function.
Like:
.colorWithAlpha(#bgcolor, #color, #alpha)
{
background-color: rgba( red(#bgcolor), green(#bgcolor), blue(#bgcolor), #alpha );
color: rgba( red(#color), green(#color), blue(#color), #alpha );
}
Then:
.button {
.colorWithAlpha(#colorBlack, #colorWhite, #opacityNormalLabel);
}
Docs:
All variables defined in a mixin are visible and can be used in caller's scope (unless the caller defines its own variable with the same name).
Since your first .colorWithAlpha expansion does already define the #colorWithAlpha variable inside the .button, the second .colorWithAlpha call has no effect. (See #1892 for more details).
So you need either to isolate each expansion in its own scope:
.button {
.colorWithAlpha(#colorBlack, #opacityNormalFill);
background-color: #colorWithAlpha;
& { // <- begin new scope
.colorWithAlpha(#colorWhite, #opacityNormalLabel);
color: #colorWithAlpha;
}
}
Or use the solution suggested in #throrin19's answer.
---
And btw., to change color opacity use fade function, i.e. you don't need this mixin at all and your snippet can be simplified to:
#opacityNormalFill: 20%;
#opacityNormalLabel: 75%;
.button {
background-color: fade(#000, #opacityNormalFill);
color: fade(#fff, #opacityNormalLabel);
}
I am creating a LESS stylesheet with the SimpLESS compiler, and I notice when I create an entry using the CSS rbga() function, like this:
#contentDefaultOpacity: 0.5;
header#main-header {
nav.navbar {
div.container-fluid {
div.collapse {
ul.nav {
li {
a {
#alpha: 255 * #contentDefaultOpacity;
color: rgba(255, 255, 255, #alpha);
}
}
}
}
}
}
}
The compiler throws away the rgba() and outputs this instead:
header#main-header nav.navbar div.container-fluid div.collapse ul.nav li a {
color: #ffffff;
}
Is there a way I can retain the rgba()?
Thank you for your time.
LESS' rgba() function takes a percentage between 0% and 100%.
You're passing 128, which is fully opaque.
If you wish to generate the CSS rgba() function (instead of static hex color codes generated by Less), you can do so by using a string with interpolated variables, and the ~ operator to remove the quotes. This Less code:
#contentDefaultOpacity: 0.5;
a {
#alpha: #contentDefaultOpacity;
color: ~'rgba(255, 255, 255, #{alpha})';
}
will generate the CSS:
a {
color: rgba(255, 255, 255, 0.5);
}
I used this in my button pushButton stylesheet
QPushButton#pushButton {
background-color: yellow;
}
QPushButton#pushButton:pressed {
background-color: rgb(224, 0, 0);
}
QPushButton#pushButton:hover {
background-color: rgb(224, 255, 0);
}
when I hover my mouse over it, it changes color, like I expect it to , But the hover color remains even when I press the button.
I tried changing the order, but its still the same problem .
little new in Qt.
You can combine states, for example:
QPushButton:hover:!pressed
{
border: 1px solid red;
}
QSS reference - states
Css, and Qt CSS, depends on the order of declarations. Later declarations with the same specificity will overwrite previous declarations. So, in order to have the pressed state take precedence, simply move it below the hover state.
QPushButton#pushButton {
background-color: yellow;
}
QPushButton#pushButton:hover {
background-color: rgb(224, 255, 0);
}
QPushButton#pushButton:pressed {
background-color: rgb(224, 0, 0);
}
This is the correct stylesheet as you want:
//base stylesheet
QPushButton
{
background-color: yellow;
}
//pressed button stylesheet
QPushButton:pressed
{
background-color: rgb(224, 0, 0);
}
//hover stylesheet
QPushButton:hover:!pressed
{
background-color: rgb(224, 255, 0);
}
You can set the image in QPushButton:
QPushButton#pushButton {
background-url(Images/image1.png);
}
QPushButton#pushButton:pressed {
background-url(Images/image2.png);
}
QPushButton#pushButton:hover {
background-url(Images/image3.png);
}