Dylan
Dylan

Reputation: 9363

CSS: nested list - how to highlight entire line?

I have a nested list like this :

   <ul class="tree">
     <li><div>Animals</div>
       <ul>
         <li><div>Birds</div>
           <ul>
             <li class="last"><div>Eagle</div></li>
           </ul>
         </li>
         <li><div>Mammals</div>
           <ul>
             <li><div>Elephant</div></li>
             <li class="last"><div>Cats</div>
               <ul>
                 <li><div>Lion</div></li>
                 <li class="last"><div>Tiger</div></li>
               </ul>
             </li>
           </ul>
         </li>
         <li class="last"><div>Reptiles</div>
           <ul>
             <li><div>Snake</li>
             <li class="last"><div>Turtle</div></li>
           </ul>
         </li>
       </ul>
     </li>
   </ul>

I'd like to style this so each level is indented, but I also wish to have each entire line highlighted when hovered. When I put a hover on DIV , the highlighting only starts from the left-position of the containing UL:

  ul.tree, ul.tree ul {
    list-style-type: none;
  }

  ul.tree li div:hover {
    background-color: red;
  }

Is there some way to achieve the effect I want, without defining multiple rules for li li, li li li, etc. ? There could be an infinite number of levels of nesting, so I find it quite ugly to define all these different rules.

Or is there a way to calculate the level of nesting dynamically (in CSS?), so I could remove the padding of UL and instead put the right amount of padding inside each DIV ?

UPDATE:

added a fiddle that shows what I want: http://jsfiddle.net/za3db/

You can see it's only indented on the second level, because I did not define the rule for the third, or fourth...

Upvotes: 3

Views: 2123

Answers (3)

Hayko Koryun
Hayko Koryun

Reputation: 1244

I know this answer is a tad late, however I was working on a tree recently and had the exact same thought and found a solution by studying the way several products tackle it. The below snippet illustrates a possible solution by placing a fill div for each item in the tree which has a large negative margin which allows it to cover the whole line. It's a very simple CSS only solution.

Hopefully it will help you and others who come across this question + answer.

.fill {
  display: none;
  margin-left: -10000px;
  position: absolute;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  z-index: -1;
}

.title {
  position: relative;
}

.title:hover .fill {
  display: block;
  background-color: #eee;
}
<ul class="tree">
  <li>
    <div class="title">
      <div class="fill"></div>
      Animals
    </div>
    <ul>
      <li>
        <div class="title">
          <div class="fill"></div>
          Birds
        </div>
        <ul>
          <li class="last">
            <div class="title">
              <div class="fill"></div>
              Eagle
            </div>
          </li>
        </ul>
      </li>
      <li>
        <div class="title">
          <div class="fill"></div>
          Mammals
        </div>
        <ul>
          <li>
            <div class="title">
              <div class="fill"></div>
              Elephant
            </div>
          </li>
          <li class="last">
            <div class="title">
              <div class="fill"></div>
              Cats
            </div>
            <ul>
              <li>
                <div class="title">
                  <div class="fill"></div>
                  Lion
                </div>
              </li>
              <li class="last">
                <div class="title">
                  <div class="fill"></div>
                  Tiger
                </div>
              </li>
            </ul>
          </li>
        </ul>
      </li>
      <li class="last">
        <div class="title">
          <div class="fill"></div>
          Reptiles
        </div>
        <ul>
          <li>
            <div class="title">
              <div class="fill"></div>
              Snake
            </div>
          </li>
          <li class="last">
            <div class="title">
              <div class="fill"></div>
              Turtle
            </div>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

Upvotes: 1

darthmaim
darthmaim

Reputation: 5148

This kinda does was you want: http://jsfiddle.net/za3db/4/

It is placing an absolute positioned (left:0; right:0) pseudo-element under (z-index:-1) each of your divs. But this construct has 2 downsides:

  • It only works when you know the height of the div (in my example always 1.3em = line-height)
  • It wont highlight when you hover over the indent, because the div still doesnt start at the left.

So the best solution might still be javascript or just writing down all those li li, li li li, ... rules.


Edit: I played a little more with it and came up with a new version using hidden floated counter()-pseudo-elements for the indent: http://jsfiddle.net/za3db/5/.

Upvotes: 0

Martin
Martin

Reputation: 1226

I haven't been able to do it with CSS, but it can be done with a little bit of javascript (jQuery).

$(".tree div").each(function()
{
    var padding = $(this).parents("ol, ul").length * 20 + "px";

    $(this).css("padding-left", padding);
});

See this jsFiddle

Upvotes: 0

Related Questions