14

I need to set a Less variable to match the website's active theme, ie, each theme has a different color.

I'd like to set @themeColor to the right color, based on the HTML's body CSS class that defines the theme.

For example:

body.themeBlue { @themeColor: blue; }
body.themeRed { @themeColor: red; }

This way I'd only need to use the @themeColor variable inside the other Less files.

Can anyone help? According to this (http://www.lesscss.org/#-scope) it is possible to do something like that, but I can't make it work. what is going on here?

  • 1
    Unless you are processing the less files clientside, this is not possible due to the fact that the less file will be compiled server side. – Christoph Mar 12 '13 at 17:01
  • thank you for your answer. I wasn't thinking about that. –  Mar 12 '13 at 17:54

3 Answers3

24

The LESS file cannot read the actual class applied to the html body element at run time (you would probably need to implement a javascript solution to do something like that).

If you just want to have all themed css ready for use based on the body class, the best way to implement this to have all the necessary theme based css in a mixin, then apply it under the theme classes. This reduces code duplication. For example:

LESS

//mixin with all css that depends on your color
.mainThemeDependentCss() {
  @contrast: lighten(@themeColor, 20%);
  h1 {color: @themeColor;}
  p {background-color: @contrast;}
}

//use the mixin in the themes
body.themeBlue {
  @themeColor: blue;
  .mainThemeDependentCss();
}

body.themeRed {
  @themeColor: red;
  .mainThemeDependentCss();
}

CSS Output

body.themeBlue h1 {
  color: #0000ff;
}
body.themeBlue p {
  background-color: #6666ff;
}
body.themeRed h1 {
  color: #ff0000;
}
body.themeRed p {
  background-color: #ff6666;
}

For some other answers that deal with aspects or ways of theming, see:

Community
  • 1
  • 1
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • Thank you very much, it works! This will allow me to write less code. I didn't want to duplicate the code 5 times in the entire template. –  Mar 12 '13 at 18:04
  • Yes, the main point of LESS and other preprocessors is to have "less" code duplication. – ScottS Mar 12 '13 at 19:12
  • 1
    Mabbe it's better to pass @themeColor as a mixin parameter? – Aleksei Chepovoi Aug 11 '14 at 11:34
  • Is there any way to make your `@themeColor` variable global? I believe that as is, it is limited to the scope of your mixin, meaning any element you want to apply your @themeColor to needs to be inside the mixin. Ideally we could apply @themeColor outside of the mixin. Is that possible? – Michael Lynch Sep 18 '14 at 16:11
  • @MichaelLynch: It can be global if only a single value for the whole file is needed. The above code creates values that differ _based on body class_, and so the variables all within the scope of that body class call. If you set a global value with the code above, then `.themeBlue` and `.themeRed` would _match values_ for `@themeColor` (not desirable). I encapsulated theme color dependencies into the `.mainThemeDependentCss()` mixin so that they only had to be coded once for each class. Global values could be used if different _CSS files_ handled body class change (perhaps merged after). – ScottS Sep 18 '14 at 17:04
3

Variables in Less are actually constants and will only be defined once.

Scope works within its code braces, so you would need to nest your CSS within each theme you want (which means duplication).

This is not ideal as you would need to do this:

body.themeBlue {
  @color: blue;
  /* your css here */
}

body.themeRed {
  @color: red;
  /* your css here AGAIN :( */
}

You could, however, try to use variables like this:

@color: black;
@colorRed: red;
@colorBlue: blue;

h1 {
  color: @color; // black
  body.themeRed & {
    color: @colorRed; // red
  }
  body.themeBlue & {
    color: @colorBlue; // blue
  }
}

You would only need to declare the colours once, but you would need to constantly do the "body.themeRed" etc. prefixes where the colour varies depending on the theme.

Karl Tynan
  • 125
  • 2
  • 12
  • I was trying to write less code without having to duplicate anything, but it seems I can't. :/ thank you for your answer. –  Mar 12 '13 at 17:53
1

You could actually use @import to load your theme! So common.less would contain all your default styles and @themeColor will be applied to it.

.mainThemeDependentCss() {
  //file with all themed styles
  @import 'common.less';
}

//use the mixin in the themes
body.themeBlue {
  @themeColor: blue;
  .mainThemeDependentCss();
}

body.themeRed {
  @themeColor: red;
  .mainThemeDependentCss();
}

BTW you should avoid using body selector in your common.less, because it wouldn't work.

sliter
  • 71
  • 1
  • 6