Rails SCSS global variables - sass

I've set up my project to use Bootstrap and scss with Webpacker, however, whenever I start my server locally I get this error:
ActionView::Template::Error (Error: Undefined variable: "$secondary-accent".
on line 76:23 of app/assets/stylesheets/_hero.scss
>> border: solid 0.5px $secondary-accent;
This error actually goes away locally if I do a hard refresh, but of course, Capistrano is not as forgiving and I want to figure out the issue anyway.
In my /app/javascscript/ folder I have a src/style.scss file which imports the required stylesheets.
#import '../../assets/stylesheets/_globals.scss'; //import globals first so the values propagate to Bootstrap
#import '~bootstrap/scss/bootstrap'; //import bootstrap
#import '../../assets/stylesheets/application.scss' //import everything else;
/assets/stylesheets/application.scss looks like:
#import '_navbar';
#import 'actiontext';
#import '_hero';
#import 'comments';
#import 'static_pages';
body {
font-family: $body-font;
font-size: $standard;
}
Of course, the easy way to get rid of this is to just add #import 'globals' to each of the partials but that does not seem to fit with the sass way. I don't really want to add #import 'globals' at the top of every single .scss file, not a big deal at the moment but as the project grows and the complexity of the styles increases maintainability could become a headache. I thought that Webpacker would take care of this, am I wrong? Am I missing something in the setup?
Ps. I realize this question has been asked dozens of times, but they all seem to be for older versions of Rails, or the solutions don't apply to me (such as removing the require tree from application.css

This was resolved by tightening my Webpacker set up a bit.
The biggest issue was installing scss I thought sass-rails in my gemfile was sufficient but I also needed yarn add scss. I didn't need to import the globals inside of src/style.scss just in application.scss.

Related

Importing sass files conditionally in to another sass file

In a next.js project, I have a sass file called main.scss.
Here I'm importing another sass file with:
#import "style-1.scss";
But now I'm facing a situation where instead of style-1.scsss, I need to import another sass file called style-2.scss.
Basically I'm trying to find a way to import style-1.scss or style-2.scss conditionally based on a class in body or maybe based on existence of a prop.
Something like this:
if (body has class amp)
#import "style-2.scss";
esle
#import "style-1.scss";
Alternatively (although I don't think that I can use porps in a sass file)
if (prop two is true)
#import "style-2.scss";
esle
#import "style-1.scss";
The main idea is that only one of the two sass files should output any css and the other one shouldn't.
But I still couldn't find a working solution. Any help would be appreciated.

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.

Import Spacing (margin, padding etc) with SCSS in Bootstrap 5

I'm probably missing something obvious here - I'm trying to compile my Bootstrap using SCSS, so I can just select the files I need. Everything working great until I get to the margin and padding classes (e.g. mt-0). I thought these were part of the utilities.scss but apparently not, and I can't seem to track them down. Am I missing an obvious include here?
#import "../../node_modules/bootstrap/scss/functions";
#import "../../node_modules/bootstrap/scss/variables";
#import "../../node_modules/bootstrap/scss/mixins";
#import "../../node_modules/bootstrap/scss/utilities";
// Optional
#import "../../node_modules/bootstrap/scss/root";
#import "../../node_modules/bootstrap/scss/reboot";
#import "../../node_modules/bootstrap/scss/type";
#import "../../node_modules/bootstrap/scss/images";
#import "../../node_modules/bootstrap/scss/containers";
#import "../../node_modules/bootstrap/scss/grid";
The mapping for the margin and padding classes (e.g. mt-0) is in the _utilities.scss [1] file however it generates the classes using the utilities/_api.scss [2] so you'll need below the utilities import:
#import "../../node_modules/bootstrap/scss/utilities/api";
References
[1] Utilities file (https://github.com/twbs/bootstrap/blob/5f89ea3a0f9b56547eb03b98afcd189b89d7e5a6/scss/_utilities.scss)
[2] Utilities API file (https://github.com/twbs/bootstrap/blob/5f89ea3a0f9b56547eb03b98afcd189b89d7e5a6/scss/_utilities.scss)
I just recently had the same issue. Every class worked except classes for margin/padding.
Now (From bootstrap V5.0) left is replaced by start and right is replaced by end.
So change mr-3 to me-3
Here's why

#import url doesn't work with gulp-ruby-sass

I'm trying to compile my scss in a css file.
Everything is working except this :
#import url('http://fonts.googleapis.com/css?family=Roboto:300,400,500,600,700');
In my css, I've got the same thing :
#import url("http://fonts.googleapis.com/css?family=Roboto:400,500,700,300");
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} ......
Here my gulp task :
return sass(vendorFiles.scss.app, {
compass: true,
style: 'compressed'
})
.on('error', sass.logError)
.pipe(rename('app.css'))
.pipe(gulp.dest(distPaths.css));
});
I tried without quotes, without url, none of this worked.
Others imports work but when I try with #import url, with any url, it doesn't matter, it wont work.
Any ideas?
What do you mean by it won't work? Do you get a sass error?
Try https --- note the "s"
Is it the first line of your css?
Where and how do you use Roboto - I see no reference to it?
You are not supposed to use #import in as it can cause render block issues, and i did tried the #import in VSCode with sass-lint. They showed an error.
I would suggest using in this way :
<link href="https://fonts.googleapis.com/css?family=Roboto:400,500,700" rel="stylesheet">
Problem: This method of calling CSS is bad because it adds to the time that it takes to load your css before your page can load.
Solution: Locate the # import calls and replace them.
Detection: Use the pagespeed tool. In the left hand column one of the items is "Avoid # CSS import". If you have a green checkmark, no #imports were found. If found, there will be a red "x".
Details: CSS imports look like this and will usually be near the top of the file.
#import url("style.css")
Rather than call that css file using the import method it is better to just keep that additional css in just one file (copy and paste the imported css into the original css file).
For more info: Go through this link. Dont use #import

Laravel Elixir combining Sass files in wrong order

I have three Sass files in the same directory: _include.scss, app.scss and partials.scss.
Both app.scss and partials.scss have an import at the first line:
#import "include";
And at the first line in _include.scss:
#import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
My gulpfile.js looks like this:
var elixir = require('laravel-elixir');
elixir(function(mix) {
mix.sass([
'app.scss',
'partials.scss'
]);
});
Bootstrap's and my own Sass code is combined into the same CSS file (public/css/app.css). The only problem is that Bootstrap's CSS is inserted after app.scss, so any changes I make will be overridden by Bootstrap if they collide. partials.scss is inserted at the correctly at the bottom.
What causes this? I have, as far as I can see, the exact same setup in other projects without this problem.
The error lies in the doubled #import "include"; statement:
Both app.scss and partials.scss have an import at the first line
There is an issue for import once semantics in SASS, but it is still not resolved. I would suggest to include the library only in one place until the issue is resolved.
Update: There is an informative blog post on the topic as well, which might help you to find a workaround that suits you.

Resources