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.
Related
How can I change the font for all items in Vuetify from Roboto to another.
I use Vuetify, there is a default Roboto font. I want to change it to another. Changing the font in the variables.scss file does not help, because each class has a specific Roboto font.
#import url('https://fonts.googleapis.com/css? family=Oxygen:300,400,700&display=swap');
#import url('https://fonts.googleapis.com/css? family=Comfortaa&display=swap');
$body-font-family: 'Oxygen';
$title-font: 'Comfortaa';
$heading-font-family: 'Oxygen';
However, when I use classes like this:
class = "text-md-h6 text-lg-h6 .text-xl-caption"
the Roboto font is still used.
#media (min-width: 1024px)
<style>
.v-application .text-xl-caption {
font-size: 0.75rem !important;
font-weight: 400;
line-height: 1.25rem;
letter-spacing: 0.0333333333em !important;
font-family: "Roboto", sans-serif !important;
}
What do I need to do to change the font in all places?
This should work by setting the font variables in variables.scss file as documented here. A couple things to check if it doesn't work:
The file should be in an expected folder src/[sass, scss or styles]. Docs.
Vuetify Loader should be installed along with sass and sass-loader as dev dependencies
Variables file only contains variables, not imports. Fonts could be declared/imported in main or elsewhere.
it's a bad practice to use !important for most of the cases and unfortunately because those font-family styles also have !important CSS will only use the style with a more specific selector so You also have to use !important. You can try something like .v-application .v-application--wrap * with !important. so it will be like :
.v-application .v-application--wrap * {
font-family: $body-font-family !important;
}
and if you have different styles for different classes , you can just put all of them inside a .v-application .v-application--wrap { } and sass will process them for you. but also note that other vuetify classes might use more specific selectors , so in those cases you have to use more specific selectors for those specific cases.
I want to make a light mode for a website that uses SASS with variables in it. So, here are the variables and smth I tried (but doesn't work):
#media (prefers-color-scheme: dark), (prefers-color-scheme: no-preference) {
$bg: #0d0d0e;
$c0: #ffffff;
$c1: invert(#333);
$c2: #7c7c7c;
$c3: invert(#aaa);
$c4: invert(#eee);
}
#media (prefers-color-scheme: light) {
$bg: #fff;
$c0: #000;
$c1: #505050;
$c2: #66666a;
$c3: #aaa;
$c4: #eee;
}
I have to keep SCSS. Should I try #mixin?
That won't work with Sass variables during runtime since they are being compiled and then statically served. What you can do though is using CSS custom properties aka CSS variables. Those can be changed during runtime with Javascript (more versatile) or use media queries along with the boolean context value prefers-color-scheme. This value is unfortunately set by the user's browser environment and cannot be changed with Javascript.
You can however just switch the colors around with Javascript. With an onClick event you just save the state of current color in a buffer, assign the current color with the alternative color and then set the alternative color to the one saved in the buffer (aka the former current color).
I've tried switching around colors stored in CSS custom properties with a checkbox and the input:checked selector but the changes have only local scoping (thanks, W3C), so they won't do you any good - that is of course unless you want to wrap your whole website in your color switcher element.
The only way with Sass variables would be to recompile the Sass stylesheets when a user switches over the color scheme.
tl;dr: use CSS custom properties and either go with browser defaults in media queries or use a bit of Javascript. Everything else is very hacky.
I'm defining each theme side by side and using them inside #media (prefers-color-scheme).
Even made my self a mixin:
/** Helper to tigth properties to color preferences */
#mixin color-scheme($value: light) {
#media (prefers-color-scheme: $value) {
#content;
}
}
/** Usage */
.element {
/* ... */
#include color-scheme(dark) {
/* ... */
}
}
i read this article http://www.sitepoint.com/dealing-color-schemes-sass/ and I wanted to try to apply the method but I've a question: It's possible use this with a variable?
Ex. I use bootstrap and i wanna change only value (without assign a property) for $brand-primary, can i change this value with this method?
I've assigned a dynamic class on my body ( or ), and i wanna change a $brand-primary value for every class...
Another Ex.
If body class is "en" $brand-primary: red; if body class is "it" $brand-primary: blue; if body class is "fr" $brand-primary: green;
It's possible?
Thanks for your reply.
Perhaps the cleanest way to accomplish this is to create a mixin, and then pass in theme color variables.
The theme mixin code takes in all necessary colors, as well as a name that corresponds to the body class:
#mixin theme($name, $brand-primary) {
body.#{$name} {
background-color: $brand-primary;
}
}
Create a separate Sass partial for housing your theme color variables. In this case, it would look something like this:
$brand-primary: green;
Create as many of these files as you have themes.
Using the themes is then as simple as:
#import 'Themes/_theme-name.scss';
#include theme("theme-name", $brand-primary);
Bonus - if you need to apply styles to a specific theme, it's as easy as an #if statement in the mixin:
#if ($name == "theme-name") {
.class-name {background-image: url(example.png);}
}
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";
I have a common.less file, that implements the basic CSS for different skins:
#textColor: black;
#iconSize: 16px;
.container: {
color: #textColor;
background-color: white;
}
.icon: {
width: #iconSize;
height: #iconSize;
}
// note that #iconSize is also used in this file inside mixins
The plan is to use it like so skin_1.less:
#iconSize: 32px; // override the icon size
// but leave #textColor as default
#import "common.less";
.container: {
color: red;
}
// I would now have big icons and red text
So I would like to have a common style, that I can reuse and selectively override variables.
This does not ssem to work however. I think it's because imports are always moved to the top, so variables cannot be pre-defined.
(I also read that variables are rather constants, so that may be another problem.)
Anyway: is there a better pattern to solve my use case?
You don't need to split the files up, just override the variable after the import. Variables are always resolved as the last definition, even if it is after where it is used.