I have LESS variables set up to manage colour selections. Here's part of it:
/* The themes
#lightTheme1:#grey300;
#lightTheme2:#grey100;
#lightTheme3:#grey50;
#lightTheme4:#fff;
#darkTheme1:#000;
#darkTheme2:#grey900;
#darkTheme3:#303030;
#darkTheme4:#grey800;
/* Set theme name
#theme:'lightTheme';
/* The chosen theme
#theme1:'#{theme}1';
#theme2:'#{theme}2';
#theme3:'#{theme}3';
#theme4:'#{theme}4';
/* Using the theme
#background:##theme3;
background-color:##theme3;
The issue I've got is that in order to use #theme1, theme2 etc I need to prefix with '##'. This is easy to forget because the normal variable syntax is a single '#' - is there anything I can do higher up in the hierarchy so that when I need to use the variables in code I can do so with a single '#'?
If you will only be using 1 theme at a time you could store the theme variables in seperate files:
lightTheme.less
#theme1:#grey300;
#theme2:#grey100;
#theme3:#grey50;
#theme4:#fff;
darkTheme.less
#theme1:#000;
#theme2:#grey900;
#theme3:#303030;
#theme4:#grey800;
Then rather than setting the theme via a string property, you can #import a theme:
#import "lightTheme.less"
Then your use of the theme is a single #:
background-color:#theme3;
Related
EDIT: This question was marked as a duplicate of this one, but see the addendum near the end of this answer to see what that question doesn't ask, and what the answer doesn't answer.
I'm working on a web app that uses Bootstrap 3. I have a basic 3-layer override architecture, where 1) Bootstrap's _variables.scss contains the core variables, 2) _app-variables.scss contains the base app variables that override Bootstrap's _variables.scss, and 3) _client-variables.scss contains client-specific customizations that override _app-variables.scss. Either #2 or #3 (or both) can be blank files. So here's the override order:
_variables.scss // Bootstrap's core
_app-variables.scss // App base
_client-variables.scss // Client-specific
Simple enough in theory, but a problem arises because of what I'll call "variable dependencies" -- where variables are defined as other variables. For example:
$brand: blue;
$text: $brand;
Now, let's say the above variables are defined in _variables.scss. Then let's say in _app-variables.scss, I override only the $brand variable to make it red: $brand: red. Since SASS interprets the code line by line sequentially, it will first set $brand to blue, then it will set $text to blue (because $brand is blue at that point), and finally it will set $brand to red. So the end result is that changing $brand afterwards does not affect any variables that were based on the old value of $brand:
_variables.scss
---------------------
$brand: blue;
$text: $brand; // $text = blue
.
.
.
_app-variables.scss
---------------------
$brand: red; // this does not affect $text, b/c $text was already set to blue above.
But obviously that's not what I want - I want my change of $brand to affect everything that depends on it. In order to properly override variables, I'm currently just making a full copy of _variables.scss into _app-variables.scss, and then making modifications within _app-variables from that point. And similarly I'm making a full copy of _app-variables.scss into _client-variables.scss and then making modifications within _client-variables.scss at that point. Obviously this is less than ideal (understatement) from a maintenance point of view - everytime I make a modification to _variables.scss (in the case of a Bootstrap upgrade) or _app-variables.scss, I have to manual trickle the changes down the file override stack. And plus I'm having to redeclare a ton of variables that I may not even be overriding.
I found out that LESS has what they call "lazy loading" (http://lesscss.org/features/#variables-feature-lazy-loading), where the last definition of a variable is used everywhere, even before the last definition. I believe this would solve my problem. But does anyone know a proper variable-override solution using SASS?
ADDENDUM:
Here's one technique I've already thought through: include the files in reverse order, using !default for all variables (this technique was also suggested in the answer to this question). So here's how this would play out:
_app-variables.scss
---------------------
$brand: red !default; // $brand is set to red here, overriding _variables.scss's blue.
.
.
.
_variables.scss
---------------------
$brand: blue !default; // brand already set in _app-variables.scss, so not overridden here.
$text: $brand !default; // $text = red (desired behavior)
So that solution is almost perfect. However, now in my override files, I don't have access to variables defined in Bootstrap's _variables.scss, which I would need if I wanted to define my variable overrides (or my own additional custom variables) using other Bootstrap variables. For example, I might want to do: $custom-var: $grid-gutter-width / 2;
Solved, but I don’t know from which version this works. I believe the solution could have always been available. Tested on:
> sassc --version
sassc: 3.2.1
libsass: 3.2.5
sass2scss: 1.0.3
We are going to use a simplified environment, so filenames do not match with Bootstrap’s.
Challenge
Given a framework we do not control (for example installed only on the Continuous Integration environment and not available in our machines) that expresses SCSS variables in the following manner:
// bootstrap/_variables.scss
$brand-primary: #f00 !default;
$brand-warning: #f50 !default;
$link-color: $brand-primary !default;
And given a file in that same framework that uses the variables:
// bootstrap/main.scss
a:link, a:visited {
color: $link-color;
}
The challenge is:
Include the framework in your own application’s SCSS in such a way that
variables’ dependencies in the framework are preserved and honors;
you can depend in on the default values but still be able to change the results on the framework dependencies.
More precisely:
Include the framework in your application’s SCSS in such a way that $brand-color will always be the inverse of $brand-warning, whatever its value is in the framework.
Solution
The main file would look like this:
// application.scss
#import "variables";
#import "bootstrap/variables";
#import "bootstrap/main";
And your variables file would look like this:
// _variables.scss
%scope {
#import "bootstrap/variables";
$brand-primary: invert($brand-warning) !global;
}
Results:
> sassc main.scss
a {
color: blue; }
Explanation
The %scope part is not something magic of SCSS, it’s simply a hidden class with the name scope, available exclusively for later extensions with #extend. We are using it just to create a variable scope (hence the name).
Inside the scope we #import the framework’s variables. Because at this moment there’s no value for each variable every variable is created and assigned its !default value.
But here’s the gimmick. The variables are not global, but local. We can access them but they are not going to pollute the global scope, the one that will be later used to derive variables inside the framework.
In fact, when we want to define our variables, we want them global, and indeed we use the !global keyword to signal SCSS to store them in the global scope.
Caveats
There’s one major caveat: you cannot use your own variables while you define them.
That means that in this file
%scope {
#import "bootstrap/variables";
$brand-primary: black !global;
#debug $brand-primary;
}
The #debug statement will print the default value defined in bootstrap/_variables.scss, not black.
Solution
Split variables in two parts:
%scope {
#import "bootstrap/variables";
$brand-primary: black !global;
#debug $brand-primary;
}
#debug $brand-primary;
The second #debug will indeed correctly print black.
With Bootstrap 4 or bootstrap-sass all variables set in the _variables.scss with the !default flag.
Therefore, if you set a variable before bootstrap's _variables.scss is included, when it is included, the value from _variables.scss will be ignored.
So my sass entry file might look like this ...
#import "bootstrap-overrides";
#import "bootstrap/scss/bootstrap-flex";
#import "mixins/module";
In alpha 6 of Bootstrap 4, all variables in _variables.scss can be overridden in _custom.scss, in the way that mryarbles describes.
However, the overrides do not cascade to other elements, because the inclusion order is:
#import "variables";
#import "mixins";
#import "custom";
When I change this to
#import "custom";
#import "variables";
#import "mixins";
it works as expected.
The _custom.scss file in BS4 dev branch has been removed. Try to reorder your imports with this order:
Setup
#import "client-variables";
#import "app-variables";
#import "boostrap";
#import "app-mixins";
#import "client-mixins";
Make sure to copy the content of boostrap variable file _variables.scss to app-variables and client-variables. Leave the !default beside each variable to allow further override.
Explanation
All bootstrap variables are declared with !default. From Sass reference:
You can assign to variables if they aren’t already assigned by adding the !default flag to the end of the value. This means that if the variable has already been assigned to, it won’t be re-assigned, but if it doesn’t have a value yet, it will be given one.
Bootstrap will respect all variables already defined on top making the app_variables with higher priority and client_variables with highest priority.
You need to copy all the variable declarations from bootstrap _variables into app-variables and client-variables so you can have a custom variable as you wanted. (Disadvantage is that it is harder to maintain on every bootstrap update)
All variables are now available in your app-mixins and client-mixins
Using Foundation 4 buttons allows you to customize design using the mixins.
This is the same for most elements.
However, there are many settings that the mixins don't expose to customization, e.g.:
Font color
Hover effect
Border color
These are all calculated based on the button background color.
The button is just an example, but I have the same issue with all other elements.
Is there a recommended way to customize parts which are not exposed by the mixin?
I don't want to go into the source and change the actual mixin definition.
If my design spec is very different from Foundation defaults, would it be better to not use Foundation?
Almost every setting can be customized using SASS variables. The most common ones are accessible in _variables.scss, but you can overwrite any of the other variables used in the actual component SCSS files.
For values that don't already have variables, you can override the styles using CSS and include the overrides in a wrapper mixin. Ex:
#mixin my-button-style($bg:$primary-color, $radius:false, $disabled:false) {
#include button-style($bg, $radius, $disabled);
/* CSS overrides go here */
border-color: pink; /* etc */
}
I have a situation where I have to override the less variable property/value with inline variable written in jsp/html. I define few variable in main file (abc.less) as follows:
#bodyColor: rgb(88,90,91); // (#585a5b) grayish
#brandColor1: rgb(23,59,107); // (#173b6b) dark
and I write following ones in jsp/html for changing the color, I am using the same variables name as main file.
#bodyColor: rgb(255,0,0); // (#ff0000) redish
#brandColor1: rgb(204,204,204); // (#cccccc) grayish
but it is overriding the main file property, kindly let me know how it will works. Thanks in advance.
You can create a file with all the colors defined in it as colors.less
#bodyColor: rgb(255,0,0); // (#ff0000) redish
#brandColor1: rgb(204,204,204); // (#cccccc) grayish
then add the following statement at the top in all the other less files,
#import "colors.less";
This way there is not need to change the colors in all the files, instead you can just change it in the colors.less file and it will get updated in all the other places.
You can use the same method for defining and reusing styles, mixins and other variables.
I have few questions on styles (Themes). Presently i get a blue colored theme in all my window and panels. I want to change this to Pink. How can i do that ?
I read about swapStyleSheet( String id, String url) : Void but, i am not sure how to use it.
2.) I also need to know how to change the colors of labels/form panels etc, I want all the styles to be on 1 page, rather than adding it as an attribute in labels/form panels. (eg: fieldStyle: 'background-color: #ddd; background-image: none;')
Although I have not created a custom theme, there is a themeing guide located here: http://www.sencha.com/learn/theming/ that will give you very powerful tools to create your theme instead of styling individual components.
We have many images which are actually picked up based on a color theme (e.g. blue, red, gray ...). We create files with a common name under each theme (e.g. background, ...), is there a way to define the color theme in a common place so that the definition can be abstracted out. This would prevent me from changing the color theme all over the css file.
body {
background: url('../img/blue/background.png');
font-size: 13px;
margin: 0px;
}
While the options suggested here are viable approaches, I'd like to mention SASS and LESS
They are two CSS extension languages, which amongst other things provide variables for doing this sort of color stuff you mention.
You can create dynamical CSS file by using any serverside scripting language like PHP.
style.css.php:
<?php
header("Content-type: text/css");
$theme = 'blue';
$color1 = '#fefefe';
?>
body {
background: url('../img/<?=$theme?>/background.png');
font-size: 13px;
margin: 0px;
}
.sometext {
color: <?=$color1?>
}
I don't believe you can with a pure css implementation as you would need to define your base paths for your images in a variable which you set with some logic (switch statement, if/else if, ..etc.) and then use that variable in the css.
Here are some options I thought of to do this. If you create a pseudo css file with your variable defined as a string that does not occur in css (ex: $basePath) and build out all your css rules in this fake css file as "$basePath+image.jpg". Then with some server side code retrieve the css file and create your template css files by replacing $basePath+ with the actual base path for that theme. The server side code would then save those css files as theme1.css, theme2.css, ...etc.
You then could use url variables to switch between themes using some server side code to insert a reference to the correct css theme file.
This way you would only need to maintain your pseudo template css file. Although you would need to rerun your css creation code each time you change the template css file so that your theme css files get updated.
Not natively in CSS - but you can write some scripts to compile your theme CSS files from templates with variable substitution. I would suggest having a 'layout' and a 'colour' css. The layout would be consistent irrespective of which theme the user is using. The colour css contains only those settings that change per theme.
<style type="text/css">
#import ulr(layout.css);
#import ulr(theme_<?= $activeTheme ?>_.css);
</style>
You could use a tool such as http://lesscss.org/ (if you like Ruby) to create your themed CSS files.
We use NAnt for something similar to this (not CSS, but same idea), and it saves a heap of time rather than maintaining multiple files that differ only by values.