Sass interpolate a variable name to string - sass

We were provided a number of colors with specific hover-state colors associated:
$red: #cb333b;
$red-hover: #fe666e;
$brown: #544742;
$brown-hover: #877a75;
etc.
Since all the colors are formatted the same way, so I was hoping to write a mixin that takes the color's variable name, then concatenates -hover to the end. This is my first try:
#mixin button_colorizor($color) {
border-color: $color;
color: $color;
&:hover {
color: #{$color}-hover;
border-color: #{$color}-hover;
}
}
But what this does is output a color like this: #f1735f-hover. The same thing when I do this: color: #{$color+-hover};

You can create map of colors. And get color values by its names.
Demo on sassmeister.
$colors: (
red: #cb333b,
red-hover: #fe666e,
brown: #544742,
brown-hover: #877a75
);
#mixin button_colorizor($color) {
color: map-get($colors, $color);
border-color: map-get($colors, $color);
&:hover {
color: map-get($colors, $color + '-hover');
border-color: map-get($colors, $color + '-hover');
}
}
a {
#include button_colorizor(red);
}
span {
#include button_colorizor(brown);
}
This code is compiled to css:
a {
color: #cb333b;
border-color: #cb333b;
}
a:hover {
color: #fe666e;
border-color: #fe666e;
}
span {
color: #544742;
border-color: #544742;
}
span:hover {
color: #877a75;
border-color: #877a75;
}

Related

how to simply style in scss so that multiple elements will use same style

I am new to sass.
Here is my code in scss. Just wondering if this can be simplified further i.e i dont want to repeat the style color, text-decoration and transition.
a {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
div.menu-item-click {
&:hover, &:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
}
Note exactly that use case is covvered better by ReSedano.
You cand do it using mixins:
#mixin mixinName {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
a {
#include mixinName;
}
div.menu-item-click {
&:hover, &:focus {
#include mixinName;
}
}
Also here is example with variables:
#mixin icon($width) {
width: $width;
stroke: currentColor;
}
.icon {
#include icon(25px);
}
And here is example with body
#mixin desktop ($xl: null) { // look here is default Value!
#media (min-width: if($xl, $xl, $screen-desktop)) {
#content; // here is true magic
}
}
.page {
#include desktop { // you may ignore variable because we have default
padding: 30px;
}
}
For this, maybe it is better using a placeholder with #extend directive (the output is less verbose than using a mixin):
%my-class {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
a {
#extend %my-class;
}
div.menu-item-click {
&:hover, &:focus {
#extend %my-class;
}
}
The output is:
a, div.menu-item-click:hover, div.menu-item-click:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}

Sass - Repeating code, how can I make this more succinct

I am creating helper classes that change the colour to predefined variables. For the most part the code is the same. I will be adding more specific selectors to this how can I make this easier to maintain?
.fg-text {
color: $colorText;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $colorText;
border-color: $colorText;
}
}
.fg-foreground {
color: $colorForeground;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $colorForeground;
border-color: $colorForeground;
}
}
.fg-alternate {
color: $colorAlternate;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $colorAlternate;
border-color: $colorAlternate;
}
}
.fg-background {
color: $colorBackground;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $colorBackground;
border-color: $colorBackground;
}
}
.fg-highlight {
color: $colorHighlight;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $colorHighlight;
border-color: $colorHighlight;
}
}
You could use an #each directive
#each $name, $color in (text: $colorText, foreground: $colorForeground ...) {
.fg-#{$name} {
color: $color;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $color;
border-color: $color;
}
}
}
I have condensed it to a mixin:
#mixin fg($name, $color) {
.fg-#{$name} {
color: $color;
button, .button,
input[type="button"],
input[type="submit"],
input[type="reset"],
select {
color: $color;
border-color: $color;
}
}
}
#include fg(brand, $colorBrand);
#include fg(foreground, $colorForeground);
#include fg(background, $colorBackground);
#include fg(text, $colorText);
#include fg(alternate, $colorAlternate);
#include fg(highlight, $colorHighlight);

Prevent combination of multiple selectors

I'm trying to group all my vendor-specific stuff into a placeholder selector like this:
%search-bar-placeholder {
color: red;
}
.search-bar::-webkit-input-placeholder {
#extend %search-bar-placeholder;
}
.search-bar:-moz-placeholder {
#extend %search-bar-placeholder;
}
.search-bar::-moz-placeholder {
#extend %search-bar-placeholder;
}
.search-bar:-ms-input-placeholder {
#extend %search-bar-placeholder;
}
And then it compiles to this:
.search-bar::-webkit-input-placeholder, .search-bar:-moz-placeholder, .search-bar::-moz-placeholder, .search-bar:-ms-input-placeholder {
color: red; }
How can I make sure Sass doesn't put all the selectors together ? Like this:
.search-bar::-webkit-input-placeholder {
color: red;
}
.search-bar:-moz-placeholder {
color: red;
}
.search-bar::-moz-placeholder {
color: red;
}
.search-bar:-ms-input-placeholder {
color: red;
}
When looking at Extend/Inheritance at sass-lang.com it seems that the selectors will always be comma separated. Even if you add another property, it will keep the shared properties in the comma separated list, and add another selector just for that overridden value.
The way I achieved what you want is by using a mixin. Though it's not really the purpose of a mixin, it does get the job done. Your style is still centralized and you can print it out in each selector using a one liner too.
#mixin placeholder-properties() {
color: red;
font-weight: bold;
}
.search-bar::-webkit-input-placeholder {
#include placeholder-properties();
}
.search-bar:-moz-placeholder {
#include placeholder-properties();
}
.search-bar::-moz-placeholder {
#include placeholder-properties();
}
.search-bar:-ms-input-placeholder {
#include placeholder-properties();
}
The result will the following.
.search-bar::-webkit-input-placeholder {
color: red;
font-weight: bold;
}
.search-bar:-moz-placeholder {
color: red;
font-weight: bold;
}
.search-bar::-moz-placeholder {
color: red;
font-weight: bold;
}
.search-bar:-ms-input-placeholder {
color: red;
font-weight: bold;
}
Here's a fiddle.

Sass Mixin: Callback or Replace #content

I don't know if Sass is able to do this, but it doesn't hurt to ask.
The Problem
Basically I have three colors pattern that are repeated in multiple sections of application, like blue, green and orange. Sometimes what changes is the background-color, or the border-color of the component... Sometimes is the text color of a child element, etc.
What I thought?
1. Replace a string pattern inside a content.
.my-class {
#include colorize {
background-color: _COLOR_;
.button {
border-color: _COLOR_;
color: _COLOR_;
}
}
}
2. Providing a callback variable for #content.
// This is just a concept, IT DOESN'T WORK.
#mixin colorize {
$colors: blue, green, orange;
#each $colors in $color {
// ...
#content($color); // <-- The Magic?!
// ...
}
}
// Usage
#include colorize {
background-color: $color;
}
I tried to implement such solutions, but without success.
Instead of it...
See below my workaround to get it partially working:
#mixin colorize($properties) {
$colors: blue, green, orange;
#for $index from 1 through length($colors) {
&:nth-child(#{length($colors)}n+#{$index}) {
#each $property in $properties {
#{$property}: #{nth($colors, $index)};
}
}
}
}
You can use this mixin that way:
.some-class {
#include colorize(background-color);
}
What will come output:
.some-class:nth-child(3n+1) {
background-color: blue;
}
.some-class:nth-child(3n+2) {
background-color: green;
}
.some-class:nth-child(3n+3) {
background-color: orange;
}
The problem? Well, I can't use it with child selectors.
Based on the above information, there is some magic solution for this case?
I think I figured out what you meant; it is a little (very) messy, but it should do what you want:
#mixin colorize($parentProperties,$childMaps) {
$colors: blue, green, orange;
#for $index from 1 through length($colors) {
&:#{nth($colors, $index)} {
#each $property in $parentProperties {
#{$property}: #{nth($colors, $index)};
}
}
#each $mapped in $childMaps {
$elem: nth($mapped,1);
$properties: nth($mapped,2);
#{$elem}:nth-child(#{length($colors)}n+#{$index}) {
#each $property in $properties {
#{$property}: #{nth($colors, $index)};
}
}
}
}
}
It would turn out to be:
/* -------------- USAGE ------------------*/
.some-class {
#include colorize(
background-color,( //Parent properties
(button, background-color), //Child, (properties)
(span, (background-color,border-color)) //Child, (properties)
)
);
}
/* --------------- OUTPUT ----------------*/
.some-class:nth-child(3n+1) {
background-color: blue;
}
.some-class button:nth-child(3n+1) {
background-color: blue;
}
.some-class span:nth-child(3n+1) {
background-color: blue;
border-color: blue;
}
.some-class:nth-child(3n+2) {
background-color: green;
}
.some-class button:nth-child(3n+2) {
background-color: green;
}
.some-class span:nth-child(3n+2) {
background-color: green;
border-color: green;
}
.some-class:nth-child(3n+3) {
background-color: orange;
}
.some-class button:nth-child(3n+3) {
background-color: orange;
}
.some-class span:nth-child(3n+3) {
background-color: orange;
border-color: orange;
}
Hope that that is what you are looking for :)

Can SASS merge properties?

Maybe a better question would be, Is there a more efficient way to override parts of a mixin?
This piece of SCSS:
#mixin button {
.button {
background-color: red;
color: white;
}
}
.container {
#include button;
.button {
background-color: green;
}
}
compiles to:
.container .button {
background-color: red;
color: white;
}
.container .button {
background-color: green;
}
I wish it could compile to:
.container .button {
background-color: green;
color: white;
}
Pass an argument into the mixin instead:
#mixin button($color: red) {
background-color: $color;
color: white;
}
.container {
.button {
#include button(green);
}
}

Resources