Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternate colors based on depth with CSS

Tags:

html

css

Problem:

I'm making a nav CSS module. I'm wanting submenus to have a different background color than their parent menu. However, if there is a submenu within a submenu, I need that submenu to have the same background color as it's parent's parent. I know I could do this fairly verbosely if I set a limit on the number of submenus that would be allowed but I would prefer the option to have as many nested menus as needed and have them colored appropriately. Is there some CSS trickery that can do this or am I relegated to JS for this?

I've looked into :nth-child and :nth-of-type but these only apply to sibling elements within a parent node as far as I know.

Code:

ul.nav {
  list-style: none;
}

ul.nav.dropdown {
  height: 0;
  overflow: hidden;
}

ul.nav.dropdown.show {
  height: auto;
}

ul.nav li {
  background-color: #44499f;
}

ul.nav ul li {
  background-color: #b6ff00;
}
<ul class="nav">
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li>
    <a class="dropdown-toggle">Test dropdown</a>
    <ul class="nav dropdown">
      <li><a>Test link</a></li>
      <li><a>Test link</a></li>
      <li><a>Test link</a></li>
      <li>
        <a class="dropdown-toggle">Test dropdown</a>
        <ul class="nav dropdown">
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
like image 797
Tyler Sells Avatar asked Mar 03 '23 10:03

Tyler Sells


2 Answers

Here is an idea based on my previous answer where I will rely on a recursive behavior of CSS variables and gradient coloration. The trick is to increment the variable on each level and at the same time move the background and we will alternate between both colors:

:root {
 --x:0;
}

ul.nav {
  list-style: none;
  position: relative;
  border:1px solid;
  background:
    linear-gradient(yellow 50%,pink 0) 0 calc(var(--x)*100%)/100% 200%;
  --y: calc(var(--x) + 1);
}

ul.nav li {
  --x: calc(var(--y));
}
<ul class="nav">
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li>
    <a class="dropdown-toggle">Test dropdown</a>
    <ul class="nav dropdown">
      <li>
        <a class="dropdown-toggle">Test dropdown</a>
        <ul class="nav dropdown">
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
          <li>
            <a class="dropdown-toggle">Test dropdown</a>
            <ul class="nav dropdown">
              <li><a>Test link</a></li>
              <li><a>Test link</a></li>
              <li><a>Test link</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a>Test link</a></li>
      <li><a>Test link</a></li>
      <li>
        <a class="dropdown-toggle">Test dropdown</a>
        <ul class="nav dropdown">
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

You can also do with 3 colors

:root {
 --x:0;
}

ul.nav {
  list-style: none;
  position: relative;
  border:1px solid;
  background:
    linear-gradient(lightblue 33.33%,yellow 33.33% 66.66%,pink 0) 0 calc(var(--x)*100%)/100% 300%;
  --y: calc(var(--x) + 1);
}

ul.nav li {
  --x: calc(var(--y));
}
<ul class="nav">
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li><a>Test link</a></li>
  <li>
    <a class="dropdown-toggle">Test dropdown</a>
    <ul class="nav dropdown">
      <li>
        <a class="dropdown-toggle">Test dropdown</a>
        <ul class="nav dropdown">
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
          <li>
            <a class="dropdown-toggle">Test dropdown</a>
            <ul class="nav dropdown">
              <li><a>Test link</a></li>
              <li><a>Test link</a></li>
              <li><a>Test link</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a>Test link</a></li>
      <li><a>Test link</a></li>
      <li>
        <a class="dropdown-toggle">Test dropdown</a>
        <ul class="nav dropdown">
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
          <li><a>Test link</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

You can easily increase to any number of colors. Simply make the background size to be n*100% with n number of colors and split the color inside the gradient so each one will have the same proportion 100%/n


Related question to understand the calculation behind the background values:

Using percentage values with background-position on a linear gradient

like image 164
Temani Afif Avatar answered May 01 '23 23:05

Temani Afif


Though my answer is very obvious I've used classnames,

          .oddNav{
            background: red;
          }
          .evenNav{
            background: blue;
          }
        <ul class="nav1 oddNav">
          <li>firstlist</li>
          <li>
            <ul class="nav2 evenNav">
              <li>SecondList</li>
              <li>
                <ul class="nav3 oddNav">
                  <li>ThirdList</li>
                  <li>
                    <ul class="nav4 evenNav">
                      <li>FourthList</li>
                    </ul>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
like image 30
Ankit Avatar answered May 01 '23 23:05

Ankit