Get value from a list of properties / map - css

Currently, I've a list of colors (for example):
#colors: {
base: #716aca;
brand: #716aca;
danger: #c14549;
warning: #ffb822;
success: #34bfa3;
primary: #5867dd;
black: #000000;
}
I have each function that iterates over all the colors and makes all the possible rule colors that we can use:
each(#colors, .(#value, #key, #index) {
.rules-here-#{key} {
attribute: #value;
}
}
What I can't make work is something like this:
.getColor(#color);
Where I would use on other places, like:
div.system-warning-notification {
background-color: .getColor('base');
color: .getColor('danger');
}
I have no idea if this is even possible. I have been losing my mind over this for over a week now without any progress.
If that isn't possible, can I generate the variables so I can access them like:
#color-base: #716aca;
Without having to manually create them?
Thank you very much and I hope I asked this right. I am new here.

Related

CSS variables only for certain properties

There is a way to specify the usage of variables only for certain properties.
It is used to not overwrite say a padding with a color variable.
So if you would declare a variables like this:
--myColor: red
you could not use the variable in a padding like this:
.p {
/* should NOT be possible */
padding: var(--myColor);
}
Could someone help me out with the name of this feature, please?
So, basically the code will be more complex then --myColor: red.
I think I remember something like an object structure (but I might be wrong):
myColor { color: red; elements: color }
I found the answer, see here explanations https://youtu.be/3IUxyBx_PnM?t=1660
CSS.registerProperty({
name: "--stop-color",
syntax: "<color>",
inherits: false,
initialValue: "black"
})
it's actually Houdini CSS

Maps and themes

I am new to using CSS pre-compilers and started using Less. I found Sass code to add themes to my web app and it works great.
https://codepen.io/dmitriy_borodiy/pen/RKzwJp
I am trying to convert it to Less and having difficulty rewriting it. I have gone through Less documentation but sorry to say that I am not even able to create a multilevel themes variable.
sass variable is as follows:
$themes: (
light: (
backgroundColor: white,
textColor: #408bbd
),
dark: (
backgroundColor: #222,
textColor: #ddd
),
);
Below conversion is totally wrong but this is what I have tried:
#set: {
light: {
backgroundColor: white,
textColor: #408bbd
},
dark: {
backgroundColor: #222,
textColor: #ddd
},
}
EDIT:
Example of what I am trying to achieve:
.theme(key) {
return all outcomes using #themes variable.
}
div {
background: .theme(divBackgroundColor)
}
it should return the following css :
.light-theme div{
background: white
}
.dark-theme div{
background:grey
}
Any help is appreciated.
A question like this ...
... ("I'm learning a language X and I found some program in language Y that looks like what I need. How to do the same thing using X?") is pretty much impossible to answer in (and too broad for) the SO format, as soon as the snippet goes beyond a single distinct minimalistic statement/feature.
Either way, to not leave the Q unanswered:
To be able to write a similar code in Less you will need to get familiar with the following features:
Maps
Rulesets as values/parameters
plus all typical language basic facilities like variables, functions, scope etc. etc. and the last (but not the least) Mixins.
Answering how to make something like background: .theme(backgroundColor) to do what you need would require explaining all of this from scratch (i.e. turning the answer into a book or a very loooong tutorial). Technically, you should not really be able to miss that the code in the linked snippet is a waaaaaay more complex than just background: .theme(backgroundColor).
And here's a (minimalistic) Less equivalent of the snipped at CodePen you pointed to.
(No comments there. They are pointless since nothing magic happens in it - to understand what it does you just need to get familiar with the languages features I listed above):
#theme: {
#light: {
backgroundColor: white;
textColor: #408bbd;
}
#dark: {
backgroundColor: #222;
textColor: #ddd;
}
}
// ....................................
// usage:
.themify({
div {
background: .theme[backgroundColor];
}
span {
color: .theme[textColor];
}
// etc.
});
// ....................................
// impl.:
.themify(#style) {
each(#theme, {
#name: replace(#key, '#', '.');
.theme() {#value()}
#{name}-theme {#style()}
});
}
For other possible techniques and solutions related to similar "Theming" use-cases see also:
Variables based on ancestor class
How to thematize in ...
and other Q/As linked/referenced there.
Try this code
#light: #f9f9f9;
#dark: #333333;
.theme(#theme: #color, #background: #background) {
color: #theme;
background: #background;
a {
color: #theme;
}
}
.light-theme {
.theme(#theme: #light, #background: #dark);
}
.dark-theme {
.theme(#theme: #dark, #background: #light)
}
<div class="light-theme">
Light Theme<br> Light Theme
</div>
<div class="dark-theme">
Light Theme<br> Light Theme
</div>

Generating dynamic color map in SASS

I'm trying to generate a rather automated system to define colours in SASS. I have a list of colours, defined with a hexidecimal value (like so: $color--deep-ocean: #123143;) and a global $colors: (); definition.
I then want to create their RGBA values dynamically, and given variable interpolation isn't an option in SASS, I've tried my hands at maps.
The idea is to feed a set-color function a name and a color to populate my $colors variable with map-merge, which I can then retrieve with get-color. Here below are my two function definitions and how I'm trying to use them:
#function color-set($name, $hex) {
$submap: (hex: $hex);
#for $o from 0 to 20 { // Going in increments of 5
$percentage-decimal: $o*0.05;
$percentage: $o*5;
$submap: map-merge($submap, ($percentage: rgba($hex, $percentage-decimal)));
}
$colors: map-merge($colors, ($name: $submap));
/* We should then have a map that looks like this:
$colors: (colorname: (
hex: #000000,
0: rgba(0,0,0,0),
5: rgba(0,0,0,.05),
// and so on…
100: rgba(0,0,0,1)
)
)
… right? */
}
#function color-get($name, $opacity: hex) {
#if $opacity != hex { // Returns RGBA value
#return map-get(map-get($colors,$name), $opacity);
}
#else { // Returns hexidecimal value
#return map-get(map-get($colors,$name), hex);
}
}
Please let me know if my functions are confusing! I'll try to comment them better.
This is how I'm trying to define a colour (part of _variables.scss):
color-set(bkgrnd, $color--deep-ocean);
And here's how I'm trying to use my colours:
body { // These colours have been defined, too …supposedly
background-color: color-get(bkgrnd, 80);
color: color-get(white);
}
Here is the error I get on _variables.scss:
Invalid CSS after "...ackground color": expected 1 selector or at-rule, was "color-set(bkgrnd, $"
So I feel like I'm missing something. I've had my head wrapped around this for four hours and I'm going mad. It's probably super simple stuff but I can't seem to figure it out. I use SASS casually, so I might not be aware of some syntax issue but if anyone has a clue about how to fix this, I'd be quite grateful.
Have a nice day and thank you for taking the time to read my post!
Regards,
Chris
PS: I compile this in Brackets with the Brackets SASS plugin, if ever that information is relevant.
After digging some more, I found out what my issue was. SASS functions must have a #return directive in order to work. As a result, I updated my color-set function, and added #return $colors; at the end of it. Then, I just needed to give some directive so the function wouldn't be called "out of the blue", so I assigned my $colors variable to it like such:
$colors: color-set(bkgrnd, $color--deep-ocean);
I think it might be a bit repetitive to reassign $colors to itself all the time, but given this only affects performance during compilation, and not on my final CSS file, I can get away with it. There might be a better way (and I'm all ears if you have an idea!) but for now this fits my needs just fine.
And like that, I am able to handle my colors using maps. Thanks to anyone who had a look at my problem, and sorry for posting this - I should have taken some time to cool down and think some more. I hope this helps someone else who is stumbling on the same problem to fix their issues!
Take care,
Chris
PS: If ever you wanted it, below is the full code.
_colors.scss
$color--deep-ocean: #123143;
$color--yellow: #ffce00;
// And so on, and so forth…
_mixins.scss
#function color-set($name, $hexval) {
#return map-merge($colors, ($name: $hexval));
}
#function color-get($name, $opacity: hex) {
#if $opacity != hex { // Returns RGBA value
$opacity-decimal: $opacity/100;
#return rgba(map-get($colors,$name), $opacity-decimal);
}
#else { // Returns hexidecimal value
#return map-get($colors, $name);
}
}
_variables.scss
$colors: color-set(bkgrnd, $color--deep-ocean);
$colors: color-set(main, $color--yellow);
// And so on, and so forth again…
Usage example:
body {
background-color: color-get(bkgrnd); // Returns #123143
color: color-get(main); // Returns #ffce00
}
button {
border: 2px solid color-get(main, 50); // Returns rgba(255, 206, 0, 0.5)
}

scsslint ColorVariable and sass palettes

I have a problem with scsslint in this variable
ColorVariable: Color literals like blue should only be used in
variable declarations; they should be referred to via variable
everywhere else.
I have this sass palette:
$color-palettes: (
blue: (
light : lighten($grey, 6%),
base : $grey,
),
);
//using sass palettes
p {
color: palette(blue);
}
//wrong way
p {
color:blue;
}
// right way by scsslint I totally agree
// creating the variable
$blue:#0055FF;
p {
color:$blue;
}
the problem is I am passing the value palette(blue); and this make scsslint complain about blue.
I know I can change the scss-lint.yml to false ans solve that
ColorVariable:
enabled: false
but the problem I want avoid bad practices like:
p {
color:blue;
}
p {
color:white;
}
so in that case what the best I should do? to Keep Using the validation in my file jumping some classes that ColorVariable?
Thanks.

Sass #each with multiple variables

I'm just getting started with Sass and Compass, and I'm loving it. Something I'd like to do is take advantage of the #each function to simplify repetitive tasks. However, I've only seen examples of #each inserting one variable, and I'd like to be able to use multiple variables.
The standard way (from the Sass Reference):
#each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
Which is great, but I'd like to be able to do something like:
#each {$animal $color} in {puma black}, {sea-slug green}, {egret brown}, {salamander red} {
.#{$animal}-icon {
background-color: #{$color};
}
}
Is this possible?
Just came across this, have the answer for you. In Sass, you can actually have a multidimensional list, so instead of constructing individual variables, you'd create one variable to hold them all, then loop over them:
$zoo: puma black, sea-slug green, egret brown, salamander red;
#each $animal in $zoo {
.#{nth($animal, 1)}-icon {
background-color: nth($animal, 2);
}
}
You can have multidimensional lists just like you would have single dimensional lists as long as each nested dimension is separated in a different manner (in our case, commas and spaces).
UPDATE Oct 24, 2013
In Sass 3.3, there is a new data type called maps which are a hashed set of items. With this, we can rewrite my previous answer in the following way to much more closely resemble the desired result:
$zoo: ("puma": black, "sea-slug": green, "egret": brown, "salamander": red);
#each $animal, $color in $zoo {
.#{$animal}-icon {
background-color: $color;
}
}
You can see this in action over at SassMeister
I'm in the same boat (beginner to Sass/Compass) and had to do something similar. Here's what I came up with, using nested lists:
$flash_types: (success #d4ffd4) (error #ffd5d1);
#each $flash_def in $flash_types {
$type: nth($flash_def, 1);
$colour: nth($flash_def, 2);
&.#{$type} {
background-color: $colour;
background-image: url(../images/#{$type}.png);
}
}
It's not the most elegant solution but it should work if you can't find anything else. Hope it helps! I'd appreciate a better method too :)
Another way I used if anyone needs it:
$i:0;
#each $name in facebook, twitter, google_plus, instagram, youtube, pinterest {
$i:$i+1;
}
This functionality is supported for Sass 3.3.0 and above (I just updated from 3.2.14 to 3.4.4 in order to use it).
#each $animal, $color in (puma, black), (sea-slug, green), (egret, brown), (salamander, red) {
.#{$animal}-icon {
background-color: $color;
}
}
I'd recommend to check the changelog for backwards incompatibilities, if you're updating Sass.
Sass reference for multiple assignments with #each
Another solution could be to create different lists and "zip" them.
//Create lists
$animals: puma, sea-slug, egret, salamander;
$animals-color: black, green, brown, red;
//Zip lists
$zoo: zip($animals, $animals-color);
//Do cycle
#each $animal, $color in $zoo {
.#{$animal}-icon {
background-color: $color;
}
}
Probably this solution is more complicated to mantain than the others, but if you use a list more than one time, you can save time. (was my case)

Resources