Dynamic import style and set scss variable value - css

I have an admin template in which I would like user to provide option to switch between different theme color such as dark/light theme along with setting variable values, but I'm unable to conditionally import style files.
#if $light-theme {
#import "./_metronic/_assets/sass/themes/layout/aside/light.scss";
$primary: green;
} #else {
#import "./_metronic/_assets/sass/themes/layout/aside/dark.scss";
$primary: blue;
}
Getting error: Import directives may not be used within control directives or mixins.

Also it is a very long wished item to sass ... as the error message returns: that is not possible. (https://github.com/sass/sass/issues/279)
But what you can do is setting a theme variable and import your theme files. Every theme file has an conditional output based on the theme variable:
$theme: 'light-theme';
#import 'path/dark-theme';
#import 'path/light-theme';
// EVEREY THEME FILE WITH STRUCTURE:
#if( $theme == 'this-theme' ){
/*
here goes your theme variables or
if whanted your theme code in the file
*/
}

Related

(S)CSS define global color

So I would like to define a global color in my Angular project in the styles.scss stylesheet.
I know I can defined global variables like this
:root {
--blueish: #658bc7;
}
and then in other styles(heets) reference to it
p {
color: var(--blueish);
}
But this is NOT a globally defined color. This is a globally defined variable.
We could for example do
p {
color: aliceblue;
}
and this does work since aliceblue is globally defined along with a lot more preset colors. Is there a way for me to ADD a color to this list using (S)CSS? If not, would it be possible in less or SASS?
You can assign in SCSS vars with $varName. Important note if you like to use dash or underScore in your varnames. For the SASS compiler, $var-name is the same as $var_name. You have to take that into consideration.
SCSS
$blueish: #658bc7;
p {
color: $blueish;
}
Will compile to CSS:
p {
color: #658bc7;
}
You Can Define and Assign Variables in scss/sass Like This
$blueish: #658bc7;
p {
color: $blueish;
}
Notice that in sass/scss files named "blablabla" are globally scope
while files named "_blablabla" are not globally scoped and must be imported by.
You Must Have one globally file in sass/scss for example named "style.scss" that imports all scss/sass files in it for example:
/*
This File is only for imports
*/
#import "./libraries/_variables.scss";
#import "./libraries/_mixins.scss";
#import "./layouts/_header.scss";
#import "./pages/_about.scss";
Also, you can not add "_" and ".scss" in the importing it is not necessary for your editor will understand it for Example :
#import "./libraries/variables";
#import "./libraries/mixins.scss";
#import "./layouts/_header";
They are the same as the above example!

Feed theme variables to new Modules system

I work on styles for multi-tenant application for which the choice has been made to use SASS. Following the latest version guidelines, I started building base styles using #use and #forward. Now I want to theme this base with customers' colors and fonts variables to receive multiple stylesheets that can be served to different instances of our application.
If I was to use deprecated #import, I would go like this:
styles/customerA/index.scss
#import "customerA-variables";
#import "../base/index";
But with new rules I cannot find an easy way to simply feed theme specific variables to the base styles. I tried to use with keyword, but it turns out I need to define variables in a module, while I would rather encapsulate them in another module and import it.
styles/customerA/index.scss
#use "customerA-variables" as variables;
#use "../base/index" with (
$bgColor: variables.$bgColor,
$textColor: variables.$textColor
);
styles/base/_base-variables.scss
$bgColor: #eee !default;
$textColor: #333 !default;
styles/base/index.scss
/* HOW IT WORKS */
$bgColor: #eee !default;
$textColor: #333 !default;
/* HOW I WISH IT WORKED */
#use "./base-variables" as *;
/* LATER IN THE FILE */
body {
background-color: $bgColor;
color: $textColor;
}
In #use "../variables" as * scenario I get this error:
Error: This variable was not declared with !default in the #used module.
I'm looking for a working solution preferably without copy-pasting all theme variables inside with parenthesis.
First the error:
Error: This variable was not declared with !default in the #used module.
That error arises when you try to #use a module/file with configuration variables but the configuration variables are not set as !default variables in the module/file. So, SASS checks if you are passing a configuration which is not provided to be configurated for the module. That's additional security to you.
I am not quite sure if I did understand your example right, but it could be the way:
// styles/customerA/index.scss
#use "customerA-variables" as variables;
#use "../base/index" with (
$bgColor: variables.$bgColor,
$textColor: variables.$textColor
);
--> SASS ERROR because $bgColor and/or $textColor
--> in #used module/file are not set as defaults, i.e.:
--> $bgColor: green;
--> must be: $bgColor: green !default;
So, you may check the module if the variables are all set to defaults and not overwritten by non-default values.
**SECOND: usage of #use:
The new rule #use indeed is really confusing ... in your example that leads to doubled code: once when you set the custom vars in customerA-variables.scss and then when you repeat that variables when you #use the module/file in styles/customerA/index.scss (see your second code example).
A good way to avoid that doubled code is to prepare a configuration file with the settings for the individual customer and THAN #use the configuration file (not the wanted module/file direct).
Example:
// ###
// ### module/file: ../base/index.scss
$bgColor: #eee !default;
$textColor: #333 !default;
body {
background-color: $bgColor;
color: $textColor;
}
// ###
// ### customer configuration file: configModuleCustomerA.scss
#forward "../base/index" with (
$bgColor: red,
$textColor: blue
);
// ###
// ### use that configuration file
// ### to your main file: styles/customerA/index.scss
#use "...path.../configModuleCustomerA" as *;
// Note:
// 1. that writes the configurated css
// 2. and it provides the variables for additional use to THIS file
// see going on this file below ...
.additionalElement {
background: $bgColor;
color: $textColor;
}
// ###
// ### ---> that compiles to CSS:
body {
background-color: red;
color: blue;
}
.additionalElement {
background: red;
color: blue;
}
NOTE: there is an additional TRICK/EFFECT you should know.
YOU ONLY NEED TO SET THE VARIABLES ONCE ... just the time when you config the module/file. And as you do it in a/the module config file the variables you set there are part of you project configuration!
So, if you need the SAME variables of a module a second/third/... time (i.e. in additional partials files) you #use that configuration file in any file where you need it/them. Don't worry: the css code is only compiled ONCE to your CSS: the first time you #use the module.
BUT HEAD UP IN YOUR CASE:
But if you want to #use a module/file with different configurations as in your case you have to compile it into two DIFFERENT CSS files. One module with two or more different configurations loaded to the same CSS is blocked by SASS. In that case you need to split the css to different customer css files which all uses different module configuration files.

Building separate Stylesheets for different themes with webpack

Right now we are using a scss mixin ( https://github.com/zellwk/themify ) to provide different themes for our react components in our app.
It works great, but produces rather long selector chains in the compiled css file.
While we do have to provide the ability to change themes during runtime ( which is no hassle with the current solution, we only have to switch one classname on the body element ) the default usecase is, that the theme does not change.
So we thought about reducing the complexity and filesize of our stylesheets by splitting them up in separate files.
Example:
themes.scss:
$themes: (
red: (
mainColor: #aa3939,
secondaryColor: #D46A6A
),
blue: (
mainColor: #2e4272,
secondaryColor: #4f628e
)
);
button.sccs
#import 'themes.scss';
.button {
#include themify($themes) {
color: themed('secondaryColor');
background-color: themed('mainColor');
}}
}
This becomes:
.theme-red .button {
color: #D46A6A;
background-color: #aa3939;
}
.theme-blue .button {
color: #4f628e;
background-color: #2e4272;
}
Now I want this to become:
theme-red.css:
.button {
color: #D46A6A;
background-color: #aa3939;
}
theme-blue.css:
.button {
color: #4f628e;
background-color: #2e4272;
}
We are not depenent on the themify mixin, we could change that to any kind of solution one could make work with webpack. Any hint in the right direction would be appreciated! :)
#ManuKaracho, I tried to use the similar approach with the help of these two tutorials and faced the same issue as you are facing.
Sass Theming: The Neverending Story
Theming Web Apps with SASS
The CSS is generated in a single file instead of two separate files. I wanted to generate two separate CSS files just like you. I did some R&D about the issue and finally figured out how to do this.
First of all you need to break your themes.scss file into two separate files as shown below.
_theme-red-variables.scss
$themes: (
red: (
mainColor: #aa3939,
secondaryColor: #D46A6A
)
);
_theme-blue-variables.scss
$themes: (
blue: (
mainColor: #2e4272,
secondaryColor: #4f628e
)
);
Next you need to make some changes in your button.scss file. Simply remove the #import statement from the top because we will import theme specific variables into their own separate files as shown below
button.scss
.button {
#include themify($themes) {
color: themed('secondaryColor');
background-color: themed('mainColor');
}
}
Next you need to create two separate theme files. In these files, you need to import theme specific variables file, mixin file and your button.scss file
theme-red.scss
// Import red theme variables file
#import 'theme-red-variables';
// Import mixins file, where you have defined themify and themed mixins
#import 'mixins';
// Import button.scss file in this theme file
#import 'button';
theme-blue.scss
// Import blue theme variables file
#import 'theme-blue-variables';
// Import mixins file, where you have defined themify and themed mixins
#import 'mixins';
// Import button.scss file in this theme file
#import 'button';
Two separate files will be generated using the above technique
theme-red.css
.button {
color: #D46A6A;
background-color: #aa3939;
}
theme-blue.css
.button {
color: #4f628e;
background-color: #2e4272;
}
I hope I have explained the solution well and it will help you to resolve your problem.

SASS Multiple levels of variable precedence/inheritance

I'm using Laravel Mix and Webpack for SASS pre-processing.
I have two "themes" in my website which I want to be lean, inheriting variables where they need to. For example, my primary theme will include in this order:
// Primary theme
#import "./primary-variables.scss";
#import "/path/to/default/theme/main.scss";
My default theme would look like this:
// Default theme
#import "./default-variables.scss";
#import "~bootstrap-sass/assets/stylesheets/_bootstrap";
Similarly to this question, I've included the primary variables first, then the default theme variables, then bootstrap last.
In my default theme I add !default to all variables so where they are redefining Bootstrap they will be used in priority, and where new they will be a default value. The primary theme doesn't use !default at all.
Working example
If Bootstrap defines $brand-danger as say red !default, my default theme redefines it as blue !default and my primary theme redefines it as yellow, my rendered output will be yellow - great!
The problem
When I need to reference variables that are only defined at other levels from my primary theme. For example:
// Primary theme:
// This fails since I haven't defined $brand-primary in my primary theme
$my-primary-theme-variable: $brand-primary;
The build now fails with an error saying primary-theme/src/scss/main.scss doesn't export content.
Workaround
I can work around this problem by copying the entire Bootstrap variables file through to my primary theme and changing variables as necessary, but I don't really want to do this.
Question
How does the SASS variable processor actually work? Is it possible for me to just change one of the Bootstrap variables in my theme without necessarily having to redefine the entire file?
This question is pretty similar.
It seems like you are using #include to import your SCSS try using #import instead – If this is just a typo in the question please let me know :-)
#import "./primary-variables.scss",
"/path/to/default/theme/main.scss"
;
I've added a few quick notes on the question you were referring to.
The important thing to know about the !default flag is that it takes effect at the point when it is used in a selector and does not re-define variables.
Sass does not look ahead when processing variables – it prints out the current value. In this example .class-1 will be red as the re-definition comes after it being used in the selector and .class-2 will be blue as there is no default flag.
$brand-color: red !default; // defined
.class-1 { background-color: $brand-color; } // red
$brand-color: blue; // re-defined
.class-2 { background-color: $brand-color; } // blue
Default flags will cause Sass to skip variable re-definition. In this example the result will be red as being defined first. The two following re-definitions are ignored because of the default flags.
$brand-color: red !default; // defined
$brand-color: blue !default; // ignored
$brand-color: green !default; // ignored
.class-1 { background-color: $brand-color; } // red
In this case all variables from from the config will be used – then variables from partial-1 if not defined in config and last partial-2 will define any variable not defined in the two others.
#import '_config.scss'; // definition
#import '_partial-1.scss'; // contains defaults
#import '_partial-2.scss'; // contains defaults
Hope it makes sense :-)
Import structure
// _default-theme.scss
#import '_default-variables.scss', '_bootstrap.scss';
// _primary-theme.scss
// primary variables will override defaults or use defaults if not defined
#import '_primary-variables.scss', '_default-theme.scss';
// style.scss
#import '_primary-theme.scss'; // or '_default-theme.scss'
Scope
In case your default and primary has content that is unique to each theme you could create a scoping mixin to handle what is compiled.
Here is a very rudimentary version:
// _scope.scss
$scope-context: null !default;
#function scope($scopes: null, $true: true, $false: false) {
#each $scope in $scope-context {
#if index($scopes, $scope) { #return $true }
}
#return $false;
}
#mixin scope($scopes: null) {
#if scope($scopes) or length($scopes) == 0 and not $scope-context {
#content;
}
}
How it works
The scope mixin takes a context argument and a content block #content. If the passed context matches a global variable ($scope-context) the content block get's rendered.
// _default-theme.scss
.class { content: 'Will show in both themes'; }
#include scope(default-theme){
.class { content: 'Will only show in the default theme'; }
}
#include scope(primary-theme){
.class { content: 'Will only show in the primary theme'; }
}
// can also be used as "if" function
.class {
content: scope(default-theme, 'Is default', 'Not default')
}
In your case define the $scope-context in both default and primary variables
// _default-variables.scss
$scope-context: default-theme !default;
// _primary-variables.scss
$scope-context: primary-theme;
... and add _scope.scss to the _default-theme.scss
// _default-theme.scss
#import '_default-variables.scss', '_bootstrap.scss', '_scope.scss';
The problem I found was that I was assuming things incorrectly about how SASS works.
When you define a variable declaration, the value of it is compiled at the time your write it. For example $my-var: $brand-primary would assign the current value of $brand-primary to $my-var at the time it is processed.
This means simply that I can't achieve what I wanted, which was to include a minimal variables file over the top of Bootstrap, because it would only update the variable itself, but not any other variables that reference that variable within Bootstrap.
The solution
It's not elegant, but duplicate the entire variable file for each theme and adjust them as required in each place.

How to set custom font for foundation button

I am trying to set a custom font-family for the button in foundation 6 with no luck I am running foundation 6 with sass and believe they have removed the $button-font-family variable that was in previous versions. What is the best solution to achieve this without the variable?
Ideally I would like to apply a text-transform on the button text as well which is also not a button variable in the _setting.sass foundation file. As you may have gathered I am very new to foundation and sass so any help would be greatly appreciated.
It doesn't look like a font-family is specified in scss/components/_button.scss and that's where button syles are defined. The $body-font-family is set in both scss/settings/_settings.scss as well as scss/_global.scss (if not already defined in _settings.scss). So, verify that you have updated the value of $body-font-family there.
Aside from that, if you are using foundation sass semantically (i.e. mixins), you should be able to use the button mixin like so:
#include button( false, #ebebeb, #a5a5a5, black, solid );
..and then set the font-family property after the mixin like you normally would.
----Update: Based on follow up question/comment----
Here's an example main sass file for one of the foundation sites I'm working on now.
// Author copy of Foundation settings/_settings.scss
#import "settings";
// Author copy of Foundation _globals.scss
#import "global";
// Import from Foundation
#import "path/to/foundation-sites/scss/grid/grid";
#import "path/to/foundation-sites/scss/typography/typography";
#import "path/to/foundation-sites/scss/components/button";
// Include Foundation classes/styles that we want to use
#include foundation-global-styles();
#include foundation-typography();
//
// Author Variables
//
$color-map : ( 'blue': #40578a, 'blue-tint': #7e8ba8, 'blue-shade': #364a75, 'dark': #3d3e41, 'silver': #bdc0c6, 'gold': #ab883c );
$blue : map-get($color-map, 'blue');
$blue-tint : map-get($color-map, 'blue-tint');
$blue-shade: map-get($color-map, 'blue-shade');
$dark : map-get($color-map, 'dark');
$silver : map-get($color-map, 'silver');
$gold : map-get($color-map, 'gold');
//
// Author Components
//
#import "common";
#import "btn";
#import "view";
#import "cover";
#import "header";
#import "hero";
#import "navbar";
#import "main";
#import "page";
#import "intro";
#import "services";
I'll go through this section by section. It's pretty simple and once you have a project set up this way, you'll love it.
// Author copy of Foundation settings/_settings.scss
Here, we are importing a copy of the Foundation _settings.scss file and modifying it for our needs. Don't mess with the original _settings file that ships with Foundation. Doing so will make it more difficult to update the library moving forward.
// Author copy of Foundation _globals.scss
Same concept as the _settings file.
// Import from Foundation
These imports are the only parts of the Foundation framework that I want to use in this case. These component files include the mixins used to generate these components. This allows us to use the mixins semantically in our code.
// Include Foundation classes/styles that we want to use
And this will output the pre-defined classes/styles that we want to use from foundation. Typically, you will at least want to include global and typography styles.
// Author Variables
This is where I put my custom variables (not related to Foundation). You could put this in another partial if you want - just a preference.
// Author components
These are the project's custom components which may or may not utilize Foundation's mixins. The point is, we can if we want to now that we have included the components/mixins we want to use.
So, in your case, you could simply do this:
// Foundation settings
#import "settings";
// Foundation globals
#import "global";
// Import from Foundation
#import "../path/to/foundation-sites/scss/components/button";
//
// Author Variables
//
$special-button-font: Georgia, serif;
.special-button {
#include button(false, #ebebeb, #a5a5a5, black, solid);
font-family: $special-button-font;
&.tiny { font-size: map-get($button-sizes, tiny); }
&.small { font-size: map-get($button-sizes, small); }
&.large { font-size: map-get($button-sizes, large); }
&.expanded { #include button-expand; }
}

Resources