Reputation: 24661
I am using jQuery's isotope plugin to filter a list of entries, using the markup below for my listing of possible filters. All top-level list items are initially visible, and if I click a specific filter button then any sub-filters (if any) are then shown.
All of this works great. I am however running into a few issues getting the CSS to display the list correctly. The markup is:
<ul class="filter-list">
<li><button data-filter="*">show all</button></li>
<li>
<button data-filter=".filter1">Filter 1</button>
<ul class="sub-filter">
<li>
<button data-filter=".filter1.filtera">Filter 1,A</button>
<ul class="sub-filter">
<li><button data-filter=".filtera.filteri">Filter 1,A,i</button></li>
<li><button data-filter=".filtera.filterii">Filter 1,A,ii</button></li>
<li><button data-filter=".filtera.filteriii">Filter 1,A,iii</button></li>
</ul>
</li>
<li><button data-filter=".filter1.filterb">Filter 1,B</button></li>
<li>
<button data-filter=".filter1.filterc">Filter 1,C</button>
<ul class="sub-filter">
<li><button data-filter=".filterc.filteri">Filter 1,C,i</button></li>
<li><button data-filter=".filterc.filterii">Filter 1,C,ii</button></li>
</ul>
</li>
<li>
<button data-filter=".filter1.filterd">Filter 1,D</button>
<ul class="sub-filter">
<li><button data-filter=".filterd.filteri">Filter 1,D,i</button></li>
<li><button data-filter=".filterd.filterii">Filter 1,D,ii</button></li>
</ul>
</li>
</ul>
</li>
<li><button data-filter=".filter2">Filter 2</button></li>
<li><button data-filter=".filter3">Filter 3</button></li>
</ul>
The CSS that I have so far is:
ul.filter-list {
display:inline-block;
position: relative;
width: 100%;
margin:0;
padding:0;
}
ul.filter-list ul {
display: none;
position:relative;
}
.filter-list ul.active-filter {
display: block;
position:absolute;
top:50px;
left:0px;
}
ul.filter-list li {
list-style-type: none;
display: inline-block;
}
The expected output that I need is to have each 'level' of the list on a single line, followed by the next 'level' of filters if any for the one that is currently active. Initially, it should look like this:
show all Filter 1 Filter 2 Filter 3
If I click on Filter 1
, then the next level of buttons underneath that filter should show on the next line:
show all Filter 1 Filter 2 Filter 3
Filter 1,A Filter 1,B Filter 1,C Filter 1,D
If I were to then click on Filter 1,C
, the third level of buttons will need to display on the third line:
show all Filter 1 Filter 2 Filter 3
Filter 1,A Filter 1,B Filter 1,C Filter 1,D
Filter 1,C,i Filter 1,C,ii
One of the biggest issues I still am having is that, since the active lists are absolutely positioned, they are being displayed on top of content that is immediately following this list of filters rather than pushing it down. You can see this behavior in this fiddle. Also, when screen size is reduced, things are not flowing / breaking in the way I would expect them to (as well as having absolutely positioned buttons sitting on top of other absolutely positioned items).
Is there a way to accomplish this using just CSS (perhaps using relative positioning?), or am I going to have to add some inordinate amount of Javascript to what I have? Or should I just take out the nested lists in favor of having multiple 'flat' lists?
Upvotes: 1
Views: 593
Reputation: 9348
You can achieve must of this using just regular CSS
and jQuery/Javascript
to toggle the items visibility:
$(function() {
$('button').on('click', function() {
// The element to be toggled (show/hide).
var toToggle = $(this).next('.sub-filter');
// Go through its parents until the element
// with class sub-filter and find its
// children with this same class to hide
// them, excluding itself.
$(this).parents('.sub-filter').find('.sub-filter').not(toToggle).hide();
// Toggle the target.
toToggle.toggle();
});
});
* {
box-sizing: border-box;
}
ul.filter-list,
ul.filter-list li {
list-style-type: none;
margin: 0;
padding: 0;
}
ul.sub-filter {
/* Giving them the full width and
floating them you guarantee their
place in a new line. */
width: 100%;
float: left;
display: none;
/* Setting their padding to 0 will
keep them aligned to the line above
them. */
padding: 0;
}
ul.filter-list > li,
ul.sub-filter > li {
/* Setting their display to inline
will show them next to each other. */
display: inline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="filter-list">
<li>
<button data-filter="*">show all</button>
</li>
<li>
<button data-filter=".filter1">Filter 1</button>
<ul class="sub-filter">
<li>
<button data-filter=".filter1.filtera">Filter 1,A</button>
<ul class="sub-filter">
<li>
<button data-filter=".filtera.filteri">Filter 1,A,i</button>
</li>
<li>
<button data-filter=".filtera.filterii">Filter 1,A,ii</button>
</li>
<li>
<button data-filter=".filtera.filteriii">Filter 1,A,iii</button>
</li>
</ul>
</li>
<li>
<button data-filter=".filter1.filterb">Filter 1,B</button>
</li>
<li>
<button data-filter=".filter1.filterc">Filter 1,C</button>
<ul class="sub-filter">
<li>
<button data-filter=".filterc.filteri">Filter 1,C,i</button>
</li>
<li>
<button data-filter=".filterc.filterii">Filter 1,C,ii</button>
</li>
</ul>
</li>
<li>
<button data-filter=".filter1.filterd">Filter 1,D</button>
<ul class="sub-filter">
<li>
<button data-filter=".filterd.filteri">Filter 1,D,i</button>
</li>
<li>
<button data-filter=".filterd.filterii">Filter 1,D,ii</button>
</li>
</ul>
</li>
</ul>
</li>
<li>
<button data-filter=".filter2">Filter 2</button>
</li>
<li>
<button data-filter=".filter3">Filter 3</button>
</li>
</ul>
Upvotes: 1