CSS Modules, Composition in nested class - sass

I am working on a project where there is a main style.scss file for a number of components. I want to restructure the code so as every component has its own folder (index.js, styles.scss). There is a nested class that is using a class from another component and now that I have to separate all the styles, this part is broken. I can't use composition since it is a nested class. What other approaches can I take?
The code looks like this:
// Component A styless.scss
.component-a-class {
}
// Component B styless.scss
.component-b-class{
.component-a-class {
}
}

Use Sass's #import directive to import the external classes. Your code would become something like this:
// ComponentA/styless.scss
.component-a-class {
...
}
// ComponentB/styless.scss
.component-b-class{
#import "../ComponentA/styless.scss"
}
This will inject .component-a-class into the .component-b-class as a nested rule.
Edit: To import a style and also be able to modify one of its properties' values, you have to make use of Sass mixins:
// ComponentA/styless.scss
#mixin component-a-class($width: 100) {
.component-a-class {
width: $width + px;
}
}
#include component-a-class();
// ComponentB/styless.scss
#import "../ComponentA/style.scss";
.component-b-class{
#include component-a-class(500);
}
This will get you what you want, though it isn't ideal. The resulting compiled ComponentB/styless.css file will include everything written in ComponentA/styless.scss because the #import directive is an "all-or-nothing" feature (there is no selective import). The result would look like this:
// ComponentB/styless.css (compiled)
.component-a-class {
width: 100px;
}
.component-b-class .component-a-class {
width: 500px;
}

Related

SASS/SCSS, how to access a property/method in a dynamic way from a partial file?

Let's say for instance we have the next sass partial file:
//_colors.scss
$foo: red;
And we "use" it on another file:
//test.scss
#use './colors'
.test{
color: colors.$foo;
}
All good, but what if I would like to use/get the value in a dynamic way within a mixin? something like:
//test.scss
#use './colors'
#mixin getColor($type){
color: colors[$type]; //JavaScript example, * don't actually work *.
or
color: #{colors.{$type}; * don't work neither *
//The above returns `color: colors.foo` instead of `color: red` on compilation.
or
color: colors.#{$type}; * doesn't work neither *
}
.test{
#include getColor(foo);
}
Is it possible? thanks for the help!
For a color, I really much prefer a function so it can be used on any property (color, background-color, border, box-shadow...)
I usually declare a string equivalent to variable names, then define them inside a map. Finally this map is accessible via a dedicated function.
Something like
//_colors.scss
#use 'sass:map';
$favoriteRed: "favoriteRed";
$favoriteYellow: "favoriteYellow";
$favoriteBlue: "favoriteBlue";
$MyColors: (
$favoriteRed: #c00,
favoriteYellow: #fc0,
$favoriteBlue: #0cf
);
#function my-color($tone: $favoriteRed) {
#if not map.has-key($MyColors, $tone) {
#error "unknown `#{$tone}` in MyColors.";
}
#else {
#return map.get($MyColors, $tone);
}
}
This _colors.scss generates no code at all, it can be imported anywhere at no cost.
Then, in a specific style file:
//test.scss
#use './colors' as *;
//inside a mixin
#mixin special-hue-component($tone){
div.foo {
span.bar {
border-color: my-color($tone);
}
}
}
//or directly
.foobartest {
color: my-color($favoriteBlue);
}

scss, same class, different elements html

I use scss,
I have a css class, I need some css property to be different, depending of the html element:
<a class="myClass">...</a><input class="myClass"/>
I've try, but it don't work:
.myClass {
&.someOtherClass{...}
&text-area{...}
&input{...}
}
Any idea?
for easy readinf, I need the element to be define INSIDE the class, I can't use something like
input{ &.myClass{...}}
text-area{ &.myClass{...}}
With the #at-root directive you can write your SCSS code in a nested fashion but the resulting CSS will not be nested.
.myClass {
#at-root input#{&} { color: red; }
}
will result in
input.myClass {
color: red;
}
But honestly I don't find this better readable than just doing it KISS:
.myClass { ... }
input.myClass { ... }

sass : import only a part

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

Extending a placeholder and a regular class

I'm having a little issue with SASS #extend, placeholder class and interpolation.
I'm trying to keep the HTML as clean as possible and that's I decided to go for the #extend function in pair with placeholder classes. However, I'm mainly extending layout-related classes like grid, list etc - that's why I'm mixing a placeholder with a regular class in the declaration, i.e:
%drawer,
.drawer {
...
}
Everything was going just fine except for a moment when I noticed the interpolation with the variable being the ampersand in the main class causes some issues. Sample code (with most of the CSS rules removed):
%drawer,
.drawer {
$this: &;
position: fixed;
z-index: 10;
&__content {
right: 0;
transform: translate(100%, 0);
}
&__optional-element {
background: red;
}
&--left { // I want this modifier to be applied to the parent element as it may affect more than one children element
#{$this}__content {
left: 0;
transform: translate(-100%, 0);
}
}
}
And the extension code:
.product-drawer {
#extend %drawer;
&__content {
#extend %drawer__content;
}
}
However, the compiled CSS output is the following:
.drawer--left .product-drawer,
.drawer--left .drawer__content {
left: 0;
transform: translate(-100%, 0);
}
You may notice the first line is redundant and actually wrong. In addition, the "&__optional-element" bit is not outputted for the "product-drawer" extension which makes it really strange. It happens only to rules with the $this interpolation.
As soon as I remove the regular ".drawer" class from the original declaration (and just leave %drawer there), the problem is gone but in these layout-related classes (.grid, .list), we want to keep the regular class name as well so in some various, simple cases it can be used as well, without a need to write new CSS and extending it the placeholder class.
I know that this could be resolved by separating the placeholder class (%drawer) from the regular one (.drawer) completely and then extend the placeholder class inside the regular ".drawer" declaration but that would simply duplicate the code... Or maybe my approach is wrong by design?
Thank you!
The problem is not the #extend rule. The thing is that placeholders are a shallow copy of a class. If you extend from a class you are going to inherit all its properties, but if you extend from a placeholder it is only going to copy the first level.
See this example:
%placeholder{
content: 'placeholder';
&__element{
content: 'placeholder__element';
}
}
.a{
#extend %placeholder;
}
.class{
content: 'class';
&__element{
content: 'class__element';
}
}
.b{
#extend .class;
}
.a {
content: 'placeholder';
}
.class, .b {
content: 'class';
}
.class__element {
content: 'class__element';
}
By using both you're forcing placeholder class to use also the properties:
%placeholder,
.class{
content: 'class';
&__element{
content: 'class__element';
}
}
.b{
#extend %placeholder;
}
.b,
.class {
content: 'class';
}
.class__element {
content: 'class__element';
}

SCSS #import with & to children to class

I know you can do an import inside a class like this:
.my-class
{
#import "another-file.scss";
}
Such that a class .foo in another-file.scss will compile to .my-class .foo in the output.
What I want to do is import a file such that all the rules in the file get a certain class added to them, like this:
.my-class
{
&#import "another-file.scss";
}
Such that .foo in another-file.scss will compile to .my-class.foo in the output.
I'm building a set of components that all share a class because they are all part of the same "kit", and I want them all to share a class that denotes them as such, but I don't want to have them all in the same file under one giant nest.
Is this possible?
Thanks!
To accomplish this, you just need to preface the selectors in the file you are importing with &.
For example, if you were to import the following file, it would create rules for .my-class.header, my-class.header.cool and my-class.footer:
&.header {
color: blue;
&.cool {
font-size: 20px;
}
}
&.footer {
color: blue;
}

Resources