How to un-nest SCSS - sass

I have a scss file that includes nested styles. The file is intended to end up as the style sheet for Zendesk. Zendesk allows you to use scss like variables, and color functions, however, it does not allow you to use nested style declarations. Is there a way that I can un-nest the styles, while leaving variables and color functions as they are? I have tried looking for a "flatten" function to no avail.
For example:
Input
.footer {
.footer-language-selector {
color: lighten($color_3, 20%);
}
}
Desired Output Note: both the variable and the color function remain as in the input
.footer .footer-language-selector {
color: lighten($color_3, 20%);
}

Related

SASS/SCSS, how to access a property/method in a dynamic way from a partial file?

Let's say for instance we have the next sass partial file:
//_colors.scss
$foo: red;
And we "use" it on another file:
//test.scss
#use './colors'
.test{
color: colors.$foo;
}
All good, but what if I would like to use/get the value in a dynamic way within a mixin? something like:
//test.scss
#use './colors'
#mixin getColor($type){
color: colors[$type]; //JavaScript example, * don't actually work *.
or
color: #{colors.{$type}; * don't work neither *
//The above returns `color: colors.foo` instead of `color: red` on compilation.
or
color: colors.#{$type}; * doesn't work neither *
}
.test{
#include getColor(foo);
}
Is it possible? thanks for the help!
For a color, I really much prefer a function so it can be used on any property (color, background-color, border, box-shadow...)
I usually declare a string equivalent to variable names, then define them inside a map. Finally this map is accessible via a dedicated function.
Something like
//_colors.scss
#use 'sass:map';
$favoriteRed: "favoriteRed";
$favoriteYellow: "favoriteYellow";
$favoriteBlue: "favoriteBlue";
$MyColors: (
$favoriteRed: #c00,
favoriteYellow: #fc0,
$favoriteBlue: #0cf
);
#function my-color($tone: $favoriteRed) {
#if not map.has-key($MyColors, $tone) {
#error "unknown `#{$tone}` in MyColors.";
}
#else {
#return map.get($MyColors, $tone);
}
}
This _colors.scss generates no code at all, it can be imported anywhere at no cost.
Then, in a specific style file:
//test.scss
#use './colors' as *;
//inside a mixin
#mixin special-hue-component($tone){
div.foo {
span.bar {
border-color: my-color($tone);
}
}
}
//or directly
.foobartest {
color: my-color($favoriteBlue);
}

scss mixin linear-gradient, two variables made easy?

I have a list of elements that need some gradient colors. But how can I make a simple mixin that simplifies the whole thing?
For example, in my css I'd like to be able to write:
button { #include linear(blue); }
and then scss would use my mixin and include my colors in my variables
$redTop: #F67777;
$redBottom: #E65050;
$blueTop: #77CFF6;
$blueBottom: #50B9E6;
#mixin linear($color) {
background-image: linear-gradient($colorTop, $colorBottom);
}
For this, you'd want to split the colours into a map.
$red: (
"top": #f00,
"bottom": #c00
);
#mixin linear($color) {
background-image: linear-gradient(map-get($color, "top"), map-get($color, "bottom"));
}
.red-bg {
#include linear($red);
}

Is there a better way to use SASS variables flexibly in media queries?

I've set up some variables in SASS as follows:
// fundamental layout variables
$raw-layout-var-1: 60px;
$raw-layout-var-2: 200px;
// calculated layout variables
$calc-layout-var-1: #{$raw-layout-var-1} + #{$raw-layout-var-2};
I am attempting to use these variables with media queries so I can do something like the following, and have the calculated variables and the rest of the stylesheet update when the relevant criteria are met. I would like to be able to override the fundamental or calculated variables as I need.
#media only screen and (min-height: 500px) {
$raw-layout-var-1: 120px;
#media only screen and (min-width: 500px) {
$raw-layout-var-2: 100px;
}
Currently I have a workaround where all updates to variables use the !global keyword to update them globally, but this results in a somewhat complex setup where the fundamental variables, calculated variables, and the main css sheet are placed in mixins, to be called in each individual media query:
#mixin reset-raw-vars() {
$raw-layout-var-1: 60px !global;
$raw-layout-var-2: 200px !global;
}
#mixin update-calc-vars() {
$calc-layout-var-1: #{$raw-layout-var-1} + #{$raw-layout-var-2} !global;
}
#mixin add-main() {
div {
width: $calc-layout-var-1;
height: $raw-layout-var-1;
}
}
#media only screen and (min-width: 500px) {
#include reset-raw-vars(); // resets the raw variables in case these were changed globally in a previous media query
// here you can change any fundamental variables you need
#include update-calc-vars(); // recalculates calculated variables
// here you can override how any calculated variables are made
#include add-main(); // update the rest of the stylesheet with new layout
}
Even worse, if I have a pair of media queries such as those shown in the second code block, I have to manually create a hybrid with both min-height and min-width in order to apply both sets of conditions. Clearly this isn't DRY and could get seriously out of control with even slightly complex responsive pages. I can see from Using Sass Variables with CSS3 Media Queries that SASS doesn't have this functionality - is there a better way than I've outlined above?

Mixin background gradient with background image.png

I have a mixin declared more or less like this
#mixin color-background {
background: yellow;
}
And i would wish to use this color as background of a png. but i cant seem to be able to mix the two
now what i would like to do is for example
.myImageWithBackgroundColor{
background: url(image.png),#include color-background
}
How can i acheive this with SASS and mixin?
You could store the background value of the mixin to a variable, and then use the variable instead of the whole mixin in the second code snippet.
$my-color: yellow;
#mixin color-background {
background: $my-color;
}
.myImageWithBackgroundColor{
background: url(image.png) $my-color;
}

Iterate over theme-variable files in SCSS

I want to create different css-themes for a WordPress theme by using theme setup files. The setup (simplified) would be as following:
/themes/_theme1.scss
/themes/_theme2.scss
/components/_file1.scss
/components/_file2.scss
/theme.scss
The idea is to enable easy theming by adding a class to the body of the document like .theme-theme1 or .theme-theme2. In the files _theme#.scss I want to define variables like text colour, font sizes and so on. In _file#.scss the actual styles are defined.
My question now is, how to iterate over the theme setup files while filling up the files.scss.
Sample idea, Background colour:
body {
###foreach themefile###
&.theme# {
background-color: $background-color;
}
###/foreach###
}
I know how to do this with only one theme available in the resulting CSS file, but I want to make ALL themes available in the resulting CSS. Feel free to ask more details as I am not sure if I explain me right.
Is there a way to create this stylesheet via some kind of foreach loops through variables in theme files or does it have to be done with extra scss-rules per theme file?
This is somewhat possible using a combo of #import with a #mixin to generate the styles. This method should produce minimal repeated code.
Here's how we'll setup the files.
- scss
- themes
- _theme1.scss
- _theme2.scss
- _theme.scss
- styles.scss
The _ prefix on some of the files prevent them from being compiled into CSS to keep our build nice and clean. Now let's go through the contents of the files:
_theme1.scss
$theme-name: 'theme1';
$primary-color: red;
$primary-font-size: 24px;
_theme2.scss
$theme-name: 'theme2';
$primary-color: blue;
$primary-font-size: 12px;
This is an oversimplified example but should give the basic idea. Each theme file will contain only variables.
_theme.scss
#mixin themestyle() {
body.#{$theme-name} {
p {
color: $primary-color;
font-size: $primary-font-size;
}
.bordered {
border: 3px solid $primary-color;
}
}
}
The themestyle mixin will contain all the styles for each theme, using the variables from the /themes/_theme*.scss files. The body.#{$theme-name} will create a selector like body.theme1 or body.theme2, depending on the current value of the $theme-name variable.
In this demo I'm styling on a p tag but this could easily be extended to all elements/selectors for your site. The important thing to remember is all styles need to be inside the body.#{$theme-name} selector.
Now the final, and least DRY part. The styles.scss file will import each theme file then call the themestyle mixin to generate the styles for each theme.
styles.scss
#import 'themes/theme';
/* Theme 1 Styles */
#import 'themes/theme1';
#include themestyles();
/* Theme 2 Styles */
#import 'themes/theme2';
#include themestyles();
The repeated #import/#include is required because it's not possible to #import within a loop or mixin, or this could be optimized a bit more.
Once styles.scss is compiled the output will be:
/* Theme 1 Styles */
body.theme1 p {
color: red;
font-size: 24px; }
body.theme1 .bordered {
border: 3px solid red; }
/* Theme 2 Styles */
body.theme2 p {
color: blue;
font-size: 12px; }
body.theme2 .bordered {
border: 3px solid blue; }
These themes can now be implemented by adding a class to the body tag, like <body class="theme1"> or <body class="theme1">.
Here's a Cloud9 project showing the setup.

Resources