Telling LESS CSS how to behave with .active li
Asked Answered
T

2

9

I'm trying to make a menu which has 6 buttons and each of them has its own background color and hover background color. Now, I don't want the background color to show when hover if the link's parent li has an .active class. This is what I tried to do:

//I'm making li and li.active links to have the same normal and hover state bg color and then...
li, li.active{
    &:first-child{
        a, a:hover{
            background: @1-n;
        }
        + li{
            a, a:hover{
                background: @2-n;
            }
            + li{
                a, a:hover{
                    background: @3-n;
                }
                + li{
                    a, a:hover{
                        background: @4-n;
                    }
                    + li{
                        a, a:hover{
                            background: @5-n;
                        }
                        + li{
                            a, a:hover{
                                background: @6-n;
                            }
                        }
                    }
                }
            }
        }
    }
}
//..trying to overwrite the hovers only for normal li so I can't avoid applying them to li.active's ones
li{
    &:first-child{
        a:hover{
            background: @1-h;
        }
        + li{
            a:hover{
                background: @2-h;
            }
            + li{
                a:hover{
                    background: @3-h;
                }
                + li{
                    a:hover{
                        background: @4-h;
                    }
                    + li{
                        a:hover{
                            background: @5-h;
                        }
                        + li{
                            a:hover{
                                background: @6-h;
                            }
                        }
                    }
                }
            }
        }
    }
}

This is the CSS that is being generated:

li:first-child a, li.active:first-child a, li:first-child a:hover, li.active:first-child a:hover {
    background: @1-n;
}
li:first-child + li a, li.active:first-child + li a, li:first-child + li a:hover, li.active:first-child + li a:hover {
    background: @2-n;
}
li:first-child + li + li a, li.active:first-child + li + li a, li:first-child + li + li a:hover, li.active:first-child + li + li a:hover {
    background: @3-n;
}
li:first-child + li + li + li a, li.active:first-child + li + li + li a, li:first-child + li + li + li a:hover, li.active:first-child + li + li + li a:hover {
    background: @4-n;
}
li:first-child + li + li + li + li a, li.active:first-child + li + li + li + li a, li:first-child + li + li + li + li a:hover, li.active:first-child + li + li + li + li a:hover {
    background: @5-n;
}
li:first-child + li + li + li + li + li a, li.active:first-child + li + li + li + li + li a, li:first-child + li + li + li + li + li a:hover, li.active:first-child + li + li + li + li + li a:hover {
    background: @6-n;
}
li:first-child a:hover {
    background: @1-h;
}
li:first-child + li a:hover {
    background: @2-h;
}
li:first-child + li + li a:hover {
    background: @3-h;
}
li:first-child + li + li + li a:hover {
    background: @4-h;
}
li:first-child + li + li + li + li a:hover {
    background: @5-h;
}
li:first-child + li + li + li + li + li a:hover {
    background: @6-h;
}

I apologize if I messed up with my english, I hope I made myself clear!

Thanks!!!!

Tull answered 1/3, 2013 at 5:12 Comment(2)
:not(), although that's not LESS-specific, nor does it work everywhere (IE9+). Or you could just split it out into two statements.Latency
have you tried using jquery for active stateHubblebubble
P
2

Updated Answer for Many Levels

This utilizes a variation of option 2 below in my original answer, which means LESS 1.3.1+ needs to be the version used. This actually ends up more readable in this case (in my opinion) because of the use of the variables. I've used just numbers (1) and then a number with "h" (1h) to represent the base background and the desired hover state background respectively.

LESS

ul {
    li {
        @first: ~':first-child';
        @withActive: ~'.active';
        @noHover: ~'a';
        @withHover: ~'a:hover';
        @level2: ~'+ li';
        @level3: ~'+ li + li'; 
        @level4: ~'+ li + li + li'; 
        @level5: ~'+ li + li + li + li';
        @level6: ~'+ li + li + li + li + li';    
        &@{first}, 
        &@{withActive}@{first} {
           @{noHover}, @{withHover} {
             background: 1;
           }
        }      
        &@{first} { 
            @{level2}, 
            @{level2}@{withActive} {
              @{noHover}, @{withHover} {
                background: 2;
              }
            }
            @{level3}, 
            @{level3}@{withActive} {
              @{noHover}, @{withHover} {
                background: 3;
              }
            }
            @{level4}, 
            @{level4}@{withActive} {
              @{noHover}, @{withHover} {
                background: 4;
              }
            }
            @{level5}, 
            @{level5}@{withActive} {
              @{noHover}, @{withHover} {
                 background: 5;
              }
            }
            @{level6}, 
            @{level6}@{withActive} {
              @{noHover}, @{withHover} {
                 background: 6;
              }
            }      
            @{withHover} { background: 1h;}
            @{level2} @{withHover} { background: 2h;}
            @{level3} @{withHover} { background: 3h;}
            @{level4} @{withHover} { background: 4h;}
            @{level5} @{withHover} { background: 5h;}
            @{level6} @{withHover} { background: 6h;}
        }
    }
}

CSS Output

ul li:first-child a,
ul li.active:first-child a,
ul li:first-child a:hover, /* <-- Over written */
ul li.active:first-child a:hover {
  background: 1;
}
ul li:first-child + li a,
ul li:first-child + li.active a,
ul li:first-child + li a:hover, /* <-- Over written */
ul li:first-child + li.active a:hover {
  background: 2;
}
ul li:first-child + li + li a,
ul li:first-child + li + li.active a,
ul li:first-child + li + li a:hover, /* <-- Over written */
ul li:first-child + li + li.active a:hover {
  background: 3;
}
ul li:first-child + li + li + li a,
ul li:first-child + li + li + li.active a,
ul li:first-child + li + li + li a:hover, /* <-- Over written */
ul li:first-child + li + li + li.active a:hover {
  background: 4;
}
ul li:first-child + li + li + li + li a,
ul li:first-child + li + li + li + li.active a,
ul li:first-child + li + li + li + li a:hover, /* <-- Over written */
ul li:first-child + li + li + li + li.active a:hover {
  background: 5;
}
ul li:first-child + li + li + li + li + li a,
ul li:first-child + li + li + li + li + li.active a,
ul li:first-child + li + li + li + li + li a:hover, /* <-- Over written */
ul li:first-child + li + li + li + li + li.active a:hover {
  background: 6;
}

/* These over write the third lines of the above output due to the css cascade */
ul li:first-child a:hover {
  background: 1h;
}
ul li:first-child + li a:hover {
  background: 2h;
}
ul li:first-child + li + li a:hover {
  background: 3h;
}
ul li:first-child + li + li + li a:hover {
  background: 4h;
}
ul li:first-child + li + li + li + li a:hover {
  background: 5h;
}
ul li:first-child + li + li + li + li + li a:hover {
  background: 6h;
}

Original Answer Before Mentioning All the Levels

I've cut the code below to just the issue you relate. This can be adapted for the + li code.

Option 1 (very readable)

This (1) keeps the color definition in one place, and (2) groups the two via the comma, but (3) it repeats much selector code, though (4) it is very readable:

ul{
    li{
        &:first-child a, 
        &.active:first-child a:hover {
          background: red;         
        }
        &:first-child a:hover {
          background: blue;
        }
    }
}

Option 2 (code selector once)

This has advantages (1) and (2) from option 1, and overcomes issue (3) by utilizing dynamic selector building with variables (needs LESS 1.3.1+) to make the selector code only input once, however, it could be a little less obvious what is going to produce, and so loses advantage (4) from option 1.

ul {
    li {
        @noActive: ~':first-child a';
        @withActive: ~'.active@{noActive}';
        &@{noActive}, 
        &@{withActive}:hover {
             background: red;
        }
        &@{noActive}{ 
           &:hover { background: blue;}
        }
   }
}

CSS Output for Both

ul li:first-child a,
ul li.active:first-child a:hover {
  background: red;
}
ul li:first-child a:hover {
  background: blue;
}
Palsgrave answered 1/3, 2013 at 15:13 Comment(1)
that worked perfectly, great idea and very simple to follow, thank you very much Scott!Tull
P
1

In order to use pseudo-classes (:hover, etc) in less, you have to use the & operator, also you have the order of some of your pseudo-classes mixed up. If I'm understanding what you're trying to do, it should be something like this:

ul {
  li,
  li.active {
    &:first-child {
      a {
        background: red;

        &:hover {
          background: blue;
        }
      }

      +li {
        a {
          background: green;

          &:hover {
            background: yellow;
          }
        }
      }
    }
  }
}

Hopefully that helps; if it doesn't work, post the CSS that was generated from your LESS file in addition to the CSS that you desire as output so we can take a look.

Piapiacenza answered 1/3, 2013 at 6:6 Comment(1)
The problem is that I've got 6 <a> buttons, and each one has its own bg color and bg hover color but the hover color should't display if the button's parent li has an .active class. I edited the main post with the actual code I'm using and the CSS that is being generated. Thanks!Tull

© 2022 - 2024 — McMap. All rights reserved.