SCSS + BEM style children structure when parent has modificator - html

Please is possible to set scss for element inside --rounded ? I do not wanna use .box__something, but I need to modify children that is depend on parent modifier
<div class="box">
<div class="box__something">Hello</div>
</div>
<div class="box box--rounded">
<div class="box__something">Hi</div>
</div>
.box {
&__something {
background: blue;
}
&--rounded {
background: green;
.box__something { // <<< Is some better selector?
background: pink;
}
}
}

Sass doesn't have any great built-in solutions to solve your issue, this is a problem that has been explored many times. You can however acheive the result you are after in a slightly un-elegant manner by using the & helper to join the classes that you wish to join. I have included a live example here.
While this does work, you must realise that if you want to style the .box--rounded class directly you must have it inside it's own class as illustrated below, you cannot use it with the trailing & class that we have placed &__something on.
I recommend you play around with my sassmeister gist and see what results you can come up with.
.box {
&__something {
background: blue;
}
&--rounded {
background: green;
}
&--rounded & {
&__something {
background: pink;
}
}
}
I hope this has solved your issue.

The modifier should be used not on the parent, and the child element .box__something

If I understand your problem correctly, I feel your pain! As soon as you nest a nested property & changes to the parent.
You can however cache the original class name as a variable like this:
$box: box;
.#{$box} {
.#{$box}__something {
background: blue;
}
.#{$box}--rounded {
background: green;
.#{$box}__something { // <<< Is some better selector?
background: pink;
}
}
}
The only problem with the method above is that you end up with a larger volume of compiled CSS. This renders to:
.box .box__something {
background: blue;
}
.box .box--rounded {
background: green;
}
.box .box--rounded .box__something {
background: pink;
}
To reduce the size of the output you could combine & with the variable method like so:
.box {
$box: &;
&__something {
background: blue;
}
&--rounded {
background: green;
#{$box}__something {
background: pink;
}
}
}
This renders to:
.box__something {
background: blue;
}
.box--rounded {
background: green;
}
.box--rounded .box__something {
background: pink;
}
That way you can change the class name in the variable and everything gets updated, I also think it reads a bit better.

Related

Scss dynamically select an element

I want to know if is there a way to select dynamically an element with same prefix of class but different suffix. Ex:
HTML
<div class="bg-primary-light"></div>
<div class="bg-primary-dark"></div>
CSS
.bg-primary-light { background-color: #fff }
.bg-primary-dark { background-color: #000 }
Is there a way to select for example
.bg-primary {
height: 100px;
.-light { background-color: #fff; }
.-dark {background-color: #000 }
}
`
Just to keep the "parent" properties
You can use the attribute selector with the *= operator to select elements by its partial class name
[class*="bg-primary"][class*="-light"] { background-color: #fff; }
[class*="bg-primary"][class*="-dark"] { background-color: #000; }

Adding a modifier class to parent/root selector in nested SCSS to modify styling

In a nested group of SCSS, is it possible to move up a level and apply a modifier class to the parent to overwrite styling?
For example, I have the following SCSS where an image is added to the before/after classes. I need to change the images on a different .btn-- styling. So essentially compiled the CSS would look a bit like .btn--ghost .label:before, .btn--ghost .after {}.
There is more styling to this but I've just stripped it out for this example so it's not a wall of code.
.btn--arrow {
.label {
&:before,
&:after {
background: url(../img/icon-arrow--white.svg) no-repeat 0 0;
}
&.btn--ghost & {
&:before,
&:after {
background: url(../img/icon-arrow.svg) no-repeat 0 0;
}
}
}
}
I have successfully achieved this with the SCSS outside of the .label, so directly under .btn--arrow (below) but out of curiosity and better understanding I'd be interested to know if it's achievable in the first example I gave.
.btn--arrow {
.label {
&:before,
&:after {
background: url(../img/icon-arrow--white.svg) no-repeat 0 0;
}
}
&.btn--ghost {
.label {
&:before,
&:after {
background: url(../img/icon-arrow.svg) no-repeat 0 0;
}
}
}
}
I have tried moving the & around and using stuff like #at-root but without any success.
Thanks in advance!
You can qualify a selector by putting & to the right of the intended parent of the selector. Wrapping it in #{} allows you to place it directly beside that parent.
The #at-root rule causes everything proceeding to be emitted at the root instead of using regular nesting.
If you use both and the #{}, I think you can achieve what you are looking for.
.flashlight {
.light {
background: yellow;
#at-root .dead-battery#{&} {
background: transparent;
}
.daytime &{
background: transparent;
}
}
}
This would compile to:
.flashlight .light {
background: yellow;
}
.dead-battery.flashlight .light {
background: transparent;
}
.daytime .flashlight .light {
background: transparent;
}

Using CSS Modules with Modernizr (class names)

Modernizr adds classes to the document's <html> tag, e.g. <html class="no-touchevents">.
In my code, I used to write something like this.
.style { background: green; }
.no-touchevents .style { background: red; }
So the element would be green (OK) if the touch is supported and red (error) if it's not. Now with CSS modules, my .style class is defined in a single file and gets transformed into something like this.
.xR23A { background: green; }
.hjTT7 .xR23A { background: red; }
If I wrap my class in a :global clause, it should remain unchanged if I understand it correctly. However, this will apply to every nested class, so I will remain with this.
.xR23A { background: green; }
.no-touchevents .style { background: red; }
How do I solve this to arrive to the desired solution? This is what I am after.
.xR23A { background: green; }
.no-touchevents .xR23A { background: red; }
you should be able to use the paren version of global to only hoise the modernizr portion.
i.e.
.style { background: green; }
:global(.no-touchevents) .style { background: red; }

Difficulties with scss BEM modifiers

I'm having a hard time understanding how to properly write scss with BEM naming conventions.
Here I have some HTML:
<div class="SomeBlock">
<div class="SomeBlock__someElement">text</div>
</div>
<div class="SomeBlock">
<div class="SomeBlock__someElement--greenBG">text</div>
</div>
<div class="SomeBlock">
<div class="SomeBlock__someElement--orangeBG">text</div>
</div>
And the follow scss:
.SomeBlock {
margin: 10px 0 0 0;
color: white;
width: 100px;
height: 50px;
background: red;
&__someElement {
background: blue;
text-align: center;
&--greenBG {
background: green;
}
&--orangeBG {
background: orange;
}
}
}
What I would expect to happen is to have 3 different blocks, all identical but with different colored backgrounds, and this is what happens excepted the text is not centered as I would expect it to be since my element style has text-align: center;
What am I misunderstanding? I've read some tutorials on scss with BEM, but I still do not understand.
Be careful when you reference parent selectors using & in Sass because it does not do what you think it does.
In normal nesting in SCSS, this:
a {
b {
/* styling */
}
}
generates a b { /* styling */ }.
However, when you reference parent selectors using &, this:
a {
&__b {
/* styling */
}
}
turns into: a__b { /* styling */ } // note that this is one class.
What BEM advocates is the use of a systematic way of naming classes to style your document, but manually writing out BEM is a nightmare. Sass parent selector referencing using & makes writing out BEM easy, but you still have to remember that you're only generating class names and not actually nesting when using the & in Sass.
What this all means is that in your case, you'll need to add each of the following classes for your various CSS rules to apply:
<div class="SomeBlock SomeBlock__someElement SomeBlock__someElement--greenBG">text</div>
Actually, you were a bit closer in using BEM accurately than #dippas. I would modify your code like this:
<div class="some-block">
<div class="some-block__some-element">text</div>
</div>
<div class="some-block">
<div class="some-block__some-element some-block__some-element--green-bg">text</div>
</div>
<div class="some-block">
<div class="some-block__some-element--orange-bg">text</div>
</div>
scss
.some-block {
margin: 10px 0 0 0;
color: white;
width: 100px;
height: 50px;
background: red;
&__some-element {
background: blue;
text-align: center;
&--green-bg {
background: green;
}
&--orange-bg {
background: orange;
}
}
}
Here's simplified outputted css to put things in perspective.
.some-block {
/* block styles */
}
.some-block__some-element {
/* element styles */
}
.some-block__some-element--green-bg {
/* element mod styles */
}
As a general rule, whenever you want to use a modifier you'll need to remember to add the element class an additional time with the modifier. So for your element you have a base class of '.some-block__some-element'. You'll need to add this to all the elements that need this class. Then use that same class and add it again to the element with the modifier. In your example, since you only added that base class to the first occurrence of the three elements, css will naturally only style that one with background: blue, and text-align: center.
Additionally, although you can technically get away with using uppercase class names, I would recommend using lowercase class names and separating multiword names with a single hyphen instead of using upper camel casing.
This is the best way to name classes accordingly to BEM methodology:
/* Block component */
.btn {}
/* Element that depends upon the block */
.btn__price {}
/* Modifier that changes the style of the block */
.btn--orange {}
.btn--big {}
Take a look at BEM 101 from CSS Tricks
So I would use it single classes to simplify.
.someblock {
margin: 10px 0 0 0;
color: white;
width: 100px;
height: 50px;
background: red;
}
.some__element {
background: blue;
text-align: center;
}
.green--bg {
background: green;
}
.orange--bg {
background: orange;
}
<div class="someblock">
<div class="someblock some__element">text</div>
</div>
<div class="someblock">
<div class="someblock some__element green--bg">text</div>
</div>
<div class="someblock">
<div class="someblock some__element orange--bg">text</div>
</div>

SCSS: Add element to existing rule

I have some rules nested inside each other, and I'd like to add another unrelated element to one of the rules.
For example if I have
#element1{
display: block;
.sub-element1 {
background: yellow;
.sub-element2 {
color: red;
}
}
}
and then I'd like to add another element (#element2) to use same rules as .sub-element2, so compiled code would look like this:
#element1{
display:block
}
#element1 .sub-element1 {
background:yellow
}
#element1. sub-element1 .sub-element2, #element2 {
color: red;
}
Is it possible?
You could use a mixin. You can add rules to a mixin, then include the mixins where you want them:
#mixin redcolor {
color:red;
}
Then simply include this mixin in any selector:
.subelement2, #element2 {
#include redcolor;
}
More on mixins here:
http://sass-lang.com/guide
Use #extend.
#element2 {
#extend .sub-element2
}
The output created by this will however also copy the selector chain, so this would be the output:
#element1. sub-element1 .sub-element2, #element2 {
color: red;
}
Perhaps that is what you want, but I can imagine it's not.
In this case you'll need to write an #extend only selector. It works much like an #include, except it generates the compact output you outline in your question. You could do it many ways, this is one of them:
%red {
color: red;
}
#element1{
display: block;
.sub-element1 {
background: yellow;
.sub-element2 {
#extend %red;
}
}
}
#element2 {
#extend %red;
}
Here's a link to it in the official docs.