Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS rule for classes with number greater than

Tags:

css

sass

less

My stylesheet looks like this:

.thing-1 { background-image: url('top.png'); }
.thing-2 { background-image: url('top.png'); }
.thing-3 { background-image: url('top.png'); }
/* etc... */

Followed by this:

.thing-20 { background-image: url('bottom.png'); }
.thing-21 { background-image: url('bottom.png'); }
.thing-22 { background-image: url('bottom.png'); }
/* etc... */

I am looking for a way to simplify my stylesheet with LESS or something similar. Here's what I'd like to do:

.thing-[i < 15] { background-image: url('top.png'); }
.thing-[i >= 15] { background-image: url('bottom.png'); }

Is there a way I can do something like this with LESS? If not LESS, maybe SASS?

like image 585
Big McLargeHuge Avatar asked Nov 01 '13 23:11

Big McLargeHuge


People also ask

What does greater than do in CSS?

The greater than sign (>) selector in CSS is used to select the element with a specific parent. It is called as element > element selector. It is also known as the child combinator selector which means that it selects only those elements which are direct children of a parent.

How do I make a class more specific in CSS?

As a special case for increasing specificity, you can duplicate weights from the CLASS or ID columns. Duplicating id, class, pseudo-class or attribute selectors within a compound selector will increase specificity when overriding very specific selectors over which you have no control.


2 Answers

As you are asking for LESS and Sass, here are some solutions. You can achieve it in both with looping through values - but Sass is a bit stronger in this field as it has built-in control directives like @for, @if, @while and @each. There are of course multiple ways of implementing this but this were the first that came to mind:

LESS:

.bg (@i) when (@i < 15) { background-image: url('top.png'); }
.bg (@i) when (@i >= 15) { background-image: url('bottom.png'); }

.things (@max, @i: 1) when (@i < @max) {
  .thing-@{i} { .bg (@i); }
  .things (@max, (@i + 1));
}

.things(50);

and SCSS:

@function bg($i) {
  @if $i < 15 { @return 'top.png' }
  @else { @return 'bottom.png' }
}

@for $i from 1 through 50 {
  .thing-#{$i} { background-image: url(bg($i)); }
}

where you achieve your exact output.

But a more dry output would be achieved with:

LESS: see @seven-phases-max's answer. However, there is the problem of always having to print out .thing-15 also if you only have less than 15 items. Unless you add another guard that adds .thing-15 only when needed like so:

.thing(@i) when (@i = 15) {
    .thing-15 {background-image: url('bottom.png')}
}

you can try out the Less solutions at less2css.org

or SCSS:

%bg-top { background-image: url('top.png'); }
%bg-bottom { background-image: url('bottom.png'); }

@for $i from 1 through 50 {
  .thing-#{$i} {
    @if $i < 15 { @extend %bg-top; }
    @else { @extend %bg-bottom; }
  }
}

The last one in my opinion is the most elegant solution.

DEMO

like image 71
Martin Turjak Avatar answered Oct 18 '22 22:10

Martin Turjak


Preprocessor Not Particularly Needed Under Some Conditions

Update: Made the solution fully general to allow for extra classes on either side of thing-# class.

This is fairly practical with the numbers you are dealing with. Basically the technique is similar to what I answered for this question, but in your case the code is as follows (here is a tweaked example just using background color):

[class*="thing-"] {
    background-image: url('top.png');
}

[class*="thing-1"]:not(.thing-1):not(.thing-10):not(.thing-11):not(.thing-12):not(.thing-13):not(.thing-14),
[class*="thing-2"]:not(.thing-2),
[class*="thing-3"]:not(.thing-3),
[class*="thing-4"]:not(.thing-4),
[class*="thing-5"]:not(.thing-5),
[class*="thing-6"]:not(.thing-6),
[class*="thing-7"]:not(.thing-7),
[class*="thing-8"]:not(.thing-8),
[class*="thing-9"]:not(.thing-9) {
    background-image: url('bottom.png');
}

It uses the attribute selector when it is doing a "general" selection across multiple numbers, and then filters out for specific classes that the general should not apply to.

You Can Reduce the CSS Further

If you change your 1-9 classes to have preceeding zeros (thing-01, thing-02 etc.), then the general css can be reduced further to this:

[class*="thing-"] {
    background-image: url('top.png');
}

[class*="thing-"]:not([class*="thing-0"]):not(.thing-10):not(.thing-11):not(.thing-12):not(.thing-13):not(.thing-14) {
    background-image: url('bottom.png');
}

Practical Limits

This would all get very cumbersome if a break point at a very large number was needed, as more filtering would need to occur. But still some larger levels can be achieved for breaking as my original answer for the other question demonstrated, and at that point, perhaps using LESS or SCSS to somehow do the break pointing might be possible, while still keeping output CSS low.

like image 5
ScottS Avatar answered Oct 18 '22 23:10

ScottS