I have the following SASS structure
.entry {
//some styles here
.banner {
border:4px solid red;
.position {
display: inline-block;
}
}
}
And in html
<div class="entry">
<div class="banner>
<div class="position"></div>
</div>
</div>
Now I want to change the style of .banner and .position when an extra class is added to the entry.
<div class="entry team1">
<div class="banner>
<div class="position"></div>
</div>
</div>
This is a problem I have encountered lots of times and have never found a clean way to do it, the & operator or the #extend could be options but ideally I would like to group all the styles which have the same class.
Any suggestion on how I could write this pattern as efficiently as possible would be appreciated?
Well I would suggest something like that:
.entry {
.banner { /* defaults */ }
&.team1 {
.banner {
/* changes */
.position { /*changes */}
}
}
}
As far as I know, it is not possible to »traverse up the tree« in css, so it wont in scss either.
Another thing that comes to my mind is the #at-root what moves the rule to the root of the generated css. But all in all this will result in a »global« class definition, so I guess that is not what you want.
Related
This question already has answers here:
Is there a CSS selector by class prefix?
(4 answers)
combined multiple classes into one css rule
(3 answers)
Closed 4 years ago.
For instance, I have the following code in a .less file, and would like to simplify it. Each nav is an individual navigation point. When the user hovers over that nav point, I only want that particular nav point's background color to change. Not every single one of them.
.nav-1:hover {
background:#fc9426;
}
.nav-2:hover {
background:#fc9426;
}
.nav-3:hover {
background:#fc9426;
}
.nav-4:hover {
background:#fc9426;
}
.nav-5:hover {
background:#fc9426;
}
.nav-6:hover {
background:#fc9426;
}
.nav-7:hover {
background:#fc9426;
}
.nav-8:hover {
background:#fc9426;
}
.nav-9:hover {
background:#fc9426;
}
Use a comma.
.nav-1:hover,
.nav-2:hover,
.nav-3:hover {
color: #fc9426;
}
Although I don't have any markup to go off of, it looks like you could create a helper/modifier class instead of defining the same thing over and over again.
It might look something like this:
[class^="nav-"] {
margin: 1rem 0;
padding: 0 1rem;
min-height: 3rem;
color: #333;
font: 1rem/3rem Arial, sans-serif;
border-bottom: 1px solid black;
}
/**
* Utility/Modifier style properties that
* any nav could add to their base of styles.
*/
.nav-branded {
color: white;
background-color: #fc643c;
}
.nav-branded:hover {
background-color: hotpink;
}
/**
* These classes have styles specific to
* each class (acts like an ID but
* without the specificity).
*/
.nav-1 {
/* Waiting for some styles. */
}
.nav-2 {
border-bottom-width: 4px;
}
.nav-3 {
border-bottom-style: dashed;
}
<nav class="nav-1 nav-branded">Nav One</nav>
<nav class="nav-2">Nav Two</nav>
<nav class="nav-3 nav-branded">Nav Three</nav>
CSS classes are meant to be re-used so you don't have to define a bunch of different ones to get the same styling.
The point of classes is for a given property to apply to a variety of elements. So you should give each <nav> the same class.
<nav class='color-change'>
.
.
.
</nav>
Then in your CSS / LESS:
.color-change:hover {
background:#fc9426;
}
I think you imagine that you have a code like this
<div class="nav-1"> </div>
<div class="nav-2"> </div>
<div class="nav-3"> </div>
<div class="nav-4"> </div>
If so, you could simplify the code with a better advanced selector
[class*='nav-']{
background:#fc9426;
}
In this way, you will select the elements that in the 'class' attribute have in any part of the code the word 'nav-', which is the piece of the name of the class in common
In the case that in the HTML they have a father
<div class="nav">
<div class="nav-1"> </div>
<div class="nav-2"> </div>
<div class="nav-3"> </div>
<div class="nav-4"> </div>
</nav>
you can use this CSSs
.nav > div{}
.nav [class*='nav-']{}
.nav > div:nth-of-type(1){} /* the number of the son */
.nav > div:nth-of-type(2n){} /* all the pairs */
.nav > div:nth-of-type(2n+1){} /* all the odd */
If you can't change your markup to avoid the redundancy of selectors, you can use an attribute selector to catch all of those classes with a single specifier:
*[class*="nav-"]:hover, *[class*=" nav-"]:hover {
background:#fc9426;
}
The question was originally tagged with less, so if using less, you can also use recursion to generate those classes individually. This task is featured in the manual:
.generate-navs(9);
.generate-navs(#n, #i: 1) when (#i =< #n) {
.nav-#{i}:hover {
background:#fc9426;
}
.generate-navs(#n, (#i + 1));
}
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;
}
I have the markup:
<body class="arabic specific-page">
<div class="child">
<div class="grand-child">
</div>
</div>
</body>
In my sass I am already inside .specific-page and .child. I would like to apply a specific property if body is .arabic:
what I already have:
.specific-page {
.child{
.arabic & {
.grand-child{
gets compilet to:
.arabic .specific-page .child .grand-child
I would like to compile to:
.arabic.specific-page .child .grand-child (body has the same class)
without changing the selector at the top of the tree, only at child level
You can do this using #at-root like so:
.specific-page {
.child{
#at-root .arabic#{&} {
.grand-child{
border: 1px solid red;
}
}
}
}
This compiles to: .arabic.specific-page .child .grand-child, see here.
For this to work you're going to need to alter your SASS a bit. Try
.specific-page {
&.arabic {
.child {
.grand-child {
You could use #at-root and break out of your nesting structure.
.specific-page {
.child{
.arabic {
#at-root .arabic.specific-page .child .grand-child{}
}
}
}
I use an #mixin function like this, when i need change some element in middle
of a sass big tree.
The first parameters is the parent element, the target, and the second the class that should have.
SASS
#mixin parentClass($parentTarget, $aditionalCLass) {
#at-root #{selector-replace(&, $parentTarget, $parentTarget + $aditionalCLass)} {
#content;
}
}
Sample,
like I need to improve font size in a strong tag, when .txt-target had .txt-strong too
HTML
<section class="sample">
<h1 class="txt-target txt-bold">Sample<strong>Bold</strong>Text</h1>
</section>
SASS
section{
.txt-target{
strong{
#include parentClass('.txt-target','.txt-bold'){
font-weight:bold;
font-size:30px;
}
}
}
}
2 options:
.arabic.specific-page {
.child{
.grand-child{
Or (you can switch the order of arabic and specific-page):
.arabic{
&.specific-page {
.child{
.grand-child{
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>
I have two elements, I want to apply same background style, but different font style to them, how to write the style statement in the header part without having to write duplicate statement?
It doesn't get simpler than:
#element1, #element2 {
background: red
}
#element1 {
font: 20px sans-serif
}
#element2 {
font: 24px serif
}
You should read up on selector grouping.
You can apply more than one class to an element...
HTML:
<div class="common div1">My Stuff</div>
<div class="common div2">My Stuff 2</div>
CSS:
.common {
background-color:blue;
background-image:url("bill.jpg");
background-repeat:no-repeat;
}
.div1 {
font-family:Calibri;
}
.div2 {
font-family:Arial;
}
Give it a class + an ID
<style type="text/css">
div.common { background:blabla; }
div #type1 { font-style:blabla; }
div #type2 { font-style:otherblabla; }
</style>
<div class="common" id="type1">asd</div>
<div class="common" id="type2">asd</div>
Or use the method posted by the other guy, 2 classes