roydukkey
roydukkey

Reputation: 3288

Parent menu and child menu vertical separator (unique, advanced)

I've the following navigation at http://www.roydukkey.com. The navigation is designed to have vertical separators between the parent menu and it's child menu. If you look under the 'Contact' menu-item it looks the way it's designed, however have a look under 'Projects'. The are vertical separators shouldn't exist where there aren't child items against the menu.

How can the proper design be achieved through CSS alone?


This cannot currently be achieved through CSS.

Here is the solution I've chosen:

// Naivagation Vertical Separator Counter
$("#main > ul > li > ul .level-has-sub").each(function(){
    $(this).find("> ul > li")
        .slice(0, $(this).find("~ li").length + 1)
        .addClass("vertical-separator")
});

Them simply style those items for the vertical separator.

Upvotes: 1

Views: 1416

Answers (5)

Saram
Saram

Reputation: 1510

CSS selector can not refer to children elements, the only class (pseudo) i know :empty. In your case at parent level you need information about number of children. The solution is to provide this info at design time and encode it (e.g. in class attribute).

Based on you code, for projects node you need to add info as follows:

<li class="level-has-sub limit">...</li>
<li class="level-has-sub limit2">...</li>
<li class="level-has-sub limit">...</li>
<li class="level-has-sub">...</li>

And corresponding CSS:

#main li li.level-open~li:after {
content: "";
position: absolute;
top: 10px;
bottom: 10px;
right: -17px;
border-right: none;
z-index: 1;
}
// above is not necessary if you remove this selector from your css

/* main job */
#main li li.level-open:not([class*=limit])~li:after {
content: "";
position: absolute;
top: 10px;
bottom: 10px;
right: -17px;
border-right: 1px dotted #7f7f7f;
z-index: 1;
}

#main li li.level-open.limit2+li:after, 
#main li li.level-open.limit3+li:after, 
#main li li.level-open.limit4+li:after
{
content: "";
position: absolute;
top: 10px;
bottom: 10px;
right: -17px;
border-right: 1px dotted #7f7f7f;
z-index: 1;
}

#main li li.level-open.limit3+li+li:after,
#main li li.level-open.limit4+li+li:after {
content: "";
position: absolute;
top: 10px;
bottom: 10px;
right: -17px;
border-right: 1px dotted #7f7f7f;
z-index: 1;
}

#main li li.level-open.limit4+li+li+li:after {
content: "";
position: absolute;
top: 10px;
bottom: 10px;
right: -17px;
border-right: 1px dotted #7f7f7f;
z-index: 1;
}

As you can see, there is problem with multiple selectors like:

#main li li.level-open.limit2+li:after, 
#main li li.level-open.limit3+li:after, 
#main li li.level-open.limit4+li:after

You can workaround it by using coding by attribute substring, eg: limit1, limit11, limit111, and selectors [class*=limit1], [class*=limit11], [class*=limit111].

Note: I use substring selector [class*=limit] witch is little unpredictable ;) you can change it to pair: [class^="limit"], [class*=" limit"] for better control.

Hope it helps :)

Upvotes: 0

Aleks
Aleks

Reputation: 5330

The solutions lays somewhere else then you might expect.

You have missed with expectation that on "Contacts" menuis all working well. I have added a new element just to show that the "bug" is in design of the menu.

enter image description here

So the problem is in the design of the drop down menu. To solve this , take a look in your css and look for

#main li li.level-open:after, #main li li.level-open ~ li:after

And delete line:

border-right: 1px dotted #7F7F7F;

Now, in order to achieve adding dotted menu you have to do change a little your php code. You can't do that in CSS. At least to my little research I couldn't find.

Create a new class - for example .dotted-right-border , and in you code, create an algorithm to add that css class to every element that will be printed on the left side of li when there is li element on the left.

Update:

Ok, then. I usually don't like to say that something is impossible, but in this case, and to my opinion here is impossible to do the change with pure CSS. Even current creating of menu items is adding level-open into HTML tag, so it would need something that will be doing around that. There could be one more approach for this situation, for example:

  • To modify the class #main li li.level-open:after, #main li li.level-open ~ li:after

and change mentioned line:

border-right: 1px dotted #7F7F7F;

Into line:

border-right: 1px dotted transparent;

and then to set border-color: #7F7F7F for every new item under sub-menu, but then you couldn't tell apparent if the sub menu has it's match on the left side, so it would then show/not show dotted border. This is just an example approach. If I explained the approach good.

It all ends up into situation - How can you tell apart if the sub menu has a parent item on the left side in order to show dotted border? And that is why I think there is no pure CSS solution. But if someone knows better, then even better.

Upvotes: 0

user1467267
user1467267

Reputation:

You can't do this precisely, as CSS can't (yet) know the children count of another DOM-element.

CSS4 might be able to do this (ascend to the style's parent) in the near future: http://www.w3.org/TR/selectors4/#subject. This looks interesting too, although not pure CSS; http://demo.idered.pl/jQuery.cssParentSelector/. Maybe you can descend back down again after counting the children of the submenu, but that would be very complex to achieve with the low logical selection methods CSS has.

You could probably best do this in SASS, but then it's not native CSS anymore, and then you might as well just fallback to JavaScript.

Here's an example of how style a style of a parent itself based on how many children it "at least" has;

JSfiddle

HTML

<ul>
    <li>
        <ul class="submenu">
            <li>Contact 1.1</li>
            <li>Contact 1.2</li>
            <li>Contact 1.3</li>
            <li>Contact 1.4</li>
        </ul>
    </li>
</ul>

<ul>
    <li>
        <ul class="submenu">
            <li>Contact 2.1</li>
            <li>Contact 2.1</li>
            <li>Contact 2.3</li>
        </ul>
    </li>
</ul>

CSS

li {
    list-style: none;
    display: inline-block;
    border: 1px dotted red;
    padding: 15px;
}

.submenu li {
    display: block;
    padding: 15px;
    border: 0px;
    border-top: 1px dotted blue;
}

.submenu li:nth-child(1) {
    border: 0px;
}

/* This style only happens if the menu has 4 or more children li's */
.submenu li:first-child:nth-last-child(4),
.submenu li:first-child:nth-last-child(4) ~ li {
    border-left: 1px dotted blue;
}

Good luck!

Upvotes: 0

Mitesh Ashar
Mitesh Ashar

Reputation: 153

Your CSS is minified so I cannot give you line numbers.

In you custom.css file replace

#main li li.level-open:after, #main li li.level-open~li:after {rules}

with

#main li li.level-open:after {rules}

Upvotes: 0

Mooseman
Mooseman

Reputation: 18891

It's not possible with pure CSS. You would have to count the number of <li>s in the child <ul>. If you restructured the menu, you could put the separators in the child <ul> instead. Then you would either a) show the separator on the left of every <li> in the child <ul>, or use :first-child to only show it on the first.

Upvotes: 1

Related Questions