Hoist mixin in sass? - sass

In javascript, I usually write as follow to make code clean.
(function(){
doThing1(()=>{doThing2()});
doThing3();
function doThing1(){...}
function doThing2(){...}
function doThing3(){...}
})();
By moving the functions to the end, it make other dev eaiser to read just by look at the first lines to determine how the main function works.
My questions is how can I do this in sass?
I try following and doesn't work:
#include style1();
#include style2();
#include style3();
#mixin style1(){}
#mixin style2(){}
#mixin style3(){}
It complaint that cannot find mixin named 'style1'

You can't do exactly what you're asking for in part because Sass still works off of the cascade part of CascadingStyleSheets. What's below overrides what is above or, in this case, it uses what's above.
There's still a way to separate your logic from your implementation though, through partials. If you put all your mixins in one scss file, _mixins.scss then you can #import it at the top of your actual style rules. That way someone can jump into your project, see that you're using some hypothetical #include make-container(); mixin, then only go into the mixins file if they actually need to see how it works.
You'd have something like:
#import "mixins";
#include style1();
#include style2();
#include style3();
Here's a good article talking about the general ideas of Sass file organization and partials.

Related

Re-exporting scss functions or mixins

I have the following 3 scss files:
// component.scss
#use 'componentFunctions' as componentFunctions;
/** Adding a default color theme to the component **/
#include componentFunctions.addColorTheme(...);
// componentFunctions.scss
#mixin addColorTheme($param) {
... mixin that creates a color theme for the component
}
// main.scss
#use 'component' as componentName;
/** I would also like to use the createColorTheme mixin in this file, to add a new color theme for this component, in case this module is loaded, how can I achieve this? **/
What I am trying to achieve, is to access the function defined in componentFunction.scss, in the main.scss file. The only way I've managed to do this, is to manually redefine the function in the component.scss file, but surely there has to be a better way around for this.
Strangely, if I am not re-namespacing my imports, everything works automatically. There is a possibility that I misunderstood how the #use functionality works in SCSS, could someone elaborate on how could I achieve the desired effect?
According to Sass docs:
Any styles loaded this way will be included exactly once in the compiled CSS output, no matter how many times those styles are loaded.
So you can use #use again in your main.scss file as the code below:
#use 'component' as componentName;
#use 'componentFunctions' as componentFunctions;
$newVar: componentFunctions.myFunction();
In that way you don't need to redefine the function in the component.scss.

How to access variables imported with #use method in sibling imports

This is my main.scss file.
// Main
// Variables (variables.scss)
#use "../../../style/variables" as *;
// Custom Normalize (normalize.scss)
#use "../../../style/normalize";
// Site header (header.scss)
#use "sections/header";
Variables defined in variables.scss are not accessible in normalize.scss & header.scss. Is there a way to use them inside those files without separate #use 'variables' statement?
Or would you just use separate #use method for each file? I am a newbie, so I don't know what's better.
You have two options.
1. #import
If you use #import except #use for imports, then you can access variables defined in variables.scss inside the normalize.scss & header.scss.
But it has a disadvantage. It is difficult to trace where your variables and mixins are coming from because #import enables an endless chain of imported files. It also allows for overlap and makes it difficult to trace back why your perfect css breaks. This is a problem especially with complex file structures and projects with multiple contributors and global libraries, which is why #import is no longer recommended by Sass.
2. #use
It also works like #import to break our stylesheet into smaller sections and load them inside other stylesheets. The key difference is how you access the original files' members. To do this you will need to refer to the namespace of the original file.
Here's an example of simple SCSS partials.
_variables.scss
$primary_color: #000;
_header.scss
#use 'variables';
.header {
color: variables.$primary_color
}
If you need more info read this article - https://www.liquidlight.co.uk/blog/use-and-import-rules-in-scss/
Let me know if you need further support.

How can I provide configuration variables to a Sass/SCSS file before including it?

I'm migrating a Stylus library to SCSS since Angular 12 has deprecated Stylus and I'm in that impacted 0.3%. I've run into something we were doing that I'm not sure how to convert to SCSS—maybe it's impossible.
Let me lay this out simply: I work on several projects that all use loads of the same styles, so we put those styles together into one style sheet in its own NPM package. We can then just grab #import '#company/design/styles'; and suddenly we've got all of our regular styles and variables and mixins available in the project, or we can import #import '#company/package/styles/common'; for just the variables and mixins.
The thing is, our projects might need to configure the library before we import it. Suppose the library contains this bit:
// #company/package/styles/_forms.scss
input:invalid {
background: url('/assets/input-error.svg') no-repeat center right;
}
Not every project will have /assets/input-error.svg at that exact location. Maybe one of my projects has to use /subfolder/static/input-error.svg.
I could include this then overwrite input:invalid { background-image: url(...) } to supply it with the correct location, but there may be many references to this particular file and many other assets on top of that to correct. So we instead, in our Stylus library, we introduced an $asset-input-error variable that points to /assets/input-error.svg by default and did something like this:
// #company/package/styles/_forms.scss
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
// the local project
$asset-input-error: '/subfolder/static/input-error.svg';
#import '#company/package/styles';
The above is heavily simplified and isn't actually legitimate SCSS, but I hope it conveys what we're trying to do: we want to set up what are effectively environment variables in our SCSS, include the common style sheet, and have it use those variables.
The thing is, I'm not sure what the legitimate or idiomatic approach is to do this in SCSS. Unlike Stylus, which has a global scope for its variables, SCSS would have me #use '../config'; and reference config.$asset-input-error, and from outside the library there's no way I see to change the configuration to point that asset to a different location. I'm sure SCSS has a way for me to do this, but I'm not sure what it is. Do I convert the entire library into a giant mixin to which I pass optional configuration? Do I do something with global variables? Something else?
How can I provide variables to my SCSS style sheet to configure it as part of including it in a project?
Ultimately the end goal here is just to be able to say to the library things like: “the assets to reference are here” (very important) or “the error color is this in this particuilar project” (less important).
Using #import
You can use global variables declared before the #import as you stated.
SCSS Documentation for this method
#company/package/styles/_forms.scss
$asset-input-error: '/subfolder/static/input-error.svg' !default;
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
#company/package/styles/styles.scss
#import 'forms';
local.scss
$asset-input-error: '/different/path/input-error.svg';
#import '#company/package/styles';
CodeSandbox Demo
Using #use [...] with
You can also hop aboard the #use train if you prefer to future-proof your library.
SCSS Documentation for this method
SCSS Documentation for using mixins
SCSS Documentation for configuring forwards
#company/package/styles/_forms.scss
$asset-input-error: '/subfolder/static/input-error.svg' !default;
input:invalid {
background: url($asset-input-error) no-repeat center right;
}
#company/package/styles/styles.scss
#forward 'forms';
local.scss
#use 'styles' with (
$asset-input-error: '/different/path/input-error.svg'
);
Sadly CodeSandbox and StackBlitz don't support dart-sass, so I don't have a live demo for this but I tested it on the latest version of sass from npm.

Create selectors with no declaration

I am planning to use SASS by creating [_partial] and use [#import].
Question: How can I create selectors with no declaration?.
I will of course populate the selectors with declaration,
but that input comes from the other [_partials]. Have I understood correctly that SASS will delete a selector that has no declaration? Is there any workaround?
My partials structure looks as below.
#import '_1-partial_variables.sass'
#import '_2-partial_divs_only.sass'
#import '_3-partial_wrapper.sass'
#import '_4-partial_divs_layout.sass'
What I have tried so far:
In [_2-partial_divs_only.sass] I have tried:
.div-1
(the build executes without errors, but the div itself is not created).
.div-1 {};
(the build script says, "Error: Expected newline".
What about same scenarios using SCSS as source file?
The results are exactly same, a selector with blank declaration, is not created.
My build-line is:
sass --no-source-map main.sass main.css
Seems this works in order for the SASS compiler to create the selector [.div-1]:
.div-1
/*! keep */
This works also:
.div-1
/**/
As the source is a SASS file, I do not add [{}] nor [;].
Those characters are being created automatically when building from SASS to CSS.

Translating LESS mixins to Sass

Well.. Im a little familiar with LESS and when im trying to move up to SASS.
In less i create some framework this way:
.w(#x){width:#x;}
.h(#x){height:#x;}
.f(#x,#y){font:#x '#y'}
i save it framework.less and #import it on my main.less
I just searched but i didnt found how to do it in SASS.. Just read the docs in the official site but no success.
Can anybody explain me or send me a tutorial link? All the links i found on google was a little hard to understand even to make SASS work.
LESS' docs are very simple to understand but SASS is too complicated..
Those are called mixins. You would write them like so:
#mixin w($x){width:$x;}
#mixin h($x){height:$x;}
#mixin f($x,$y){font:$x $y}
Mixin invocation looks like this:
.foo {
#include f(1.5em, sans-serif);
}
However, your f mixin has redundant arguments:
#mixin f($x){font:$x}
.foo {
#include f(1.5em sans-serif);
}

Resources