Import scss file but do not render its contains - sass

I have a SCSS file that contains CSS. I want to extend those classes yet I don't want to render those on my main file (refer below).
File structure:
_vars.scss
main.scss
main.scss
#import 'vars';
//extend margin class
body{
margin: #extend .m10;
}
In my _vars.scss
.m10{margin:10px;}
.p10{padding:10px;}
If the main SCSS is compiled, it will be compiled to:
main.css
.m10{margin:10px;} /* <-- i dont want to see this in my compiled scss --> */
.p10{padding:10px;} /* <-- i dont want to see this in my compiled scss --> */
body{
margin: 10px; /* <-- but still extent from the .m10 class of _vars.scss --> */
}
Any ideas to not display those classes from the _vars.scss yet still extending those classes in the main.scss? Is there a way to do that with SASS?

The way to go is to use placeholders instead of classes:
_vars.scss:
%m10 {
margin:10px;
}
%p10 {
padding:10px;
}
main.scss
#import 'vars';
body {
#extend %m10;
}
Which produces, compiled:
body{
margin: 10px;
}
Placeholders only produce CSS if they are used. Better, they'll concatenate all selectors using them, to avoid duplicate contents:
body {
#extend %m10;
background: red;
}
main > article {
#extend %m10;
}
Will outputs:
body, main > article {
margin: 10px;
}
body {
background: red;
}

The output you get is exactly what it's supposed to be.
If you don't want to have:
.m10{margin:10px;} /* <-- i dont want to see this in my compiled scss --> */
.p10{padding:10px;} /* <-- i dont want to see this in my compiled scss -->
*/
body{
margin: 10px; /* <-- but still extent from the .m10 class of _vars.scss -->
*/
}
You shouldn't use a class and an #extend but a mixin and an #include
Here is what you could do:
#mixin m10 {
margin: 10px;
}
body{
#include m10;
}
It would even be better to add a variable :
#mixin myMargin($size) {
margin: #{$size}px;
}
.input {
#include myMargin(10);
}
This way, you can choose your margin size.

Related

check if the parent has a specific class on it

This is the usual list where one of the items is .open
for this I want to check if the parent (in this case is .item but its not relevant i think) has a specific class.
I've tried > but it doesnt seem to work.
Essentially how to put this:
&.open .info {
display: none;
}
&.open .inner-info {
display: flex;
}
inside of the their specific classes:
.info {
display: flex;
/* some other stuff */
}
.inner-info {
display: none;
/* some other stuff */
}
all of this is inside an .item{} block
So how do i have it so that i only have two blocks inside the .item{}?
It seems overkill to me, but you can use a hacky way to do that using a mixin and various functions. Please note that this will work for your specific example but probably not for something else.
I used the helper functions str-to-list and nth-delete, which are not native to SASS.
#mixin parentWithClass($class) {
$parent: nth-delete(str-to-list(#{&}), -1);
#at-root #{selector.replace(&, $parent, #{$parent}#{$class})} {
#content;
}
}
.item {
.inner {
color: blue;
#include parentWithClass(".open") {
color: orange;
}
}
.inner-info {
color: red;
#include parentWithClass(".open") {
color: grey;
}
}
}
You can also nest -info in inner.

sass merge selectors on ampersand

assuming I have an existing SASS rule like:
[dir] .foo {
background-image: ...;
// ... some more
}
And I want to add specific behaviors for ltr / rtl like:
[dir] .foo {
background-image: ...;
[dir='ltr'] & {
padding-right: ...;
}
[dir='rtl'] & {
padding-left: ...;
}
}
this would generate undesired css like:
[dir='rtl'] [dir] .foo {
padding-left: ...;
}
This will not match what I want.
Assuming I cannot change the parent selectors (due to specificity), is there any way I can write such nested selectors in a way that compiles to just [dir='rtl'] .foo {...} for the nested elements?
Some resources about the ampersand: https://css-tricks.com/the-sass-ampersand/#aa-qualifying-based-on-context
There is no way that I know to merge selectors as requested.
As you're not allowed to change the parent selector, the only solution I see would be to use the #at-root rule.
#at-root
The #at-root rule is usually written #at-root { ... } and causes everything within it to be emitted at the root of the document instead of using the normal nesting. It's most often used when doing advanced nesting with the SassScript parent selector and selector functions.
Definition on sass-lang.
Here is an example:
[dir] .foo {
$root: '.foo';
background-image: linear-gradient(black, white);
#at-root {
[dir=ltr] #{$root} {
padding-right: 1em;
}
[dir=rtl] #{$root} {
padding-left: 1em;
}
}
}
This will compile to:
[dir] .foo {
background-image: linear-gradient(black, white);
}
[dir=ltr] .foo {
padding-right: 1em;
}
[dir=rtl] .foo {
padding-right: 1em;
}
You could create a mixin to help you with that:
#mixin dir($dir: ltr, $selector: &) {
#at-root {
[dir=#{$dir}] #{$selector} {
#content;
}
}
}
[dir] .foo {
$root: '.foo';
background-image: linear-gradient(black, white);
#include dir(ltr, $root) {
padding-right: 1em;
}
#include dir(rtl, $root) {
padding-right: 1em;
}
}
Food for thougt
If you don't have to support internet explorer, you might want to check padding-inline-end and padding-inline-start properties.
They will free you from the need to have different rules for different directions.
padding-inline-end
The padding-inline-end CSS property defines the logical inline end padding of an element, which maps to a physical padding depending on the element's writing mode, directionality, and text orientation.
MDN Docs - padding-inline-end
padding-inline-start
The padding-inline-start CSS property defines the logical inline start padding of an element, which maps to a physical padding depending on the element's writing mode, directionality, and text orientation.
MDN Docs - padding-inline-start

SCSS Placeholder and Mixin to generate

I want to generate multiple CSS-Files
class.css
Should contain from an configuration file (tailwindcss-like) generated utility-first CSS-Classes
.block {display:block; }
.text-center { text-align:center; }
#media (min-width: 768px) {
.md:text-center {
text-align:center;
}
}
components.css
Should contain component-based CSS-Classes
// Input
.avatar { #extend block, background($blue)}
// Output
.avatar { display: block; background-color: blue;}
Question
Is there a way to generate these separated files? I have no idea!
My way to first generate #mixins (or %placeholders, I tried both ways) from a config-file (colors, spacing,...) and afterwards in an second step, building my components.css from these #mixins is not very maintainable

Import multiple files at once (with namespaces) by importing a single file with #use

I have a folder where I store all the variables and functions of the project. Separated by functionality in its own file, with a strong use of namespacing.
Right now, maybe because of lack of knowledge about dart-sass, I am forced to import all these files with #use every time they are needed.
index.scss
#use "core/color";
#use "core/font";
#use "core/spacing";
#use "core/breakpoint" as bp;
#use "core/mixins/normalize";
#use "core/functions" as *;
body {
background-color: color.$background;
font-family: font.$family;
font-size: rem(16px); // rem is a function inside _functions.scss
}
.row {
max-width: spacing.$content-max-width;
padding: 0 spacing.$content-padding;
#media (max-width: bp.$sm) {
padding: 0 spacing.$content-padding-sm;
}
}
.btn {
#include normalize.button;
}
So my question is: is there any way to get that same functionality with a single #use?
I thought something like that would work, but it seems that #forward don't accept namespaces, only prefixes.
// What follows won't work, don't try it. I just want to show what I'm trying to achieve
core/_index.scss
#forward "color" as color;
#forward "font" as font;
#forward "spacing" as spacing;
#forward "breakpoint" as bp;
#forward "mixins/normalize" as normalize;
#forward "functions";
index.scss
#use "core" as *;
body {
background-color: color.$background;
font-family: font.$family;
font-size: rem(16px); // rem is a function inside _functions.scss
}
.row {
max-width: spacing.$content-max-width;
padding: 0 spacing.$content-padding;
#media (max-width: bp.$sm) {
padding: 0 spacing.$content-padding-sm;
}
}
.btn {
#include normalize.button;
}

SASS: create name that is unique per-mixin?

I'm creating a mixin called static() that is used inside another mixin to separate the static properties out into placeholders, so that those properties aren't repeated in the output every time a mixin is used. Here's how you would use it in a mixin called button(), for example:
#mixin button($color) {
#include static('button') {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
background-color: $color;
&:hover {
background-color: mix(black, $color, 15%;
}
}
Here's the code for the static() mixin:
#mixin static($mixin-name, $extend: true) {
// set global $Placeholder-Selectors if it doesn't already exist
$Placeholder-Selectors: () !global !default;
$selector: map-get($Placeholder-Selectors, $mixin-name);
#if $extend == true {
#if $selector == null {
$selector: unique-id();
$Placeholder-Selectors: map-merge($Placeholder-Selectors, ($mixin-name: $selector)) !global;
#at-root %#{$selector} {
#include static($mixin-name, false) {
#content;
};
}
}
#extend %#{$selector};
} #else {
#content;
}
}
The only purpose of the variable $mixin-name is to make sure the declarations of the created placeholder are not overwritten by another placeholder of the same name. My assumption is that the best way to ensure this is to use the name of the mixin itself for the $Placeholder-Selectors' key (since this will be unique to the mixin).
Question:
If that assumption is correct, I don't want to have to type out the name of the mixin I'm using (as in "#include static('button')")...so, in the static() mixin, is there a way to dynamically determine the name of the mixin that static() is being used inside?
Or, is there another way to ensure a placeholder that is unique per-mixin?
No. Sass does not have a way to get any of the names of the mixins used.
That said, you're over-engineering. All you need to do is setup your extend selector outside of the mixin.
%common-button-styles {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
#mixin button($color) {
color: $color;
#extend %common-button-styles;
&:hover {
background-color: mix(black, $color, 15%);
}
}
If you're jumping through all of these hoops in an attempt to avoid creating duplicate extend only selectors via multiple imports, what you're looking for is called import once. If you're a Compass user, 1.0 includes an extension by default that does this. If not, a quick search will show you a few different ways of implementing such a feature.

Resources