Iterate over theme-variable files in SCSS - sass

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.

Related

How to render SCSS while keeping nesting?

I am creating a SCSS -> HTML plugin and need to first render SCSS -> CSS while keeping the nesting so I can then parse with PostCSS to then create an HTML tree with.
I would like to render SCSS like this
// myMixin.scss
#mixin myMixin {
.myMixin {
padding: 1rem;
background: yellow;
}
}
// main.scss
#import 'myMixin.scss';
$blue: #004AAD;
.button {
.text {
color: $blue;
}
#include myMixin;
}
And the output would look like this:
.button {
.text {
color: #004AAD;
}
.myMixin {
padding: 1rem;
background: yellow;
}
}
Basically, I'd like a way to render everything in SCSS while keeping the original nesting. Is it possible? Thanks.
Nesting is specific to SCSS. Also I don't think #import is best practice, use #use instead.
https://sass-lang.com/documentation/at-rules/use
Here is the thing our client(browsers) only support raw CSS and not SCSS, When you use SCSS it compiles down to raw CSS, And CSS doesn't have inbuilt Nesting feature.

Using irregular CSS in a .scss file

I have some funky formatting which I am using to override a Polymer component. It's the custom variables mixin. Scss does not like it to compile with. Is it possible to set a chunk that doesn't get compiled the sass way? Similar to jekyll raw html tag.
For example
// tag do not compile with sass //
--my-component-custom-mixin: {
background-color: #000;
color: #fff;
};
// tag finish do not compile with sass //
You could use Sass string interpolation (#{'...'}) to escape the CSS mixin:
SELECTOR {
--CSS-VARIABLE-NAME: #{'CSS-VARIABLE-VALUE'};
}
Example:
my-view1 {
--my-component-custom-mixin: #{'{
background-color: #000;
color: #fff;
}'};
}
demo

Include `.scss` file in another `.scss` file?

How can I Include .scss file in another .scss file?
I was trying to write this in a file:
app.scss:
#include('buttons');
#include('dropzone');
body {
background: $primaryColor;
overflow-x: hidden; /*Clip the left/right edges of the content inside the <div> element - if it overflows the element's content area: */
height: 100%; /* Cover all (100%) of the container for the body with its content */
padding-top: 70px;
} /* more css code here */
and it returns an error : invalid css after #import
I try to include 2 other scss files inside the main scss file, so it will be all compiled to one css file eventually. How is it possible?
You can import it like this;
#import "../../_variables";
#import "../_mixins";
#import "_main";
#import "_login";
#import "_exception";
#import "_utils";
#import "_dashboard";
#import "_landing";
According to your directories and it will do what you want.
You can include a partial by doing this:
#import "partial";
The imported file needs an underscore, so sass will recognize it to be included: _partial.scss
You can use #use rule for it. This rule loads another Sass file as a module, which means you can refer to its variables, mixins, and functions in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output!
// _base.scss
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
see how to using #use 'base'; in the styles.scss file
// styles.scss
#use 'base';
.inverse {
background-color: base.$primary-color;
color: white;
}
you don't need to include the file extension.
#osherdo You have no need to add !important for overwriting bootstrap CSS.
body
{
background: #4d94ff; /* Use to override Bootstrap css settings. */
}
First of you need to verify from where bootstrap is rendering on the page and what is the weight of the bootstrap CSS file. After that you can place your 'css/app.css' file after bootstrap then it will work. Then you can easily overwrite the entire bootstrap CSS.
Ok, so it appears to be that my app.scss file collide with Bootstrap.css file.
Because I wanted the app.scss background property to apply, instead of the bootstrap css file. I've added !important in this property to override bootstrap style.:
body
{
background: #4d94ff !important; /* Used to override Bootstrap css settings. */
}
Also, gulpfile.js has been updated to suite my needs accordingly:
var elixir = require('laravel-elixir');
elixir(function (mix) {
mix.sass('app.scss', 'resources/assets/css')
.styles([
'app.css'
], 'public/css/app.css');
mix.version([
'css/app.css'
]);
});
And that's how I fixed it.

Is it possible to make multiple css sheets from single layout-scss page, and multiple variable-scss sheets?

I'm attempting to integrate scss with the .net theming functionality.
Ideally most scss would be in a dedicated directory, but each theme would have its own scss page containing exclusively the variable values for that particular theme.
The problem I'm encountering is that I need to pass placeholder variables to the _layout.scss sheet, and then have their values updated by the theme scss sheets. Currently the original null values are outputted.
SCSS Files
Resources/SCSS/_variables.scss
$theme_color: null;
Resources/SCSS/_layout.scss
#import "variables";
div {
color: $theme_color;
}
Themes/Blue/blue.scss
$theme_color: #0000ff !default;
#import '../../Resources/SCSS/layout';
Themes/Red/red.scss
$theme_color: #ff0000 !default;
#import '../../Resources/SCSS/layout';
Desired CSS Output Files
blue.css
div {
color: #0000ff;
}
red.css
div {
color: #ff0000;
}
You have it backwards. The !default flag tells Sass that this is the value to use if it doesn't a previous declaration doesn't exist.
$foo: red;
$foo: blue !default;
#debug $foo; // red
$bar: red !default;
$bar: blue;
#debug $bar; // blue
You need to place the !default flag on the default null values, not the theme values.

What is the equivalent of LESS's "import (reference) 'style'" in SASS

In addition to application.css.scss, I have multiple partials like homepage.css.scss. At the moment I have to add #import 'bootstrap' to each one of them in order to use bootstrap variables and mixins.
Let's say I want to change my default links colour to red, I'd add that to application.css.scss. But the links in homepage.css.scss will not be red because the bootstrap import will override it with blue.
In LESS, I can do #import (reference) "bootstrap", how can I do that in SASS?
The closest you will get is a silent class / placeholder. These work a little different to how LESS and reference work, you can read more on them here: http://blog.teamtreehouse.com/extending-placeholder-selectors-with-sass
LESS
lib.less
.class {
background: red;
}
main.less
#import (reference) "lib";
.anotherClass {
&:extend(.class);
}
SASS
lib.sass
%class {
background: red;
}
main.sass
#import "lib";
.anotherClass {
#extend %class;
}
CSS Output
.anotherClass {
background: red;
}

Resources