SCSS Placeholder and Mixin to generate - sass

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

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

Is it possible to create functions (or something else) that include selectors with SASS?

I want to be able to write:
div {
background-size: 100%;
#bgimgfunction('img1.png');
}
and have SASS produce something like:
div {
background-size: 100%;
/* Generated by the call to #bgimgfunction */
background-image:('/img/img1-medium.png');
#media (max-width: 640px) {
background-image:('/img/img1-low.png');
}
#media (min-width: 1600px) {
background-image:('/img/img1-high.png');
}
/* End generated by the call to #bgimgfunction */
}
mixins I think don't work because I can't pass a parameter
functions I think don't work because they are only valid after a selector.
Is there a way to do this?
What you need is a #mixin which does take parameters. Given the structure of your image URLs, I think you need two arguments, one for the image name and one for its extension:
#mixin bgImageFunction($imageName, $imageExt) {
$path: '/img/' + $imageName;
background-image: url("#{$path}-medium.#{$imageExt}");
#media (max-width: 640px) {
background-image: url("#{$path}-low.#{$imageExt}");
}
#media (min-width: 1600px) {
background-image: url("#{$path}-high.#{$imageExt}");
}
}
div {
background-size: 100%;
#include bgImageFunction('img1', 'png');
}
You can also use a default parameter for the extension and only pass the name as argument:
#mixin bgImageFunction($imageName, $imageExt: 'png') {
...
}

How to convert less mixin to scss?

I only just starting to learn both less and sass and can't figure out how to convert this less mixin to scss. This one compiles just fine and provides proper values in a compiled .css file:
.button-styles(#type) {
&--#{type} {
border-color: ##type;
a:hover {
background: ##type;
color: #FFF;
}
}
}
I tried using different converters.
This doesn't work, for example:
#mixin button-styles($type){
&--${type} {
border-color: $$type;
a:hover {
background: $$type;
color: #FFF;
}
}
}
I also tried to tinker with this mixin myself but I can't make it to work.
Help, please.

Import scss file but do not render its contains

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.

Resources