In Sass I have some components (navbar, footer) and some #mixins (fonts) and a function to control the fonts.
I #import the location of the fonts and do #include in the function of the fonts, in this function I just choose the font I want to use.
The problem is that as I separated as "partials" the components (navbar and footer) they have the same sources and I gave #import in those sources in each .scss.
And with that it generates duplicate code in my generated .scss file. I'd like to know what good practices are for this and if I'm doing it right and how do I avoid these duplicates in .scss?
Since I can't see your code, I am not sure how you imported your resources exactly. However, if you are only generating one .css file, a good practice is to import everything on the file that will be compiled and not on each partial.
Let's imagine you have the following structure :
styles
├─ components
│ ├─ _footer.scss
│ └─ _navbar.scss
├─ settings
│ ├─ _functions.scss
│ └─ _mixins.scss
└─ styles.scss
In this example, styles.sccs is the only one that will be compiled, it will be used only to import all partials (the order matters):
// Settings
#import './settings/mixins';
#import './settings/functions';
// Components
#import './components/footer';
#import './components/navbar';
You then can use any mixins or functions in your components and everything is only imported once.
I'm not sure this answers your question – but to prevent duplicates in Sass I would create a mixin to check if an #include has already been made
SCSS
// Global list to keep track of what mixins has been included
$include-once: ();
// Mixin helper to be used inside other mixins we would like
// not to produce duplicate content
#mixin once($mixin-name) {
// check if mixin name exists in our list
#if not index($include-once, $mixin-name) {
// add mixin name to list (using the global flag)
$include-once: append($include-once, $mixin-name) !global;
// print out the content of the mixin
#content;
}
}
// Use example
#mixin font {
// wrap content in the include once wrapper passing the name of the mixin
#include once(font){
// make sure font import is not nested
#at-root {
#import url("https://fonts.googleapis.com/css?family=Open+Sans");
}
}
}
// Test
.foo { #include font; color: red; }
.bar { #include font; color: green; }
.baz { #include font; color: blue; }
CSS Output
#import url("https://fonts.googleapis.com/css?family=Open+Sans")
.foo {
color: red;
}
.bar {
color: green;
}
.baz {
color: blue;
}
I'm sort of late to the game, but I experienced this issue and having partials or using #include did not work. What did it for me was using i.e. css-nano-webpack-plugin https://www.npmjs.com/package/cssnano-webpack-plugin. I'm using webpack v5, so could not get it to work using the webpack mini-css-extract-plugin https://www.npmjs.com/package/mini-css-extract-plugin.
Please bear in mind that the below snippet minimizes and minifies the css PER scss file. So, repetitions between files may still make it in the .css output file.
So, include it in your webpack config like so (source is the npmjs cssnano-webpack-plugin site)
const CssnanoPlugin = require('cssnano-webpack-plugin');
module.exports = {
module: {
loaders: [
{
test: /.s?css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},
optimization: {
minimizer: [
new CssnanoPlugin()
]
}
};
´´´
Related
I have a main.scss file that I want to import colors into from a _colors file.
I have defined a body color in the color file, when I try to import it, I see no changes in the webpage. They are both in the same scss folder but neither #include or #import seem to make a difference. I have tried with and without the underscore in my import statement, both single and double quotes and both import and include keywords. Please tell me what stupid mistake I am making that will rectify this problem as I have researched the problem and think I have been able to copy the examples with no success.
_colors.scss
body {
$background-color: maroon;
}
main.scss
#include 'colors';
Partials are used with #use directive. Then,
_colours.scss
body{
background-color: maroon;
}
style.scss
#use "_colours";
The reuse of code is done through the #mixin directive.
_colours.scss
#mixin body--background{
background-color:maroon;
}
style.scss
#use "_colours.scss" as so;
body{
#include so.body--background;
}
But, if you want to just define just colours use variables instead. Example below,
_colours.scss
$maroon=maroon;
$lightblue=//et cetera.
style.scss
#use "_colours";
body{
background-color:$maroon;
}
If you have a main.scss file which will be the file that gets compiled, and you want to import variables, mixins etc from another partial file, such as _colors.scss. You could do so by loading the members from the partial _colors.scss into main.scss with a #use at-rule. This allows loaded members from the module to be referenced with dot-notation throughout your main.scss stylesheet.
Let's say your _colors.scss file looked like this:
$bodyColor: maroon;
$someOtherColor: #f06;
/* adding a mixin for demo */
#mixin highlight($c, $bg) {
color: $c;
background: $bg;
}
/* some extra styles pertaining to _color.scss */
.some-styles {
color: $someOtherColor;
}
Note: The syntax for #use is #use <url> as <namespace>;.
You could load the variables/mixins etc into main.scss with a #use rule and reference the namespace throughout your program:
#use "./colors" as c;
body {
background-color: c.$bodyColor;
}
.highlighted {
#include c.highlight(#fff, #f06);
}
or without defining a namespace like:
#use "./colors" as *;
body {
background-color: $bodyColor;
}
.highlighted {
#include highlight(#fff, #f06);
}
You certainly can include a body {} declaration inside _colors.scss and load it the same way as discussed above, but I think your wanting to place the body style block inside main.scss and simply reference loaded variables from _color.scss. If you have a directory of many partials and want to load them into main.scss without writing separate #use rules for each load, then introduce a index file with #forward rules to load an entiry directory of partials into main.scss using a single #use rule.
I'm migrating a codebase from using #import to #use and #forward. Most of it is okay but I'm unsure what to do in a case where #import is used with #content.
Considering the following mixing that the only goal is to wrap styles in a class:
#mixin alternative-styles {
.parent-class {
#content;
}
}
The mixin is then used with #import to wrap all those styles in a .parent-class:
#include alternative-styles {
#import 'components';
}
I assumed replacing it with a #forward wouldn't work but have it a try anyway in this way:
#include alternative-styles {
#forward 'components';
}
This threw the following error:
Error: This at-rule is not allowed here.
╷
22 │ #forward 'components';
│ ^^^^^^^^^^^^^^^^^^^^^
╵
I have found that the sass-migration tool solves the issue this way:
#use 'sass:meta';
#use 'mixins';
#include mixins.alternative-styles {
#include meta.load-css('components');
}
The components.scss files has multiple #forward statements to keep all component references in one place like this:
// components.scss
#forward 'components/buttons';
#forward 'components/text';
After the sass compiler runs it results in an empty block:
.parent-class {
}
Is there any way to achieve wrapping a bunch of styles in a class that supports the #use and #forward rules?
I found that the meta.load-css mixin actually does work after creating a separate prototype with the same structure:
#use 'sass:meta';
#use 'mixins';
#include mixins.alternative-styles {
#include meta.load-css('components');
}
More details on using meta.load-css for this case can be found in this GitHub issue: https://github.com/sass/sass/issues/3095
The reason I got the empty .parent-class block was because I was making use of asynchronous compiling with the gulp-sass package. Replacing sass().on(...) with sass.sync().on(...) solved the issue.
For many years I've been completely happy with #import, but times, they are a-changing ...
So I try to shift my projects from #import to #use and #forward, and I found this posting quite useful. But when I try to implement #use into my partials, I keep getting an 'undefined mixin'. I think I may have misunderstood the way #use works, but I can't for the live of me figure out where i went wrong. I've reached the point where I just want to climb the next church tower and start shooting people ... which doesn't help me concentrating either ;)
So I stripped it all down to very basic chunks of code to examine the problem under 'lab conditions'. Here is what I came up whith:
Folders and files:
styles.scss
├── a_tools
│ └── _mixins.scss
├── b_settings
│ └── _global.scss
└── c-components
└── _test.scss
_mixins.scss:
#use '../b_settings/global' as *;
#function bp($bp) {
#return ($breakpoints, $bp);
}
#mixin vp-medium {
#media (min-width: #{breakpoints(small) + 1}) and (max-width: #{breakpoints(medium)}) {
#content;
}
}
_gobal.scss:
$breakpoints: (
'small': 767px,
'medium': 1024px,
'navigation': 840px,
);
:root {
--vp-name: small;
}
#include vp-medium {
:root {
--vp-name: medium;
}
}
_test.scss:
#use 'a_tools/mixins' as *;
#use 'b_settings/global' as *;
.test {
margin: 10px;
#include vp-medium {
margin: 20px;
}
}
styles.scss:
#use 'c_components/test';
Compiling keeps throwing 'undefined mixin on line 15, column 1 of _global.scss', which is the line '#include vp-medium {'. Compiled with Dart Sass 1.32.8.
Who can tell me where I got on the wrong path? Thanks in advance!
As I understand the new ruls #use the way, that you have to #usethe needed files with the needed mixin to EVERY file you want to use it.
If I did get it reight:
You #used the file mixins with mixin vp-medium in test.scss where it is used.
But you did not #use the same file in global where want to use the mixin as well. Just try to #use the file also to global.
ADDITIONAL:
We had similar discussion here: https://stackoverflow.com/a/66300336/9268485
I have 2 scss files, I want to use one mixin from the first into the second, but without importing the rest of the file ( I have a few url() who don't react well into this file
someDir/F1.scss
#mixin somemixin($width, $height) {
}
.someClass {
#include somemixin(17px, 10px);
background-image: url('./someUrl');
}
anotherDir/anotherAnotherDir/F2.scss
#import '../../someDir/F1';
.someOtherClass {
#include somemixin(17px, 10px);
background-image: url('./someOtherUrl');
}
How can I do it?
You can instead try #use module instead of #import and make only mixins public or decide on what you want to make public from file 1.
Check it here
https://sass-lang.com/documentation/at-rules/use
In addition to application.css.scss, I have multiple partials like homepage.css.scss. At the moment I have to add #import 'bootstrap' to each one of them in order to use bootstrap variables and mixins.
Let's say I want to change my default links colour to red, I'd add that to application.css.scss. But the links in homepage.css.scss will not be red because the bootstrap import will override it with blue.
In LESS, I can do #import (reference) "bootstrap", how can I do that in SASS?
The closest you will get is a silent class / placeholder. These work a little different to how LESS and reference work, you can read more on them here: http://blog.teamtreehouse.com/extending-placeholder-selectors-with-sass
LESS
lib.less
.class {
background: red;
}
main.less
#import (reference) "lib";
.anotherClass {
&:extend(.class);
}
SASS
lib.sass
%class {
background: red;
}
main.sass
#import "lib";
.anotherClass {
#extend %class;
}
CSS Output
.anotherClass {
background: red;
}