0

I've got a Less mixin with a default state and a hover state. Now I need to activate the hover state in the mixin when I'm hovering over the parent element.

Less

#icons () {
  .settingsIcon() {
    background: url("settings.png");
    &:hover {
      background: url("settings_hover.png");
    }
  }
}

.SettingsButton {
    height: 50px; 
    width: 200px;
   .icon {
       #icons > .settingsIcon();
    }
}

HTML:

<div class="SettingsButton" >
  <span>Settings</span>
  <div class="icon"></div>
</div>

I need to make sure that the same effect that happens on settingsIcon hover is triggered on the button hover also. So I think I need to do something like this, where I 'call' the hover of settingsIcon somehow. Something like this (not valid Less code)

.SettingsButton:hover {
  .icon {
     #icons > .settingsIcon():hover;
  }
}

How would I do that?

Harry
  • 87,580
  • 25
  • 202
  • 214
Drkawashima
  • 8,837
  • 5
  • 41
  • 52
  • @Harry [have you not found one?](http://stackoverflow.com/questions/30048985/) [And there was](http://meta.stackoverflow.com/q/283550/792066) – Braiam May 07 '15 at 16:50
  • @Harry well, how you expect that there's "community consensus" if you don't participate? There was a discussion, the interested sides were heard, I'm just applying what those interested parties discussed. (BTW, less tag contains: css preprocessor "less", "less" the opposite of more (the command line tool) and "less" rails) – Braiam May 07 '15 at 16:57
  • @Harry that wouldn't fix the main problem: less means 3 different things. [That shouldn't be allowed](http://meta.stackoverflow.com/questions/283550/removing-the-less-tag-from-unix-questions-using-the-less-command-good-thing#comment147717_283552) (also Mooing Duck comment). Do you have any suggestion which allows the problem to be fixed? Mine is: create the 3 needed tags (maybe more, you know, programmers sucks at naming stuff), move the questions to those tags, and burninate plain [less]. – Braiam May 07 '15 at 17:07
  • @seven-phases-max [We need \[less\] no more](http://meta.stackoverflow.com/q/293664) BTW, are you willing to retag those questions each time they appear? – Braiam May 07 '15 at 17:21

2 Answers2

1

It would probably be better to re-write your mixins like in the below example. Essentially we are splitting your base setting and hover setting into two different mixins within the same namespace (#icons()) and then call them as required.

#icons () {
  .settingsIcon() {
    background: url("settings.png");
  }
  .settingsIconHover(){     
    background: url("settings_hover.png");
  }
}

.SettingsButton {
  height: 50px; 
  width: 200px;
  .icon {
    #icons > .settingsIcon();
    &:hover{
      #icons > .settingsIconHover();
    }
  }
  &:hover .icon{
    #icons > .settingsIconHover();
  }
}

Another way to achieve this while still maintaining only a single entry in #icons for all the states is to move the .icon selector also to be within the mixin like in the below snippet.

#icons () {
  .settingsIcon() {
    .icon{
      background: url("settings.png");
    }
    &:hover .icon, & .icon:hover{ /* & here means .SettingsButton */
      background: url("settings_hover.png");
    }
  }
}

.SettingsButton {
  height: 50px; 
  width: 200px;
  #icons > .settingsIcon();
}
Harry
  • 87,580
  • 25
  • 202
  • 214
  • I would really prefer to let each icon be represented by a single entry in #icons(), and nest all the states (like hover and active). Having to define 2 disconnected rules in #icons() just to represent 2 states of the same thing sort of ruins the LESS structure I had in mind – Drkawashima May 08 '15 at 20:24
  • @Drkawashima: I have added a different version to the answer. I hope this helps you. – Harry May 10 '15 at 05:06
0

It is my understanding that you can solve this issue by using extend too.

.settingsIcon {
    background: url("settings.png");
    &:hover {
      background: url("settings_hover.png");
    }
}


.SettingsButton {
    height: 50px;
    width: 200px;
    &:extend(.settingsIcon all);
    .icon {
       &:extend(.settingsIcon all);
    }
}

outputs:

.settingsIcon,
.SettingsButton,
.SettingsButton .icon {
  background: url("settings.png");
}
.settingsIcon:hover,
.SettingsButton:hover,
.SettingsButton .icon:hover {
  background: url("settings_hover.png");
}
.SettingsButton {
  height: 50px;
  width: 200px;
}

Notice that the above generate a not used .settingsIcon selector in your CSS. Cause Less does not enable you to extend mixins (see: https://github.com/less/less.js/issues/1177) which do not output, you can only solve this by putting the .settingsIcon declaration in a different file a @import that file by using the reference keyword:

settingsicon.less:

.settingsIcon {
    background: url("settings.png");
    &:hover {
      background: url("settings_hover.png");
    }
}

project.less:

@import (reference) "settingsicon.less";
.SettingsButton {
    height: 50px;
    width: 200px;
    &:extend(.settingsIcon all);
    .icon {
       &:extend(.settingsIcon all);
    }
}

Now compiling project.less generates:

.SettingsButton,
.SettingsButton .icon {
  background: url("settings.png");
}
.SettingsButton:hover,
.SettingsButton .icon:hover {
  background: url("settings_hover.png");
}
.SettingsButton {
  height: 50px;
  width: 200px;
} 

--

NB aren't you looking for CSS for hover that includes all child elements in the first place?

update @harry wrote:

My understanding was that the same background needed to be applied for .SettingsButton:hover .icon and .SettingsButton .icon:hover only.

I think that makes sense. You can do that by using extend too, but i also agree that extending the same class twice is not so DRY too.

With settingsicon.less being again:

.settingsIcon {
    background: url("settings.png");
    &:hover {
      background: url("settings_hover.png");
    }
}

You can use:

@import (reference) "settingsicon.less";
.SettingsButton {
  height: 50px;
  width: 200px;
  &.icon {
  &:extend(.settingsIcon);
  }
  &:hover, & .icon:hover {
  &:extend(.settingsIcon:hover);
  }
}

or:

@import (reference) "settingsicon.less";
.SettingsButton {
  height: 50px;
  width: 200px;
  & .icon {
  &:extend(.settingsIcon all);
  }
  &:hover {
  &:extend(.settingsIcon:hover);
  }
}

which both compile into:

.SettingsButton.icon {
  background: url("settings.png");
}
.SettingsButton:hover,
.SettingsButton .icon:hover {
  background: url("settings_hover.png");
}
.SettingsButton {
  height: 50px;
  width: 200px;
}
Community
  • 1
  • 1
Bass Jobsen
  • 48,736
  • 16
  • 143
  • 224
  • Extending all within `.SettingsButton` would result in it getting the background also (which I think is not desired). Extending just the `:hover` would probably be a better alternate :) – Harry May 10 '15 at 05:17
  • 1
    @harry, yes i think you're right about that, but i understand the question asks for two times the background? For the same reason i also refer to the other question. – Bass Jobsen May 10 '15 at 06:25
  • Hmm, might be. I think we should leave it to OP to clarify. My understanding was that the same background needed to be applied for `.SettingsButton:hover .icon` and `.SettingsButton .icon:hover` only. – Harry May 10 '15 at 06:29