Should module child elements be nested in module modifiers? - css

When writing css using BEM if you need to make changes to a module element when it is in a sub-module do you nest the module-element in the sub-module or create a new class name for the module-element?
Creating a New Class
Creating a new class name(i.e. module--modifier__element) seems to be more in the spirit of BEM. It prevents unnecessary specificity. But it also adds a lot of extra work adding an extra class to each element within the module.
Nesting
Nesting the existing element class within the module modifier(i.e. module--modifier module__element {} will add some extra specificity but saves you a lot of work(at least for large modules) and makes the markup easier to maintain. For example if you needed to change the modifier of a module you would only have to change it one place in the markup rather than having to change it on every child element.
In addition to that if not all of the child elements change then you will have to refer to the css to figure out which child elements need a class added to them.
EXAMPLE CODE
.module {
display: block;
width: 90%;
height: 2rem;
margin: 2rem auto;
padding: 0.5em;
background: #fff;
border: 2px solid #333;
}
.module--modified1 {
background: #333;
border: none;
}
.module--modified2 {
background: #baa;
border: 3px solid #8f8;
}
.module__element {
color: #333;
text-align: center;
}
/* Option 1 */
/* In sass this would actually be nested within the module_modified1 block */
.module--modified1 .module__element {
color: #fff;
}
/* Option 2 */
.module--modified2__element {
color: #fff;
font-size: 1.3em;
}
<div class="module">
<div class="module__element">Module</div>
</div>
<div class="module module--modified1">
<div class="module__element">Module Modifier 1</div>
</div>
<div class="module module--modified2">
<div class="module__element module--modified2__element">Modulue Modifier 2</div>
</div>

Both options are valid. Reduce the specificity is a good practice, but make the code simple is also a good practice.
However, BEM blocks have to be context-free. If a block can be recursively included into itself, then cascades must be avoided. For example, a generic block fun-rounded-block could be recursively reused like this:
<div class="fun-rounded-block fun-rounded-block--blue-version">
<div class="fun-rounded-block__content">
<div class="some-block-here">
<div class="fun-rounded-block">
<p class="fun-rounded-block__content">element in the sub-block here</p>
</div>
</div>
</div>
</div>
In this example, you cannot use a cascade for styling elements because the selector .fun-rounded-block--blue-version .fun-rounded-block__content would interfere with the sub-block.

Related

css having a range after a class attribute

I have three class : product1, product2, product3. I can add css to all these class as follows:
.product1, .product2, .product3{
// add css here
}
But I am looking for more cleaner code to track 1 to 3 followed by 'product' and add css to these. My expectation can be Pseudocode Examples:
.product1to3{
// fun with css.
}
Is there any approach in css?
There is no such kind of css pseudo on what you wanted to achieve.
You can try to use SASS to achieve what you wanted.
and then use the #for Directive
SASS
#for $i from 1 through 3 {
.product#{$i} { width: 20px; }
}
CSS
.product1 {
width: 20px;
}
.product2 {
width: 20px;
}
.product3 {
width: 20px;
}
Also you can try to use LESS
Hope this helps
pure css implementation JSfiddle
So basically you need an "Attribute Begins With Selector" i.e select all classes which start with "product" and then you can use nth child attribute to select range
div[class^="product"]:nth-child(n+4):nth-child(-n+5) {
background: red;
}
Really good article on complex css and nth:child
/* This selects all the elements which have the class name starting with
"product"
*/
[class ^= "product"] {
//CSS
}
If you have an unknown / high number of ".product(x)", and for whatever reason don't want to use an extra class to target them, you can get away with an attribute selector that matches all elements that have a class containing "product".
[class*="product"]
div{
border:2px solid tan;
height:40px;
}
[class*="product"]{
background:steelblue;
}
<div class="product1"> product 1 </div>
<div class="product2"> product 2 </div>
<div class="not"> not a product</div>
<div class="product3"> product 3 </div>
<div class="product4"> product 4 </div>
It occupies just 1 line of compiled CSS, so it's minimal footprint, but be careful how you apply it.
Not an answer for the OP but for others that may find their way here remember that you can use multiple classes for each element.
html
<div class="product product1"></div>
<div class="product product2"></div>
<div class="product product3"></div>
css
/* shared styling */
.product {
display: flex;
background-color: gray;
border: 1px solid red;
}
/* individual styling */
.product1 {
color: black;
}
.product2 {
color: white;
}
.product3 {
color: blue;
}

BEM naming from unique to repeating elements

I have code like this
<div class="chatlist-container chatlist-container_hidden">
<div class="container-header">
<span class="chatlist-title">
</span>
<div class="container-header__button">
<span class="icon-minus"></span>
</div>
<div class="container-header__button">
<span class="icon-cancel"></span>
</div>
</div>
<dl class="chatlist-container__chatlist">
<div class="chatlist-container__chatgroup">
<p ...
<div ...
</div>
<div class="chatlist-container__chatgroup">
</div>
<div class="chatlist-container__chatgroup">
</div>
</dl>
</div>
Where chatlist-container is a main container, then goes container-header , which can be reused in another containers, so he named without dependency chatlist-container__, then goes chatlist-container__chatlist, which exists only inside chatlist-container so he named with his dependency, and then goes chatlist-container__chatgroup, groups which can repeat but only exists inside chatlist-container, how to name their childs, with or withoud dependency of chatlist-container ?
I imagine this like chatlist-container__chatgroup-title and chatlist-container__chatgroup-description, right? But if so, if description will have and childs later, their naming can be very tricky and long.
Also, if so, how to write css, now it looks like:
.chatlist-container { ...
.chatlist-container .chatlist-container__chatlist { ...
.chatlist-container .chatlist-container__chatlist .chatlist-container__chatgroup { ...
But if i add child elements to my groups, their selectors are getting kilometer long, and looks like this
.chatlist-container .chatlist-container__chatlist .chatlist-container__chatgroup .chatlist-container__chatgroup-title { ...
A different approach to the naming could be taken, if you so desired.
You mentioned that other containers exist, and that chatlist_container is only one type of a container, which makes me think that perhaps there should be a container class somewhere with the chatlist version being a modifier, i.e. container--chatlist.
Also, in my opinion, just because chatgroup currently only exists within the chatlist container doesn't mean that it has to have the container's name prefixed to it. Giving it a name like chatgroup allows it to be used outside of the container at some point perhaps. Then any of its children only need to have chatgroup prefixed to their names.
This is not an answer, as you know what you are building far more than any of us here, but perhaps these thoughts might lead you to rethinking the current naming scheme and thus making things easier for yourself.
If maintainability is the issue, i'd suggest using a preprocessors such as sass would help out.. Sass has a functionality with nesting and using the & sign to avoid long rules, pseudo example code:
.wrapper {
height: 100%;
.b-header {
display: flex;
background: #F5F5F5;
flex-direction: column;
padding: 0 2rem;
margin-top: 2rem;
&__about {
width: 100%;
padding: 2rem;
word-wrap: break-word;
.title {
font-size: calc(1.5rem + 3vw);
margin-bottom: 5rem;
}
.job {
font-size: calc(1.8rem + 3vw);
margin-bottom: 1.5rem;
}
.cv {
display: inline-block;
font-size: calc(0.5rem + 3vw);
margin: 3rem 0;
}
}
&__image {
img {
min-width: 100%;
max-width: 100%;
}
}
}
}

Prevent a LESS Mixin being applied if it is within itself?

I have a LESS mixin applied to a number of different classes. Its possible for one element with the mixin to be within another element which also have the mixin. When this is the case I dont want the child element to have the styling applied.
http://codepen.io/anon/pen/NPBWXM
.style1() {
padding: 10px;
border: 1px solid red;
}
.elm1 {
.style1;
}
.elm2 {
.style1;
}
<div class="elm1">Element 1</div>
<div class="elm2">
Element 2
<div class="elm1">Element 1</div>
</div>
No, it appears this is not possible.

whats the CSS selector for a label that does not have a sibling input type=checkbox||radio?

I need to set it with CSS, not jquery.
The selector is for
all labels which do not have a sibling that is a checkbox or radio component.
a sample is:
<span>
<input id="item" type="checkbox">
<label for="item">Data</label>
</span>
This is because i have CSS which sets label to 12px, BUT it affects asp:checkboxes and asp:radio..., but i do not want them to be affected.
There isn't a CSS selector for an element that doesn't have a sibling of a certain kind.
But if you can guarantee that your structure is always an input followed by a label, then you could use the next-sibling combinator with :not() like so to match the label:
input:not([type="checkbox"]):not([type="radio"]) + label
Otherwise you're going to have to add classes to those labels, or use jQuery.
Try adjacent sibling selector:
input[type='text'] + label ​{ // your styles }​​
You need to apply it to all predecessors you need namely. But there are not many possibilities to use label for besides checkbox and radios you don't want ;)
DEMO
You can select elements based on what kinds of siblings they have, IF the siblings precede your target elements. You can do however much type/selector checking you want on preceding siblings of your target.
You can kind of go backwards using nth-last-of-type and nth-last-child, but you can't do any selector checking on elements which follow your target, and the only kind of type checking you can do on following elements is counting how many there are of the same type.
So in your case you could use:
label {
/* your styling here */
}
input[type="checkbox"] + label, input[type="radio"] + label {
/* remove the styling for labels preceded by a checkbox or radio button */
}
Use ~ instead of + if you expect other elements between your inputs and labels.
Depending on what other elements might be inside the spans that you're working with, any of the 'nth' pseudoclasses may be useful to you.
This would also work for your example, if all you care about is that the labels don't have a preceding sibling:
label:first-child {
/* awesome styles */
}
I submitted an answer to a question that I feel is extremely valuable and along the lines to what you're asking for in this question. Here is the permalink to that question/answer.
https://stackoverflow.com/a/43132408/6167697
The key thing that is missing that may not work for your case is I propose keeping the inputs a child only to what they need to be so that other content can be selector'd using generic sibling selectors. Hypothetically you could still keep them in the span, and then use the labels in various elements inside the span, and that would still allow you treat those labels separate from any others I would think. I'll copy in a code snippet for a working example that demonstrates label elements that are not siblings to their inputs that can still be styled.
* {
padding: 0;
margin: 0;
background-color: #262626;
color: white;
}
.radio-button {
display: none;
}
#filter {
padding: 5% 0;
display: flex;
justify-content: center;
}
.filter-label {
display: inline-block;
border: 4px solid green;
padding: 10px 20px;
font-size: 1.4em;
text-align: center;
cursor: pointer;
}
main {
clear: left;
}
.content {
padding: 3% 10%;
display: none;
}
h1 {
font-size: 2em;
}
.date {
padding: 5px 30px;
font-style: italic;
}
.filter-label:hover {
background-color: #505050;
}
#featured-radio:checked~#filter .featured,
#personal-radio:checked~#filter .personal,
#tech-radio:checked~#filter .tech {
background-color: green;
}
#featured-radio:checked~main .featured {
display: block;
}
#personal-radio:checked~main .personal {
display: block;
}
#tech-radio:checked~main .tech {
display: block;
}
<input type="radio" id="featured-radio" class="radio-button" name="content-filter" checked="checked">
<input type="radio" id="personal-radio" class="radio-button" name="content-filter" value="Personal">
<input type="radio" id="tech-radio" class="radio-button" name="content-filter" value="Tech">
<header id="filter">
<label for="featured-radio" class="filter-label featured" id="feature-label">Featured</label>
<label for="personal-radio" class="filter-label personal" id="personal-label">Personal</label>
<label for="tech-radio" class="filter-label tech" id="tech-label">Tech</label>
</header>
<main>
<article class="content featured tech">
<header>
<h1>Cool Stuff</h1>
<h3 class="date">Today</h3>
</header>
<p>
I'm showing cool stuff in this article!
</p>
</article>
<article class="content personal">
<header>
<h1>Not As Cool</h1>
<h3 class="date">Tuesday</h3>
</header>
<p>
This stuff isn't nearly as cool for some reason :(;
</p>
</article>
<article class="content tech">
<header>
<h1>Cool Tech Article</h1>
<h3 class="date">Last Monday</h3>
</header>
<p>
This article has awesome stuff all over it!
</p>
</article>
<article class="content featured personal">
<header>
<h1>Cool Personal Article</h1>
<h3 class="date">Two Fridays Ago</h3>
</header>
<p>
This article talks about how I got a job at a cool startup because I rock!
</p>
</article>
</main>
That has the added benefit of being pure CSS too! And as per the other post, here's the JSFIDDLE so you can play around with it yourselves.

Why are my div boxes ignoring my css code?

Firstly, I would like to say that I have tested if my link to my .css works, the background is made into a black color.
This is a ASP.NET Mvc test application which I am making, and I am having difficulty positioning some of my elements which are nested in div boxes. I have come to the conclusion that my div boxes nested within the topmostheader box is ignoring my .css code.
Here is my entire css file, called custom1.css
#topmostheader
{
background: none repeat scroll 0% 0% rgb(0, 0, 0);
height: 90px;
text-align: center;
}
#topmostheader.inner
{
width: 1280px;
margin: 0 auto;
text-align: left;
background-color: Red;
}
#topmostheader.app-name
{
font-size: 14px;
float: left;
line-height: 90px;
color: rgb(119,119,119);
margin: 0px 20px 0px 0px;
}
#topmostheader.xxx-logo
{
margin: 0px;
height: 90px;
float: right;
}
and here is my div box layout.
<div id="topmostheader">
<div class="inner" >
<div class="app-name">
Lunch Application
</div>
<div class="xxx-logo">
<img src="/content/xxx/logo.png" alt="xxx logo"/>
</div>
</div>
</div>
The desired result is not produced: the app-name, inner and acceleration logo divboxes are all dead-center in the screen, where the app-name must be in the left side, and the logo in the right.
I have tested the following code (Which produced the desired result, in an undesired manner - I may reuse this code multiple times which are in the .css file)
<div id="topmostheader">
<div class="inner" >
<div class="app-name" style="float:left">
Lunch Application
</div>
<div class="xxx-logo" style="float:right">
<img src="/content/xxx/logo.png" alt="xxx logo"/>
</div>
</div>
</div>
What am I doing wrong? Why are my div boxes not "floating" when I use the .css file?
To target the correct divs you need a space between the id and class name in your CSS rules: (e.g. change #topmostheader.app-name to #topmostheader .app-name)
You’re missing a space between your ID selectors and your class selectors.
#topmostheader.inner means “select the element with an id of topmostheader and a class of inner”.
You want #topmostheader .inner, which means “select elements with a class of inner that are descendants of the element with an id of topmostheader“
you need to put a space between the id #topmostheader and the class e.g. .acceleration-logo otherwise the browser assumes you are applying style to div with id #topmostheader and class .acceleration-logo not a child of class .acceleration-logo with parent of #topmostheader

Resources