Search code examples
csscolorsthemeslessmixins

LESS CSS - Change variable value for theme colors depending on body class


Getting to grips with LESS here but one thing is still a little unclear.

Lets say I have multiple color themes for my website, controlled by a class on the body tag. From this I can redefine the various colors for each element within each theme. Easy enough but fairly time consuming if I have a lot of elements to change... and a lot of themes. Every time I add a new theme I need to write out all the selectors again, with different color values.

I am basing my working so far on another post I found: LESS.css variable depending on class

... However it still seems overly complicated for what I want to do in that I still have to write out all the selectors and include the mixin before dropping in the same CSS with the color variable.

I have created a CODEPEN HERE

I'd appreciate it if anyone had time to take a little look and advise me how I could approach this differently or how I could streamline this process.

Many thanks to anyone who helps out :)


Solution

  • Assuming you remain with wanting to theme it within one style sheet (and not multiple sheets as cimmanon noted in the comments), and assuming you are using LESS 1.3.2+, then the following code works to reduce the amount of duplication by setting up a loop through the classes that need theme changes.

    Note that this does not work on Codepen (it is throwing an error uncaught throw #, perhaps because they are running an earlier version of LESS), but you can see it compiling correctly by putting the code into LESS's compiler.

    LESS (based off your Codepen code with an added theme for demo)

    //////////////////////////////////////////////////////
    // CONSTANTS
    
    @lightColour: #fff;
    @darkColour: #000;
    @lightBg: #fff;
    @darkBg: #000;
    @numberOfThemes: 3; //controls theme loop
    
    //////////////////////////////////////////////////////
    // MIXINS
    
    //Theme Definitions by parametric mixin numbers (1), (2), etc.
    .themeDefs(1) {
      @lightColour: #f00;
      @darkColour: #fff;
      @lightBg: #f00;
      @darkBg: #fff;
    }
    
    .themeDefs(2) {
      //inverse of 1
      @lightColour: #fff;
      @darkColour: #f00;
      @lightBg: #fff;
      @darkBg: #f00;
    }
    
    .themeDefs(3) {
      @lightColour: #cfc;
      @darkColour: #363;
      @lightBg: #cfc;
      @darkBg: #363;
    }
    
    
    .curvy {
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      border-radius: 5px;
    }
    
    //////////////////////////////////////////////////////
    // GENERAL STYLING
    
    * {padding: 0;margin: 0;}
    html {text-align: center;}
    h2 {padding: 20px 0;}
    
    .box {
      .curvy;
      color: @lightColour;
      background: @darkBg;
      display:inline-block; width:10%; padding:20px 5%; margin:0 1% 20px 1%;
    }
    
    //////////////////////////////////////////////////////
    // THEME BUILDING
    
    .buildThemes(@index) when (@index < @numberOfThemes + 1) {
    
      .theme-@{index} {
          .themeDefs(@index); 
          color: @lightColour;
          background: @darkBg; 
    
          .box {
            color: @darkColour;
            background: @lightBg;
          }
        }
        .buildThemes(@index + 1);
    }
    //stop loop
    .buildThemes(@index) {}
    //start theme building loop
    .buildThemes(1);
    

    CSS Output (only showing the looped theme css for brevity)

    .theme-1 {
      color: #ff0000;
      background: #ffffff;
    }
    .theme-1 .box {
      color: #ffffff;
      background: #ff0000;
    }
    .theme-2 {
      color: #ffffff;
      background: #ff0000;
    }
    .theme-2 .box {
      color: #ff0000;
      background: #ffffff;
    }
    .theme-3 {
      color: #ccffcc;
      background: #336633;
    }
    .theme-3 .box {
      color: #336633;
      background: #ccffcc;
    }