1

I have the following LESS code:

.favourite-action-link {
    &:after {
        color:@grey;
        content: '\e836';
    }
    &.is-favourite:after {
        color:@red;
        content: '\e811';
    }
    &:hover {
        &:after {
            color:@red;
            content: '\e811';
        }
        &.is-favourite:after {
            color:@grey;
            content: '\e836';
        }
    }
}

With the essential goal being that there is a normal state and a hover state, that are reversed when another class is present. I'll be repeating this for other actions (eg .share-action-link, .review-action-link etc) and this just seems messy the way I have it. Is there a way to create a mixin such that I could provide this like so:

.favourite-action-link {
    &:after {
        color:@grey;
        content: '\e836';
        &:hover {
            color:@red;
            content: '\e811';
        }
        .reverseOnClass(is-favourite);
    }
}

Or something like that? The only way I can think of so far would be to do:

.favourite-action-link {
    &:after {
        color:@grey;
        content: '\e836';
    }
    &.active:after {
        color:@red;
        content: '\e811';
    }
}

and then to use jQuery instead to do the hover - toggling .active on (isHovering XOR hasClass(is-favourite)) - but turning LESS into LESS + jQuery is the opposite of fixing a mess/maintainability issue.

Harry
  • 87,580
  • 25
  • 202
  • 214
Chris O'Kelly
  • 1,863
  • 2
  • 18
  • 35

1 Answers1

2

I would really recommend writing it like below because it keeps the code simple and easy to read.

.favourite-action-link {
  &:after, &.is-favourite:hover:after {
    color: @grey;
    content: '\e836';
  }
  &:hover:after, &.is-favourite:after {
    color: @red;
    content: '\e811';
  }
}

But if you really want to use a mixin to avoid repeating the selectors then you could write it like below. This mixin takes two rulesets as input and they are applied to the required selectors.

.favourite-action-link {
  .rules-gen(
    {
      color: @grey;
      content: '\e836';
    };
    {
      color: @red;
      content: '\e811';
    }
  );
}

.rules-gen(@rule1; @rule2){
  &:after, &.is-favourite:hover:after {
    @rule1();
  }
  &:hover:after, &.is-favourite:after {
    @rule2();
  }
}

In both these methods, the selectors are also grouped and that also means reduced lines of code.

Demo


Or, if the extra class is not always is-favourite and it could also be something else then you could pass it also to the mixin as a parameter like below:

.favourite-action-link {
  .rules-gen(
    {
      color: grey;
      content: '\e836';
    };
    {
      color: red;
      content: '\e811';
    };
    ~"is-favourite"
  );
}

.share-action-link {
  .rules-gen(
    {
      color: yellow;
      content: '\e836';
    };
    {
      color: gold;
      content: '\e811';
    };
    ~"active"
  );
}

.rules-gen(@rule1; @rule2; @addedClass){
  &:after, &.@{addedClass}:hover:after {
    @rule1();
  }
  &:hover:after, &.@{addedClass}:after {
    @rule2();
  }
}

Demo

Harry
  • 87,580
  • 25
  • 202
  • 214
  • 1
    I wasn't tied to a mixin for any particular reason - I can't believe I looked at it for as long as I did and didn't simplify the selectors like you have there first. That's exactly what I need, thanks. – Chris O'Kelly Feb 08 '16 at 05:56