Sass: #Extend Sibling (3rd level) without previous Sibling (2nd) name - css

Currently, I'm looking for the best way go about Sass.. so here is the problem and what structure I'm looking for is:
.block-color-default, .block-color-default--inner{
...........
}
.block-color-default--inner{
.........
}
But a bad result I got from my code is:
.block-color-default, .block-color .block-color-default--inner{
...........
}
.block-color-default--inner{
......... << -- (cannot override the css above)
}
Here is my code:
.block{
&-color{
width: 100%;
height: 500px;
display:block;
background-color: #ccc;
&-default, %third{
width:100px;
height:50px;
background-color:#fff;
&--inner{
#extend %third;
background-color: #000;
}
}
}
}
What's the best way to go about this? I do not want to use !important.
Thank you very much for advices.
Cheers,

Use the #at-root directive to remove all parents in your compiled CSS:
.block{
&-color{
width: 100%;
height: 500px;
display:block;
background-color: #ccc;
#at-root &-default, %third{
width:100px;
height:50px;
background-color:#fff;
&--inner{
#extend %third;
background-color: #000;
}
}
}
}
Generated CSS:
.block-color { width: 100%; height: 500px; display: block; background-color: #ccc; }
.block-color-default, .block-color-default--inner { width: 100px; height: 50px; background-color: #fff; }
.block-color-default--inner { background-color: #000; }
Documentation

Related

How to nest SCSS with "&" properly to re-use immediate parent (partial) class name?

I want to re-use the class name of the parent and use it on a child element, but it is not working as expected when nesting more than one level.
I want to concatenate the child class name only with the immediate parent string and not the whole concatenated parent.
I am starting to believe this is not possible.
The SCSS:
.block {
margin: 2px;
& &__element {
margin: 3px;
&-nested {
margin: 4px;
}
}
}
The output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element-nested {
margin: 4px;
}
The desired output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element .block__element-nested {
margin: 4px;
}
Bro, currently nested-& is not supported in Sass. Hopefully, that's the only solution:
.block {
margin: 2px;
& &__element {
margin: 3px;
}
& &__element &-nested {
margin: 4px;
}
}
EDIT
To achieve your desired output you may do this.
.block {
margin: 2px;
& &__element {
margin: 3px;
}
& &__element &__element-nested {
margin: 4px;
}
}
EDIT 2
.block {
margin: 2px;
& &__element {
margin: 3px;
& .block__element-nested {
margin: 4px;
}
}
}
Output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element .block__element-nested {
margin: 4px;
}
In my opinion, your desired output doesn't make sense because it's very confusing on a larger scale. The bottom example is from the docs. The point is not to go deeper than the third level I think...
.block {
background: red;
&__element {
background: red;
&--nested {
background: red;
}
}
}
.block {
background: red;
}
.block__element {
background: red;
}
.block__element--nested {
background: red;
}
Here 2 solution that are working fine with the use of selector-nest.
You will find more information: https://sass-lang.com/documentation/modules/selector#nest
You can test solution here: https://www.sassmeister.com
Method 1:
.block {
margin: 2px;
& &__element {
margin: 3px;
#{selector-nest('.block__element', '&-nested')} {
margin: 4px;
}
}
}
Method 2:
.block {
margin: 2px;
#{selector-nest('.block', '&__element')}{
margin: 3px;
#{selector-nest('.block__element', '&-nested')} {
margin: 4px;
}
}
}
Apparently this can not be done. As described here as well:
https://css-tricks.com/the-sass-ampersand/#what-the-isnt
My intention was for the & to only get replaced with .parent in hopes of compiling to this:
.parent .child {}
But that doesn’t work.
The & is always the fully compiled parent selector.

#mixin select a specific placeholder by using argument

I'm trying to use a mixin with an argument and inside a placeholder.
The idea is to use one line of code to select a specific placeholder in a class.
Actually, I don't know if there is another better way to do that, maybe with a function or other.
I'm learning Sass, so I'm trying to experiment.
HTML
<div class='wrap'>
<div class='box'></div>
<div class='box'></div>
</div>
SCSS
// VAR
$size-xs: 30px;
$size-s: 50px;
$size-m: 70px;
$color-1: orange;
$color-2: rgb(34,139,86);
#mixin box($val) {
%box-one {
width: $size-s;
height: $size-s;
background: $color-1;
margin: auto;
border-radius: 6px;
}
%box-two {
width: $size-s;
height: $size-s;
background: $color-2;
margin: auto;
border-radius: 6px;
}
.box {
#extend #{$val} !optional;
}
}
.wrap {
width: 100%;
height: 100px;
background: #f5f5f5;
display: flex;
justify-content: space-between;
#include box(box-one);
}
thank you!
Currently, your code is not working because your forgot to put a % before #{$val}:
.box {
#extend %#{$val} !optional;
}
Anyhow, it's not a good idea to put placeholder selectors inside a mixin because every time the mixin is called, you are creating new selectors. It means that for example if you add:
.randomSelector {
#include box(box-one);
}
You will get:
.wrap .box { ... }
.randomSelector .box { ... }
Instead of:
.randomSelector .box, .wrap .box { ... }
So I would recommend you to externalize %box-one and %box-two.
One last thing, if the only difference between these two classes is the background property, maybe using a single class regrouping the commons properties would be a better optimization:
.box {
width: $size-s;
height: $size-s;
margin: auto;
border-radius: 6px;
}
%box-one {
background: $color-1;
}
%box-two {
background: $color-2;
}
#mixin box($val) {
.box {
#extend %box-#{$val} !optional;
}
}
.wrap {
width: 100%;
height: 100px;
background: #f5f5f5;
display: flex;
justify-content: space-between;
#include box(one);
}
If you have more box styles you can even dynamically create the placeholders:
$boxStyles: (
one: $color-1,
two: $color-2
);
#each $box, $style in $boxStyles {
%box-#{$box} {
background: $style;
}
}

Using only CSS is it possible to set a property based on class name?

Say I have some css like:
.modal-350 {
width: 350px;
}
.modal-400 {
width: 400px;
}
.modal-500 {
width: 500px;
}
etc. Using only CSS is it possible to set the width (or other property) just from the class name?
I know in javascript this is easy and also I could just use:
.modal-auto {
display: inline-block;
width:auto;
}
It's not production code, I'm just curious.
No. Even though we can use variables in CSS, we can only do so in property values and not in selector names. So something like this will not work:
.modal-$size {
width: ${size}px;
}
You can, however, use a CSS preprocessor such as LESS or SASS, and generate such rules automagically, given the requested sizes.
A SASS example:
$modal-sizes: 50 100 200 500;
%modal-default {
border-radius: 50%;
color: red;
background: green;
border-color: blue;
}
#mixin modals {
#each $size in $modal-sizes {
.modal-#{$size} {
#extend %modal-default;
width: #{$size}px;
}
}
}
#include modals;
This will compile as:
.modal-50, .modal-100, .modal-200, .modal-500 {
border-radius: 50%;
color: red;
background: green;
border-color: blue;
}
.modal-50 {
width: 50px;
}
.modal-100 {
width: 100px;
}
.modal-200 {
width: 200px;
}
.modal-500 {
width: 500px;
}

LESS puts spaces in wrong places

So... I'am creating a small bootstrap and i want it efficiently done, so i've chose the LESS to do some job for me. And i found that LESS compiler puts spaces between classes when it is written like this:
div.cb {
input[type="text"] {
border: 1px #d9d9d9 solid;
height: 15px;
padding: 5px;
.large {
width: 250px;
}
.medium {
width: 150px;
}
.small {
width: 50px;
}
.fill {
width: 100%;
}
}
}
results in:
div.cb input[type="text"] {
border: 1px #d9d9d9 solid;
height: 15px;
padding: 5px;
}
div.cb input[type="text"] .large {
width: 250px;
}
div.cb input[type="text"] .medium {
width: 150px;
}
div.cb input[type="text"] .small {
width: 50px;
}
div.cb input[type="text"] .fill {
width: 100%;
}
and the gaps between the element and classes prevents in my browser (chrome) in the correct processing. Is there a way to have same or similar code in LESS and have right outputting CSS? Without those gaps...
With less you can reference the parent of a code block by using &
So this:
.class
{
.anotherClass
{
background: red;
}
}
Compiles to:
.class .anotherClass { background: red; }
Whereas this:
.class
{
&.anotherClass
{
background: red;
}
}
Compiles to this:
.class.anotherClass { background: red; }
I hope that makes the difference obvious

Summarize CSS selectors

Is there any possibility to summarize CSS Selectors?
This is my stylesheet:
form.image_form > div > label > img
{
display: block;
margin-left: auto;
margin-right: auto;
}
form.image_form > div
{
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
width: 100%;
height: 156px;
display: table-cell;
vertical-align: middle;
}
form.image_form > div:hover
{
background: green;
}
form.image_form > input[type="radio"]
{
display: none;
}
form.image_form > input[type="radio"]:checked + div
{
background: red;
}
and something like this is what I'd like to archieve:
form.image-form
{
> div
{
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
width: 100%;
height: 156px;
display: table-cell;
vertical-align: middle;
> label > img
{
display: block;
margin-left: auto;
margin-right: auto;
}
:hover
{
background: green;
}
}
> input[type="radio"]
{
display: none;
:checked + div
{
background: red;
}
}
}
So is there any possibility to combine/summarize/interlace this code?
(I apologize if it looks like I did no research, I indeed did but couldn't fine anything in w3c documentation. Maybe I didn't use the right search terms.)
With "pure" CSS this isn't possible. But there are little helpers like LESS or SASS which will help you achieving this.
Nested selectors are not allowed in the CSS3 specification. It's a shame, because it would help to organise CSS files.
You can use preprocessed CSS files instead like SASS.
You need to use CSS pre-processors like SASS and LESS to achive what you are looking for. It cannot be done with pure CSS.

Resources