I am trying to implement theme switching between three themes. Dark, Light and a 3rd theme.
My idea is to define 3 variable.less files, one for each theme. In the file, I re-define antd colors. reset.less will import variable.less to reset colors defined in antd.less.
Like the code below:
// dark theme
.dark {
#import '~ant-design-vue/dist/antd.less';
#import "styles/asia-info/themes/dark-theme/reset.less";
#import "styles/asia-info/themes/dark-theme/components.less";
#import (css) "../common.css";
}
// Light theme
.light {
#import "~ant-design-vue/dist/antd.less";
#import "styles/asia-info/themes/light-theme/reset.less";
#import "styles/asia-info/themes/light-theme/components.less";
#import (css) "../common.css";
}
//3rd theme
.china-mobile {
#import '~ant-design-vue/dist/antd.less';
#import "styles/china-mobile/reset.less";
#import "styles/china-mobile/components.less";
#import (css) "../common.css";
}
But the above code does not work. I think the problem is you cannot import same antd.less file in less. I tried to add (multiple) keyword when import the same file, but it takes forever for vue-cli to compile. So now what I am doing is:
// dark theme
.dark {
#import '~ant-design-vue/dist/antd.less';
#import "styles/asia-info/themes/dark-theme/reset.less";
#import "styles/asia-info/themes/dark-theme/components.less";
#import (css) "../common.css";
}
// light theme (import and.less and common.css in main.js in Vue)
#import "styles/asia-info/themes/light-theme/reset.less";
#import "styles/asia-info/themes/light-theme/components.less";
// 3rd theme
.china-mobile {
#import '~ant-design-vue/dist/antd.less';
#import "styles/china-mobile/reset.less";
#import "styles/china-mobile/components.less";
#import (css) "../common.css";
}
If I only have dark and light theme, I import antd.less in main.js for the light theme, and import antd.less 2nd time inside .dark for the dark theme. It seems to work.
But when I add the 3rd theme, since same antd.less imported again, when I switch to the 3rd theme, colors does not change.
Right now, the solution I can see is to reset colors for each antd classes in the 3rd theme. But this is really troublesome, there are so many classes I have to reset.
Wondering if there is a better solution?
Related
I am attempting to add a custom color map in Bulma, with the following SCSS code:
// Set your colors
$primary: #5B43CC;
$primary-invert: findColorInvert($primary);
$twitter: #4099FF;
$twitter-invert: findColorInvert($twitter);
$facebook: #4267B2;
$facebook-invert: findColorInvert($facebook);
$custom-colors: (
"foo": (black, grey),
);
// Import Bulma's core
#import "~bulma/sass/utilities/_all";
// Links
$link: $primary;
$link-invert: $primary-invert;
$link-focus-border: $primary;
// Import Bulma and Buefy styles
// this has been moved to App.vue because it must be at the end
#import "~bulma";
#import "~buefy/src/scss/buefy";
But I get the following error:
ERROR Failed to compile with 6 errors 1:26:26 AM
error in ./src/App.vue?vue&type=style&index=0&lang=scss&
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: argument `$color` of `darken($color, $amount)` must be a color
on line 150 of node_modules/bulma/sass/elements/button.sass, in function `darken`
from line 150 of node_modules/bulma/sass/elements/button.sass
from line 4 of node_modules/bulma/sass/elements/_all.sass
from line 5 of node_modules/bulma/bulma.sass
from line 40 of src/assets/scss/main.scss
from line 2 of /c/Users/Raj/Projects/testsite/src/App.vue
>> background-color: darken($color-invert, 5%); }
----------------------------^
# ./node_modules/vue-style-loader??ref--8-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=style&index=0&lang=scss& 4:14-416 14:3-18:5 15:22-424
# ./src/App.vue?vue&type=style&index=0&lang=scss&
# ./src/App.vue
# ./src/main.js
# multi (webpack)-dev-server/client?http://localhost:8080/sockjs-node (webpack)/hot/dev-server.js ./src/main.js
However, if I comment out // $primary-invert: findColorInvert($primary); then the error goes away. Also, if the snippet under // set your colors is moved after #import "~bulma/sass/utilities/_all", then the error also goes away.
What am I doing wrong here?
Note, this is a follow-up to this previous post
So as I mentioned in the comments, when it comes to Sass compilation it's all about ordering (of imports and/or variable declarations). Now, since those color inversions are using a Bulma utility called findColorInvert, which resides within utilities/functions.sass, we can't probably import the utilities with the original order here.
We could split them and insert our customs in between the functions and derived-variables:
#import "~bulma/sass/utilities/initial-variables";
#import "~bulma/sass/utilities/functions";
// Set your colors
$primary: #5B43CC;
$primary-invert: findColorInvert($primary);
$twitter: #4099FF;
$twitter-invert: findColorInvert($twitter);
$facebook: #4267B2;
$facebook-invert: findColorInvert($facebook);
// Links
$link: $primary;
$link-invert: $primary-invert;
$link-focus-border: $primary;
$custom-colors: (
"foo": (black, grey),
);
#import "~bulma/sass/utilities/derived-variables";
#import "~bulma/sass/utilities/animations";
#import "~bulma/sass/utilities/mixins";
#import "~bulma/sass/utilities/controls";
I am using the nativescript Core Theme.
my app.js: (I use the Light-Theme or Dark-Theme and it works fine)
import Theme from "#nativescript/theme";
Theme.setMode(Theme.Light); // Or Theme.Light
// Importing the global css file
import "./assets/css/global.css";
my app.scss:
#import "~#nativescript/theme/core";
#import "~#nativescript/theme/default";
#import "~#nativescript/theme/scss/variables";
My ActionItems are black when i use the default-theme, i want to set blue ActionItmes.
How can I achieve this?
my Actionbar:
It get's a little bit weird when i am using a wrong theme like "grey". Then the buttons are blue and even the searchbar is shown in the right way! But then all other css-settings are defect.
Problem
About overriding !default variables -- I have two .sass files:
main.sass
$variable: black
#import "_another_import.sass"
#import "_import.sass"
_import.sass
$variable: blue !default
body
background: $variable
The $variable resolves to blue in the compiled CSS:
body {
background: blue;
}
However, if I specify the overriding variable value right before I import the _import.sass stylesheet, Sass compiles it to black:
main.sass
#import "_another_import.sass"
$variable: black
#import "_import.sass"
Question
Is this behavior intended? Is there a way to declare overrides for !default variable values earlier than the !default values are declared in imports (maybe even in a separate file)?
Actual setup (for reference)
My actual setup is a little bit more complicated than that. I am using Myg (NPM components) with myg-rails (generating file structure to customize variables) and Webpack. So I have a myg.sass file loading _variables.sass and _myg.sass. _variables.sass loads a couple of other files which define the variables. _myg.sass imports the Myg (NPM) components. I verified that when I define a variable in _variables.sass and use it + set a default in a Myg component, the default will override the already set value.
No, what you are doing should work. The resulting behavior you're experiencing is irregular and not intended.
From sass-lang docs:
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.
I suspect there may be something else at play that we need to investigate.
I've verified the correct behavior with these files:
Sass source:
_t1.sass
div
margin: 0
_t2.sass
$c: blue !default
body
background: $c
main.sass
$c: black
#import '_t1.sass'
#import '_t2.sass'
CSS result:
div {
margin: 0;
}
body {
background: black;
}
It is black as intended.
My suggestion is :-
1) If you want black background then you simply do like this
// main.sass
#import "_another_import.sass";
#import "_import.sass";
// _import.sass
$variable: black;
body{
background-color: $variable !important;
}
But my suggestion is that your file structure like this
#import "_variable"; /*Define Variable in separate file & in that file declare $variable*/
#import "_another_import.sass";
#import "_import.sass";
body{
background-color: $variable !important;
}
I think you are misunderstanding what !default does. It is saying if variable is not assigned, use this value.
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.
Using this tutorial (on How to use Elixir and Laravel 5.* with Bootswatch) , I setup a Bootswatch stylesheet in my Laravel project with Elixir.
Everything works fine, the stylesheets are loaded and I have the Lumen style as wanted. But I don't get how to modify the Bootswatch variables ?
Here is my app.scss. Bootswatch files are loaded before I modify the variable :
#import "bootstrap/stylesheets/bootstrap/variables";
#import "bootswatch/lumen/variables";
#import "bootstrap/stylesheets/bootstrap";
#import "bootswatch/lumen/bootswatch";
#import url('https://fonts.googleapis.com/css?family=Lato:100');
#import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css');
$brand-danger: purple;
But it doesn't works here.
When modifying this variable into vendor/bower_components/bootswatch-sass/lumen/_variables.scss, it works.
And here is the gulpfile.js :
var elixir = require('laravel-elixir');
var bowerDirBootstrap = "vendor/bower_components/bootstrap-sass-official/assets/";
var bowerDirBootswatch = "vendor/bower_components/bootswatch-sass";
var bowerDirJquery = "vendor/bower_components/jquery/dist/";
elixir(function(mix) {
mix.sass('app.scss')
// copy relevant files to the resources folder. This is the css
.copy(bowerDirBootstrap, 'resources/assets/sass/bootstrap')
.copy(bowerDirBootswatch, 'resources/assets/sass/bootswatch')
// this is the javascript
.copy(bowerDirJquery + 'jquery.js', 'resources/assets/js/jquery.js')
.copy(bowerDirBootstrap + 'javascripts/bootstrap.js',
'resources/assets/js/bootstrap.js')
.version('css/app.css')
mix.scripts([
'js/jquery.js',
'js/bootstrap.js'
],
'public/js/app.js',
'resources/assets'
);
});
To be honest I don't exactly understand the "copy" parts : when I delete them, everything still works as said before : modifying the variable in _variable.scss works, updating the variable in app.scss doesn't.
Edit
I've tried to put the variable everywhere and with / without the !default flag, nothing works.
$brand-danger: white !default;
#import "bootstrap/stylesheets/bootstrap/variables";
$brand-danger: white !default;
#import "bootswatch/lumen/variables";
$brand-danger: white !default;
#import "bootstrap/stylesheets/bootstrap";
$brand-danger: white !default;
#import "bootswatch/lumen/bootswatch";
$brand-danger: white !default;
#import url('https://fonts.googleapis.com/css?family=Lato:100');
$brand-danger: white !default;
#import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css');
$brand-danger: white !default;
So, I'm getting crazy. I've got a
/style-1.scss
and then
/css/style-2.scss
style-2 imports style-1 and compiles in /css
style-1 also compiles in root /
style-1 also imports _utilities and _fonts (that should use the path variables)
I've got to set paths for sprites and fonts on style-1, but obviously I'd like to change the path based on the fact that style-1 is imported or directly compiled
I've tried to use global vars and then a flag var to use like this:
#if variable-exists($imported) do this.. else..
But no luck. It seems you can't change global variables from anywhere before or after importing.
Have you ever faced a problem like this? Any solution?
The unwanted behaviour of your styles is the result of how sass works.
Sass #import imports and renders (if the file contains css output) files in order that statements are made. So if you create an imported file that defines and use internally some variables to create css output, although you modify them before or after import, the css output will remain be the same. Here's an example:
foo.scss
$width: 10px;
a { width: $width; }
bar.scss
$width: 20px;
#import "foo"; // Import and then renders
$width: 30px;
bar.css
a { width: 10px; }
So you have mainly two alternatives:
Use !default
!default description 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.
So, in your case, you can do this:
style-1.scss
#import "utilities";
#import "fonts"
$foo-sprite: "path/to/foo.png" !default;
.foo-icon { background-image:url($foo-sprite) }
style-2.scss
$foo-sprite: "../path/to/foo.png";
#import "../style-1.scss";
And these would be the CSS output files:
style-1.css
.foo-icon { background-image:url("path/to/foo.png") }
style-2.css
.foo-icon { background-image:url("../path/to/foo.png") }
Create a new partial imported in both files
Sometimes you can't edit variables because it comes from imported frameworks so, in this case, the best way to deal with your problem is creating a new partial to be imported by style-1.scss and style-2.scss, let's call it _common.scss. _common.scss should contain the sass code from style-1.scss that must be rendered. This way, you can get different paths for each style file.
style-1.scss
#import "utilities";
#import "fonts";
#import "common"; // This is the
style-2.scss
#import "utilities";
#import "fonts";
#import "paths"; // You can import here different sprite and font paths
$foo-path: "../foo/bar.css" // You can also declare variables here if you prefer
#import "common";