Which nesting structure (BEM) to use, without modifying the HTML - css

I have two JS components, Parent and Child, each one with its own scss stylesheet. Parent pass a modifier string to Child: one or two. Child renders this modifier in its main div as a BEM modifier class:
<div className="parent">
<div className="parent__title">This is parent</div>
<div className="child child--one">
<div className="child__title">Hello, this is one</div>
<ul className="child__list">
<li className="child__item">item1</li>
<li className="child__item">item2</li>
<li className="child__item">item3</li>
</ul>
</div>
<div className="child child--two">
<div className="child__title">Hello, this is two</div>
<ul className="child__list">
<li className="child__item">item1</li>
<li className="child__item">item2</li>
<li className="child__item">item3</li>
</ul>
</div>
</div>
I want Child to be unaware of Parent, so I can not modify its style in Child.scss: has to be done in Parent.scss.
This is Parent.scss:
.parent {
$root: &;
.child--one {
color: tomato;
&__item {
color: yellow;
}
}
.child--two {
color: blue;
}
}
Here the color: yellow; rule is not applied to .parent .child--one child__item, because it is targeting .parent .child--one__item.
The question is:
without modifying the HTML structure, how can I manage to target .parent .child--one .child__item in an elegant and simple way?
I would like, if possible, to maintain .child nested inside .parent in the stylesheet, to avoid polluting the stylesheets.

I think this is the most organized way to write what you propose.
.parent {
$root: &;
.child--one {
color: tomato;
.child {
&__item {
color: yellow;
}
}
}
.child--two {
color: blue;
}
}
Note that yellow only affects .child--one items and you got to repeat .child inside .child--one in order to reuse the BEM benefits according to your classes names. For example, if you later wanna style &__title or &__list
On the other hand, if you want to reuse .child__item regardless in which child it is, you can do this:
.parent {
$root: &;
.child {
&--one {
color: tomato;
}
&--two {
color: blue;
}
&__item {
color: yellow;
}
}
}

Related

CSS - When input:checked, change another class?

This is my class -
.swatch input:checked + label {
background-color: #fff;
}
.swatch {
Change something here when above class is active.
}
Is there any way to do this? I am using liquid templating if that could be of assistance.
No.
It is possible for one ruleset to affect another using CSS variables…
body {
--example: yellow;
}
input:checked+.swatch {
--example: brown;
}
.swatch {
background: var(--example);
}
<input type="checkbox">
<div class="swatch">
Hello, world
</div>
… but that would only allow the variable to be set on the input, it's descendant (if inputs could have such things) or a later sibling.
There is no parent selector.

Use nth-child on parent level only

I am trying to target all top level .dokan-form-group elements with nth-child.
As you can see, there is a wrapper in the middle called dokan-child-wrapper which has some dokan-form-group elements inside.
I don't want to target these. Only the upper most top level classes which match dokan-form-group, which is a direct descendant of .wrapper.
You can see it's targeting 4 items, but the 3rd and 4th are targeting the child elements which I don't want.
Code example:
https://codepen.io/jordanc26/pen/NWKOXKQ
HTML / SCSS Code:
<div class="wrapper">
<div class="dokan-form-group">parent-item</div>
<div class="dokan-form-group">parent-item</div>
<div class="dokan-child-wrapper">
<div class="dokan-form-group">child-item</div>
<div class="dokan-form-group">child-item</div>
<div class="dokan-form-group">child-item</div>
</div>
<div class="dokan-form-group">parent-item</div>
<div class="dokan-form-group">parent-item</div>
</div>
.
.wrapper {
.dokan-form-group {
background-color: blue;
&:nth-child(0),
&:nth-child(1),
&:nth-child(2),
&:nth-child(3) {
background-color: red;
}
}
}
Change scss to:
.wrapper {
>.dokan-form-group {
background-color: blue;
&:nth-child(1),
&:nth-child(2),
&:nth-child(3),
&:nth-child(4) {
background-color: red;
}
}
}
live demo

scss nesting syntax: nest with parent adjoin class

I want to output:
.selector.another-selector .selector__block{some declaration}
but i want to nest it:
I am using & at the end so I can nest it under __block,
but how can I make it adjoin class with .selector?
code example:
.selector{
&__block{
// i want to put my .another-selector declaration here
.another-selector &{
//syntax issue
//need to make it .selector.another-selector .selector__block
}
}
thanks in advance.
If you nest your selector, then it has to be in the .selector__block context (&).
You have 2 solutions here :
You can repeat the first selector, as such:
.selector {
&__block {
...
.another-selector.selector & {
// Here `&` means `.selector__block`
}
}
}
You can nest differently:
.selector {
&__block {
...
}
&.another-selector &__block {
// Here `&` means `.selector`
}
}
Maybe the second solution is better since it respects the inception rule and is less dependent of the DOM structure.
BTW, you can also try https://www.sassmeister.com/ to play with your selectors
I would suggest that you don't nest BEM at all. Just go with plain declarations for two valid reasons.
1) error tracking nested BEM is hard, let say you get a class from devtools that is .hero__heading. That will not match anything in your code when doing a search. Now the example above is not that hard to figure out anyway but inheriting a project with nested structure is a pain. I suggest reading Harry Roberts article on code smells in css
2) nesting like this will often complicate when wanting to override with other classes like in your case.
Consider this code:
.selector {
background-color: deepskyblue;
}
.selector__block {
color: lightblue;
.another-selector & {
color: lightcoral;
}
}
#Dejan.S I'm not a big fan of BEM (but that's another rant ;-). If however you are using BEM I think nesting will help to illustrate the hierarchy and what to expect
SCSS:
.selector {
// selector styles
color: red;
// default selector block style
&__block { color: green; }
// selector variant selector block styles
&.foo &__block { color: blue; }
&.bar &__block { color: yellow; }
}
CSS Output:
.selector { color: red; }
.selector__block { color: green; }
.selector.foo .selector__block { color: blue; }
.selector.bar .selector__block { color: yellow; }
HTML:
<div class="selector">
Selector <!-- red -->
</div>
<div class="selector">
Selector <!-- red -->
<div class="selector__block">
Selector Block <!-- green -->
</div>
</div>
<div class="selector foo">
Selector <!-- red -->
<div class="selector__block">
Selector Foo Block <!-- blue -->
</div>
</div>
<div class="selector bar">
Selector <!-- red -->
<div class="selector__block">
Selector Bar Block <!-- yellow -->
</div>
</div>

SASS/CSS: :first-child selector not working [duplicate]

This question already has answers here:
CSS selector for first element with class
(23 answers)
Closed 6 years ago.
I'm trying to style a certain <div> in my markup with CSS/SASS, and I'm clueless as to why it's not applying the rules. This is my markup:
<div class="row addon-header">
<div class="col-sm-3">
// something here
</div>
<div class="col-sm-9">
<h2>Title</h2>
<h6><em>Slogan</em></h6>
<div class="col-xs-1">
// I want to access this
</div>
<div class="col-xs-1"></div>
<div class="col-xs-1"></div>
<div class="col-xs-1"></div>
</div>
</div>
And this is the SASS I'm trying to use for it:
div.addon-header {
color: white;
> div.col-sm-9 > div.col-xs-1:first-child {
background-color: black;
padding-left: 0px !important;
}
}
If I remove the :first-child selector in my SASS, it's working, but obvious for every <div class="col-xs-1"> not just the first one, which is not what I want.
I also tried playing around and doing something like
div.addon-header {
color: white;
> div.col-sm-9 > div.col-xs-1 {
&:first-child {
background-color: black;
padding-left: 0px !important;
}
}
}
or
div.addon-header {
color: white;
> div.col-sm-9 {
> div.col-xs-1:first-child {
background-color: black;
padding-left: 0px !important;
}
}
}
or using :nth-child(1) instead. Nothing works. I'm clueless. Somewhere else in my SASS, I have the following:
.tab-content {
>.tab-pane:first-child > form > div.row > div {
// rules here
> div.picture-container {
// rules here
}
}
>.tab-pane {
// rules here
}
>.tab-pane:nth-child(4) > form {
// rules here
}
}
Which is working just fine. So I really don't get what I'm doing wrong in the first example. Anyone able to help?
You need the :nth-of-type() (or, in your case, the :first-of-type selector).
In the example your provided the :first-child of .col-sm-9 element is the h2.
div.addon-header {
color: white;
> div.col-sm-9 > div.col-xs-1:first-of-type {
background-color: black;
padding-left: 0px !important;
}
}
Note, though, that the :nth-of-type() selectors, like the :nth-child() selectors, apply to tags only, not class names; if you were to insert another div before the first .col-xs-1 then this would no longer work.
col-xs-1 need to wrap row because this block is not first element. First element is h2

How to override a property set in an id (CSS)

Suppose the following code:
<div id="body" class='bodyLogin'>
#body {
background-color: red;
}
I would like to override the background colour through the class attribute, like this:
#body .bodyLogin {
background-color: blue;
}
but this doesn't work.
Similarly:
.bodyLogin {
background-color: blue;
}
doesn't work due to CSS hierarchy.
The space between your two selectors is meaningful. In fact it is a selector: the descendant selector. It means you select all of class bodyLogin descendant of an element with id body.
Get rid of the space and you select elements that are both #body and .bodyLogin:
#body {
background-color: red;
}
#body.bodyLogin {
background-color: blue;
}
<div id="body" class='bodyLogin'>Test</div>

Resources