Puggan Se
Puggan Se

Reputation: 5846

How to use variables in a selector

With .class & I can add rules adds a parent-class to the path, but it always put that parent in the front of all parents.

Is there someway to add a parent in the middle somewhere.

I tried using a variable for it like this: Example less:

@color: "";
.a {
  .b @color {
    .d {
      .e {
        font-size: 2em;
        color: black;
        @color: ".yellow";
        color: yellow;
        @color: ".red";
        color: red;
        @color: "";
      }
      .f {
        font-size: 1.2em;
      }
    }
  }
}

Expected output:

.a .b .d .e {
  font-size: 2em;
  color: black;
}
.a .b .yellow .d .e {
  color: yellow;
}
.a .b .red .d .e {
  color: red;
}
.a .b .d .f {
  font-size: 1.2em;
}

But that didn't work.

So how do I write something that generates that output in a good way. I'd like to have the color variation close to the default color. And I'd like to not have unnecessary duplicated code = not reseting the font-size to the same value for each color.

Upvotes: 0

Views: 206

Answers (2)

seven-phases-max
seven-phases-max

Reputation: 11820

The use-case is pretty close to various "theming" Qs like:

I.e. there're many possible solutions, each having its pros and cons depending on other details and goals of your real project.

---

Taking your "expected output" as-is, a good start would be to write a mixin that handles the repetitive code, e.g.:

#1

.a .b {
    .d .e {
        font-size: 2em;
        color: black;
    }
    .-(@color) {
        .@{color} .d .e {color: @color}  
    }
    .-(red);
    .-(yellow);
    .-(green);
    // etc.
}

---

With some trickery and hackery we can get rid of .d .e repetition but I doubt an increased complexity and potential issues will worth it:

#2

.a .b {
    .themed(~'.d .e', {
        font-size: 2em;
        color: black;
    }, {
        color: @color;
    });
}

// .....................
// generic "theme" impl.

.themed(@selector, @default, @colored) {
    .-(default);
    .-(red);
    .-(yellow);
    .-(green);

    .-(@color) {
         .@{color} @{selector}
             when (iscolor(@color)) {@colored();}
         @{selector}
             when not (iscolor(@color)) {@default();}
    }
}

---

To illustrate that variations of possible implementation to get to the "expected output" example are nearly infinite and mostly depend on what Less features you're familiar with and what features you can/want/like to use, here is a bit more "Modern Less" example using more "conventional"/"mainstream" logic (many people will prefer to use; req. Less 3.x or higher):

#3

.a .b {
    .d .e {
        font-size: 2em;
        color: black;
    }
    each(red yellow green, {
        .@{value} .d .e {color: @value}
    });
}

(though the same has been already suggested in another answer).

---

Speaking of .color elements in the middle of a selector, think if your HTML really requires this. I.e. will you actually need such overspecific selectors as:
.a .b .yellow .d .e,
.x .y .yellow .d .e,
.p .q .yellow .d .e,
.a .b .yellow .foo .e,
having different color values?

Won't a set like .yellow .e {color: yellow} or something be enough?

Upvotes: 1

soulshined
soulshined

Reputation: 10622

You can use a variable as a selector:

@color: .yellow;
.a {
  .b @{color} {
    ...

But it won't work in your example because variables are compiled from last use up the chain (this is why you can reuse the variable), meaning .red will never populate where you want it (same place as the yellow, because it resides in the last scope)

You could do many things to circumvent it, mixins, functions, includes, maps etc, really whatever fits your needs. Here is a simple example with a generic loop:

@colors: cornflowerblue, green, red, yellow;

.a  {
  .b {
    each(@colors, {
      .@{value} .d {
        .e {
          color: @value;
        }
      }
    });
    .d .e { 
      font-size: 2em;
    }
    .d .f {
      font-size: 1.2em;
    }
  }
}

You can click on 'see compiled css' button at the bottom of the snippet embed, or see here

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css" data-user="soulshined2" data-slug-hash="ErBYOY" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="ErBYOY">
  <span>See the Pen <a href="https://codepen.io/soulshined2/pen/ErBYOY/">
  ErBYOY</a> by soulshined (<a href="https://codepen.io/soulshined2">@soulshined2</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

Upvotes: 1

Related Questions