Why are my Sass variables shown as not defined upon compilation? - css

I'm trying to set up a project with Sass, and even though I have already made multiple Sass projects and everything seemed to work just fine, now I'm not able to use Sass (SCSS) variables at all. I checked and re-checked all of the syntax multiple times, however I can't seem to find the solution. I use dart-sass, but in the SCSS formatting.
My file structure:
styles
css
style.css
style.css.map
scss
components
_components.scss (uses #forward to import the rest of the files)
globals
_globals.scss (uses #forward to import the rest of the files)
basics.scss
colors.scss (the color variables that I'm talking about are declared here)
fonts.scss
typography.scss
util
_util.scss (uses #forward to import the rest of the files)
functions.scss
style.scss (uses #use to import the rest of the partial indexes)
My syntax for declaring variables and then calling them should be alright:
Declaring (in colors.scss):
$blue-300: hsl(204, 100%, 45%);
Then calling them (e.g. in _globals.scss):
h1 {color: $blue-300;}
I suspect it has something to do with the scope of the documents and their locations in individual folders, but I still can't wrap my head around it.
Thanks in advance

By defaut #use and #forward namespace their variables (see this). Try #forward *file* as * and #use globals/globals as *. This will remove the namespace. If you do want the namespace, try globals.colors.$blue-300.
also can you tell the version of sass you're using? (sass --version)

Related

Sass #extend to consider imported css during build

I have a global CSS file that contains all generic CSS.
I want to be able to extend all the classes present in this global CSS file in any of my SCSS files.
Right now it throws an error .xyz class does not exist and build fails. I tried importing this file but still build fails.
Adding !options next to class is one way for the build to pass but is there any other better way?
Bit more context for Vue users. I use VueCli3. I use <style lang="scss"> for writing SCSS and want to use extend here. Vue documentation suggesting adding prependData for adding variables. I imported the global CSS in a SCSS file and imported that file in the prependData but Vue build still fails.
It sounds like you want to globally include a CSS file with content that the SCSS blocks in each component can read. (Variables, style definitions, etc).
#extend works like a variable, meaning SCSS needs the definition style to be available as part of its compilation. So that means getting "SCSS Global Variables" working should solve your Extend problem too.
In that case, you need to tweak how Webpack deals with your components. You can do it manually as described here. Or my preference is to use a Vue Cli plugin called vue-cli-plugin-sass-resources-loader. Make sure that your component <style> section contains lang="SCSS" though I assume you're already doing that.
Using #import CSS file into SCSS file not possible to #extend any class.
But you can follow below steps for extends class from your pure css code.
Convert .css file into .scss.
import that global.scss file into another .scss file.
Then after you can use #extend for extend class in new file.
If your file have more then 1k line of code then it will get trouble for extend class.

How to use a SASS $variable across multiple pages using #use?

I am trying to use a variable that was declared on one partial inside of another partial, both of which will be loaded into the main.scss file using #use, which will then be compiled into css.
Here's the setup:
style.scss
#use './global';
#use './header';
_global.scss
$black: #262626;
_header.scss
header {
color: $black
}
When I run try to compile style.css, I get this error:
C:\xampp\htdocs\Site\styles>sass style.scss:style.css
Error: Undefined variable.
╷
3 │ color: $black;
│ ^^^^^^
╵
_header.scss 3:10 #use
style.scss 2:1 root stylesheet
It works fine if I use #import instead of #use in my main style.scss, but the developers of Sass advise not to use #import because it is going to be deprecated eventually.
They say to use #use instead, and that #use has many advantages over #import, one of which being that all instances of #use can be loaded at the same time. I think this is what's causing the issue, since _global.scss doesn't get to load before the pages which rely on $black defined in _global.scss, so those pages load without $black defined.
Any ideas?
From the Sass Lang documentation for #use:
Members (variables, functions, and mixins) loaded with #use are only visible in the stylesheet that loads them
Think along the lines of import in JavaScript rather than the traditional global scope of using Sass's #import syntax.
I think you may attempting to do something like the following:
global.scss
$black: #000;
header.scss
#use "global";
.header {
color: global.$black;
}
button.scss
#use "global";
.button {
color: global.$black;
}
index.scss
#use './button';
#use './header';
This might be a bit more verbose/cumbersome than what you're traditionally accustomed to with Sass, but it certainly has tremendous benefits in the long run - especially if you're a framework or library author, or even consuming an existing one with your own modifications on top.
A big pain point with Sass that many developers (myself included) have had to deal with is variables declared at root scope and, indeed, all Sass functions are globally available. While this is convenient at times, it also leads to a large number of collisions when integrating externally-authored libraries or working in larger companies with many distributed teams.
For example: if I'm using Bootstrap as the basis of my website's style, and I load in an additional library that defines its own gradient-bg mixin (also defined in TWBS), which mixin is the correct one to use? Load order has an impact on this, and you may not see any issues, but you may also see huge discrepancies in your expected output which now requires you to dig deep into those libraries to see what's happening.
The #use rule solves this by ensuring that module members (variables, functions, and mixins) are only accessible inside the stylesheets that load them. It also has an added benefit of allowing you to further simplify member names - since they're scoped to a namespace (the last component of the module’s URL) you can go ahead and just define $padding or #mixin flex {}.
Organisation
Ultimately, this can help you to logically organise your own code into a structure that makes it easier to maintain your code going forward (for your colleagues as much as yourself). There's nothing wrong with being explicit in what your code does, especially since you want it to be reliable and predictable when you plan on making updates in the future.
Personally, I'm quite fond of a structure not dissimilar to:
styles
|-- global
| |-- functions.scss
| |-- spacing.scss
| |-- typography.scss
| |-- ...etc...
|-- component
| |-- button.scss
| |-- header.scss
| |-- ...etc...
And in a situation like this, your code would look something like:
button.scss
#use "global/spacing.scss";
#use "global/typography.scss";
.button {
font-size: typography.$standard;
padding: spacing.$standard;
}
Global namespacing
Of course, it all comes down to personal preference and I understand that some people may not be fans of the new namespacing. This can be mitigated somewhat, or ignored entirely.
With #use
When using the new Sass module system, you can't put items in the global namespace when using #use. You can, however, load a module without a namespace by using the #use "path/to/file" as *; syntax. This would allow you to directly access members without needing the <namespace>.<member> syntax.
With #import
If this still doesn't suit your needs, you can of course continue to use the #import rule for the foreseeable future. The team intend to support #import up until some time around October 2022. At this point, you can always pin your version of Sass to the last version that supports #import.
Hello Guys!!
So I've been researching on how to use my SCSS variable in my index style across other style file in my code and I finally figured it out : ). Kindly follow this step carefully and trust me you would get it figured out also
1. Have a index or main file where all your variables are declared in just like this (for me, my file name was "index.scss"
2. After step one is completed now go to any other style file you want to add the variables to. (for me i had a file called "register.scss")
3. import the file where you declared all your scss variable (mine was "index.scss") and do not include the "scss" extension see sample below
NB: You can decide to import it as an alias or without any, if you don't import it as an alias (for me i imported it as 'v') you would have to use the "file_name.variable_name" to use the variable in other file. so as for me i just used "v.$variable_name" since i imported the file as an alias "v".
Boom! You done
I hope this post really helps you! Enjoy and happy coding! : )

Angular 2 - Duplicated <style> blocks everywhere

I am using the latest Angular(4) with Angular CLI. I followed the advice found on SO for setting up global scss that is available to components.
Angular-CLI global scss vairables
My structure looks like this
/
styles.scss
/styles
variables.scss
mixins.scss
common.scss
/app
/component1
component1.scss
/component2
component2.scss
The main styles.scss file has the following code
#import './styles/variables.scss';
#import './styles/mixins.scss';
#import './styles/common.scss';
And in my components, I start each component scss file with the statement of
#import '~styles.scss';
I thought that this was the correct way to bring global variables/mixins/common into my component's scss. However, when I started to have components within components, I began to notice that Webpack was actually creating one block per component in the page, and each one of them had all of the global scss written out in them. So there would be one block for component1, with ALL of the variables,mixins,common stuff at the top, and then another block right below that one for the other component2 in the page, with all that information again.
Besides this being extremely inefficient, it means that the global styles are overwritting themselves (can see that in chrome debug) once for each time they are loaded.
Some direction would be very much appreciated.
The <style> tags are normal angular behaviour. Each components SCSS gets written into a <style> element, so there is nothing wrong with that.
The style.scss is for global styles that do not need encapsulation. It also gets written into a <style> element, if you imported it in your angular.json:
"styles": [
    "styles.css"
],
What you are getting wrong is the question you linked (which is still not accepted).
You shouldn't import your already imported styles.scss (apart from variables or mixins) into your components, because this will lead to increasing bundle sizes, as you import the code over and over (which is also the reason for the GitHub issue you mentioned).
You can use the mixins, variables and common.scss simply by including them directly in your components SCSS, just as you need them.
This is basic sass behaviour, you should never import things that result in css several times (sass files imported into component should typically only contain variables, mixins and functions). If you need your import to happen only once, add it to the default styles file.
Look here

How to avoid multiple #imports of SASS variables?

The site I'm working on uses the rails asset pipeline and an application.scss file to import and process different CSS files.
However, some stylesheets are used in specific places, and for those, it makes little sense to import them into the global manifest. But not so importing them requires importing variables.scss, and possibly mixins.scss into the sheet itself (so they'll process correctly), resulting in duplicate code in the final CSS.
Is there a way to basically tell the preprocessor - "trust me, the variable/mixin you're seeing will be defined by the time everything gets processed"?
Otherwise, I don't see how to avoid importing every sheet into a single manifest, which seems bloated.
Thanks.
The short answer to your question is no. The variables need to be defined in a logical order from when they are called in compilation. It's like a "chicken and the egg" scenario.
From what I can ascertain in your description, the project you're working on is not compiling into a unified workflow, but chunking out into modular portions relational to your file structure. IF this is the case, what you can do at the beginning of each file is reference the variables file from the root.
In a normal workflow, you would import your scss files based on your defined hierarchy like so:
sass/style.scss
/* Main Stylesheet */
#import "variables";
#import "mixins";
/* Modular Sections */
#import "layout/header";
#import "layout/body";
#import "layout/footer";
would compile out to one stylesheet style.css with a command sass sass/style.scss:style.css
What I'm assuming your project does is have all the /* Modular Sections */ files compile out into their own CSS files.
layout/header.scss
/* Header Stylesheet */
#import "../variables";
#import "../mixins";
Given a files structure that resembles:
/root
style.scss
variables.scss
mixins.scss
/layouts
header.scss
body.scss
footer.scss
This all seems kinda silly though. I don't know all the parameters that go into your current sass compilation, but I'd recommend using a unified workflow.
You can use Partials so the compiler will not try to interpret variables etc.
Basically, rename the files that you do not want the compiler to interpret -- but will be available when compiled -- with an underscore before the filename.
eg.
_filename.scss
If I understood well you want to avoid copies of the same css in css files caused by using #import in scss. I solved this problems by doing a hierarchical three.
For exemple consider the home.scss file, where you import header.scss and footer.scss.
Both header.scss and footer.scss use specific colors that you import from a file named colors.scss:
// colors.scss
$MidnightBlue: #00478f;
$RedOrange: #ff5d00;
$MistyBlue: #d8e1e7;
$Ebony: #2a231f;
Now you could import colors in header.scss, footer.scss and maybe even in home.scss. The result is that in home.css the code of colors.scss is repeated 3 times.
A solution is importing colors.scss only in header.scss. Then in home.scss the first #import that you specify is #import "header.scss"; and then #import "footer.scss";, thus you can use the colors variables in footer.scss and in home.scss even if you don't import them directly in footer.scss and home.scss. That's because the variables of colors are imported before the footer and compiled before the rest of the code in home.scss.
Now if you check home.css you shouldn't see repeated code
When at first you write the color variables in footer you will receive an error because they are not defined, but it disappear when you import footer in home.scss
If you #import the same SASS file (e.g. variables.sass) in multiple files and then #import those files in the one main.sass file, the resulting main.css file will contain the content of variables multiple times.
A good way of structuring SASS files is to obey the rule of importing each file only once. Iconic architecture is the 7-1 Pattern. You basically decompose your SASS files into atomic parts and then import those in appropriate order only once in the main file.

How can one import only variables and mixins from Sass stylesheets?

I'm using the Zurb Foundation 4 (S)CSS framework, and I'm running into an issue of massively duplicated styles. This is because in every file that I #import 'foundation' in, all styles from Foundation are also imported (rules for body, .row, .button and friends). This leads to long SCSS compile times and a hard to navigate web developer console in Chrome, as all of Zurb's styles are declared four or five times.
To mitigate this, I've created a globals scss file, which contains the overrideable variables that Foundation uses (it's copy-pasted from foundation_and_overrides.scss, then foundation_and_overrides import globals). Importing just the globals.scss file gets rid of duplication only in files that don't make use of Foundation mixins.
It's in the files which make use of Foundation mixins: Can I import only the mixins from an SCSS file, without importing the concrete Foundation styles?
Imports are an all or nothing thing. Everything that's in the file is what you get. If you look through the source of Foundation, though, there are variables you can modify that will suppress emitting styles (eg. in buttons, setting $include-html-button-classes to false will disable the styles). This design pattern is Foundation specific, you cannot expect other libraries to be authored this way.
When you import foundation via #import "foundation", you're importing this file: https://github.com/zurb/foundation/blob/master/scss/foundation.scss. As you can see, it imports other files. You don't have to import this file if you don't need everything: just import the specific file you want (eg. #import 'foundation/components/side-nav' for only the side-nav file).
I had similar issue, where I wanted to simply use a variable from another file, without import of all CSS.
The #use keyword of newer Sass-versions can be used to ensure CSS is not emitted more than once.
The down-sides are:
Only "Dart Sass" supports compiling it (at least, at time of writting).
#use rules must be written before any other rules.
Last but not least, we can not simply replace #import with #use, and need to prefix scope, like:
#use '../my-module';
body {
background-color: my-module.$my-variable;
}
Warning: #extends keyword(s) can not have my-module. prefix, because extensions are not scoped at all (at least, at time of writting).

Resources