user1074170 user1074170 - 3 months ago 6
CSS Question

How can I create menu behavior using unnested markup?

I have some output html that needs to be styled as a menu.

<ul>
<li>
<a>All</a>
</li>
<li>
<a>
<span class="level0">Clothing</span>
</a>
</li>
<li>
<a>
<span class="level1 parent_0">Shirts</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_0">Tee</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_0">Polo</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_0">Jersey</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_0">Dress</span>
</a>
</li>
<li>
<a>
<span class="level1 parent_0">Hats</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_1">Beanie</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_1">Flexfit</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_1">Snapback</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_1">Strapback</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_1">Visor</span>
</a>
</li>
<li>
<a>
<span class="level0">Accessories</span>
</a>
</li>
<li>
<a>
<span class="level1 parent_2">Swag</span>
</a>
</li>
<li>
<a>
<span class="level2 parent_2">Drink Cozy</span>
</a>
</li>
</ul>


I can't change the markup except to add classes(or ids) to the spans based on a query which I have done. Now each span has the necessary information to target elements based on relationships but I can't target the elements using pseudo selectors like :hover to show or hide elements because of the "cascading" principle of css. That puts me in less familiar territory which is to use js or jQuery.

I've created the following fiddle with css classes applied. If you scroll to the bottom of the css you will see the selectors I've created to toggle the visibility of the targeted elements. The examples that I'm finding aren't very relevant to this case.

The Fiddle

How can I toggle the visibility of this html list's children based on their parent's hover state using only classes/ids?

Pat Pat
Answer

Ok, with the requirements being you cannot change the HTML hierarchy.. I believe I have come up with a solution for you. Although it is ugly as sin, it does work. Basically the way it works is if you hover inside a level 2 element, it will find the next level 3 elements until it hits a different level 2 element. Then it will add a .hovered class to those elements. This is not a perfect solution, but I think it actually works quite well. You can add more mouseout events to polish it, but this will get you started. https://jsfiddle.net/9pvbgy1j/5/

$('li.first').hover(function(){
	$(this).siblings('li.second').addClass('hovered');
}, function(e){
 if(!$(e.relatedTarget).is('span.level0')) {
  $(this).siblings('li.second').removeClass('hovered');
 }
})

$('li.second').hover(function(){
	$('li.third').removeClass('hovered');
	$(this).nextUntil('li.second','li.third').addClass('hovered');
}, function(e){
 if(!$(e.relatedTarget).is('span.level1')) {
  $(this).siblings('li.third').removeClass('hovered');
 }
})

$('li.third').hover(function(){
	$('li.fourth').removeClass('hovered');
	$(this).nextUntil('li.third').addClass('hovered');
}, function(e){
 if(!$(e.relatedTarget).is('span.level2')) {
  $(this).siblings('li.fourth').removeClass('hovered');
 }
})
.isotope-options {
  border: 1px solid #999;
  border-radius: 5px;
  margin: 0 auto;
  padding: 20px;
  width: 500px;
}

.isotope-options a,
.isotope-options a:link,
.isotope-options a:visited,
.isotope-options a:hover {
  color: #fff;
  text-decoration: none;
}

.isotope-options {
	margin: auto;
	padding: 10px;
	text-align: center;
}
.isotope-options li {
	display: inline;
}
.isotope-options li.first{
	background: #1E90FF;
	border-radius: 5px;
	display: inline-block;
	padding: 5px 10px;
	-moz-transition: background-color .3s;
	-o-transition: background-color .3s;
	-webkit-transition: background-color .3s;
	transition: background-color .3s;
	margin: 0;
}
.isotope-options span {
	font-size: 15px;
	font-style: unset;
	background: #1E90FF;
	border-radius: 5px;
	padding: 5px 10px;
	-moz-transition: background-color .3s;
	-o-transition: background-color .3s;
	-webkit-transition: background-color .3s;
	transition: background-color .3s;
}
.isotope-options .level1 {
	background: #657E97;
	width: 75%;
	margin:auto;
}
.isotope-options .level2 {
	background: #1B3855;
	width: 25%;
	margin:auto;
}

.isotope-options span:hover {
  background: #ADD8E6;
  color: #555;
}

/* Visibility Toggle Classes */

.level0 {
	display: block;
}
.level1.parent_0 {
	display: block;
}
.level2.parent_0 {
	display: block;
}
.level2.parent_1 {
	display: block;
}
.level1.parent_2 {
	display: block;
}
.level2.parent_2 {
	display: block;
}


li.second {
  display: block;
    height: 0px;
    overflow: hidden;
}

li.third {
  display: block;
    height: 0px;
        overflow: hidden;
}

li.fourth {
  display: block;
    height: 0px;
        overflow: hidden;
}

li.hovered {
  height: 1.75em;
}

li{
  transition: height .5s ease;
  transition-delay: .2s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <ul class="isotope-options clearfix" data-filter-group="unnamed_filter">
      <li class="first"><a href="#filter" class="filterbutton" data-filter="">All</a></li>
      <li class="second">
        <a href="#filter" class="filterbutton" data-filter=".clothing">
          <span class="level0">Clothing</span>
        </a>
      </li>
      <li class="third">
        <a href="#filter" class="filterbutton" data-filter=".shirts">
          <span class="level1 parent_0">Shirts</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".tee">
          <span class="level2 parent_0">Tee</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".polo">
          <span class="level2 parent_0">Polo</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".jersey">
          <span class="level2 parent_0">Jersey</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".dress">
          <span class="level2 parent_0">Dress</span>
        </a>
      </li>
      <li class="third">
        <a href="#filter" class="filterbutton" data-filter=".hats">
          <span class="level1 parent_0">Hats</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".visor">
          <span class="level2 parent_1">Beanie</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".strapback">
          <span class="level2 parent_1">Flexfit</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".snapback">
          <span class="level2 parent_1">Snapback</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".flexfit">
          <span class="level2 parent_1">Strapback</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".beanie">
          <span class="level2 parent_1">Visor</span>
        </a>
      </li>
      <li class="second">
        <a href="#filter" class="filterbutton" data-filter=".clothing">
          <span class="level0">Clothing</span>
        </a>
      </li>
      <li class="third">
        <a href="#filter" class="filterbutton" data-filter=".shirts">
          <span class="level1 parent_0">Shirts</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".tee">
          <span class="level2 parent_0">Tee</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".polo">
          <span class="level2 parent_0">Polo</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".jersey">
          <span class="level2 parent_0">Jersey</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".dress">
          <span class="level2 parent_0">Dress</span>
        </a>
      </li>
      <li class="third">
        <a href="#filter" class="filterbutton" data-filter=".hats">
          <span class="level1 parent_0">Hats</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".visor">
          <span class="level2 parent_1">Beanie</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".strapback">
          <span class="level2 parent_1">Flexfit</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".snapback">
          <span class="level2 parent_1">Snapback</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".flexfit">
          <span class="level2 parent_1">Strapback</span>
        </a>
      </li>
      <li class="fourth">
        <a href="#filter" class="filterbutton" data-filter=".beanie">
          <span class="level2 parent_1">Visor</span>
        </a>
      </li>
    </ul>

Comments