Unwanted space and arrow in accordion menu - javascript

I am creating a vertical accordion menu. Here is code what I had done so far. Two problems I am facing.
There is unwanted space between border and menu. It is for all li elements i.e for menu and sub menu items also.
And arrow is showing for submenu also after having following code
#menunav li > a:only-child:before { content: '';}
I trying to put arrow image for menu that having sub menus. e.g. Item 1 is having sub menus so Item 1 should have arrow not its sub menus items. And also if I have Sub-Item 1 a of Item 1, sub menus like below:
<li>Item 1
<ul>
<li>Sub-Item 1 a
<ul>
<li>Sub-Item 1 aa</li>
<li>Sub-Item 1 bb</li>
<li>Sub-Item 1 cc</li>
</ul>
</li>
<li>Sub-Item 1 b</li>
<li>Sub-Item 1 c</li>
</ul>
</li>
Then Item 1 and Sub-Item 1 a will have arrow etc.
I am not able to remove that space and putting arrow for menu that having submenu.
Can someone please suggest what should I change in jquery and css so that I can get that properly working?

CSS
#menunav{padding:0}
since we need to clear the default style of the ul element

Set #menunav, ul into li padding to 0
#menunav, #menunav ul {
padding: 0;
}
Or just reset the padding:
* {
padding: 0
}
Demo
Update
If you want to remove submenu arrow, do this:
Example:
#menunav li ul li a:before {
background: none;
}
updated demo: http://jsfiddle.net/jpcb7w5y/10/

Try this.
CSS:
#menunav {
padding: 0px;
}
#menunav li ul {
padding: 0px;
}
I think your <ul> has its own padding. Hope this helps.
Edited:
DEMO
I you want that the arrows only appears to the main menu that have the sub menu, I have this quick solution for that. Why not try putting some class on the <a> for the main menu. Hope this works.
Instead of:
#menunav li a:before {
content: "";
display: block;
background: url("http://transparency.perkinswill.com/content/images/right-arrow.png") no-repeat;
width: 20px;
height: 20px;
float: left;
margin: 0 6px 0 0;
}
Why not:
#menunav .main:before {
content: "";
display: block;
background: url("http://transparency.perkinswill.com/content/images/right-arrow.png") no-repeat;
width: 20px;
height: 20px;
float: left;
margin: 0 6px 0 0;
}

Related

Coloring every second sub-layer in CSS

I'm working on a whiteboard app that included hierarchy.
So my question is: How can I color every second sub-layer in CSS (or if needed js)?
Example stying
ul {
width: 256px;
min-height: 64px;
padding: 16px 0 16px 16px;
background-color: blue;
}
/*FOLLOWING SHALL BE REPLACED BY AN SELECTOR OR JS-ALGORITHM*/
div>ul>ul,
div>ul>ul>ul>ul,
div>ul>ul>ul>ul>ul>ul,
div>ul>ul>ul>ul>ul>ul>ul>ul {
background-color: red;
}
<div>
<ul>
<ul>
<ul>
<ul>
<ul>
<ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</div>
What I aim to color are the divs in line 2 and 4 (and so on: 6, 8, 10,... if I would work with more sub-layers)
There is no CSS selector for that. You can however achieve it with a recursive function in JavaScript (jQuery):
colorList($('div > ul'));
function colorList($ul) {
$ul.css({'backgroundColor': 'red'});
var $nextElement = $ul.find('> ul > ul');
if($nextElement.length) {
colorList($nextElement);
}
}

All sub-menus are showing up on click

I want to only show the sub-menu that is the child of the clicked li and button when it is clicked. Currently the click and show and hide are working but the code below shows both the sub-menus on click, I want only the child sub-menu of the li button to show on click.
<ul id="menu-main-menu" class="nav-menu">
<li class="menu-item">Menu link
<button aria-expanded="false" class="dropdown-toggle"></button>
<ul class="sub-menu">
<li class="menu-item">link1</li>
<li class="menu-item">link1</li>
</ul>
</li>
<li class="menu-item">Menu link 2
<button aria-expanded="false" class="dropdown-toggle"></button>
<ul class="sub-menu">
<li class="menu-item">link1</li>
<li class="menu-item">link1</li>
</ul>
</li>
</ul>
<div class="site-content"></div>
jQuery:
jQuery(document).ready(function ($) {
$("#menu-main-menu").on('click', 'button', function (event) {
$('ul.sub-menu').appendTo('.site-content');
if($('ul.sub-menu:visible').length)
$('ul.sub-menu').hide();
else
$('ul.sub-menu').show();
});
});
CSS:
#menu-main-menu ul.sub-menu {
display: none;
}
ul.sub-menu {
display: none;
position: absolute;
z-index: 200000;
top: 0;
left: 1.5%;
right: 1.5%;
margin: 0 auto 0 auto;
padding: 20px;
list-style: none;
}
ul.sub-menu li {
width: 24%;
display: inline-block;
padding: 8px 9px;
text-align: center;
}
ul.sub-menu .toggled-on {
display: block;
}
.site-content {
display: block;
position: relative;
}
Solution: So the solution here was to not use appendTo(), as I had to put the element back where it came from when toggled off. The solution was to merely toggle the menu item using correct position: absolute CSS for the .sub-menu and $()on('click' to toggle it.
jQuery('#menu-main-menu').on('click', 'button', function(event) {
if($(this).closest("li.menu-item").children("ul.sub-menu").length > 0)
{
$(this).closest("li.menu-item").children("ul.sub-menu").slideToggle('fast');
return false;
}
});
See it working here: http://jsfiddle.net/abdqt6d9/
The problem is that you are writing incorrect selectors for your jquery:
$('ul.sub-menu')
That means it will grab all matching elements within the page.
What you need to do is grab the corresponding li. Within your click(), the $(this) becomes the button that is clicked. Using .parent() will give you the li element. From there, search for your corresponding sub-menus within the li_element:
var $li_element = $(this).parent()
var $sub_menu = $li_element.find(".sub-menu")
if ($li_element.find(".sub-menu:visible").length > 0) {
$sub_menu.hide()
} else {
$sub_menu.show()
}
The other problem is that perhaps your styling for your sub-menu is above the buttons. so once you show it, you can no longer press the button. So you need to restyle your sub-menus.
$("ul.sub-menu") will apply to all the sub-menus, so you need to change it to only look for the sub-menu within the buttons parent. You can do this using .closest (or just .parent()) and then .find
//closest("li") will find the closest parent that is an li
//find(".sub-menu") will find the sub-menu within
$(this).closest("li").find(".sub-menu").show();
If you your button is always going to be before the sub-menu you can slim it down to just .next(".sub-menu")
$(this).next(".sub-menu").show();

Trigger completely separate div based on hover of other div

Is it possible to trigger changes to CSS of an element that is completely unrelated to the hovered div?
I have a CSS hover effect on a dropdown menu, that I also want to trigger the opacity of a div right at the bottom of the page to create a background overlay effect.
This is the CSS I'm using:
#overlay {
background:rgba(0,0,0,0.5);
position:absolute;
top:120px;
left:0;
z-index:0;
height:120%;
width:100%;
visibility:hidden;
opacity:0;
}
#menu-main-menu li.menu-parent-item:hover ul.sub-menu,
#menu-main-menu li.menu-parent-item:hover #overlay {
visibility:visible;
opacity:1;
}
The hover of the sub menu works fine, but the div #overlay is right at the bottom of the page, and doesn't get called when it's hovered.
I've tried all kinds of alternatives such as :hover > #overlay, :hover + #overlay, but nothing seems to trigger it. I also can't seem to find a definitive answer to the question.
Is it possible?
Yes. You can load this style in a php file and then use jQuery to apply the css when your div has been hovered on.
No there is no way to select parent element in css and that means that you cannot move up in hierarchy.
<ul class="hover-parent">
<li></li>
</ul>
<div>Something here</div>
<div class="target"></div>
From this point :
.hover-parent li:hover you cannot go up (to ul or div).
Selectors which you tried to use are "next":
A>B - This will select only direct B children of A
A+B This will select B immediately preceded by A
Here you can find W3C documentation of CSS selector
http://www.w3.org/TR/CSS2/selector.html#adjacent-selectors
And demos:
http://code.tutsplus.com/tutorials/the-30-css-selectors-you-must-memorize--net-16048
Notice that it will be really confusing for user that different part off app/page is changing when he is hovering something else. Bad UX idea.
You're going to have to use JavaScript to do this.
Your posted selector #menu-main-menu li.menu-parent-item:hover #overlay is looking for #overlay somewhere inside of an ancestor element of li.menu-parent-item that is somewhere inside of an ancestor element with an id of #menu-main-menu.
Using the child selector > will not work as the overlay element is not a child of the list element you're hovering in your menu from what you have described and from comment responses.
As #Paulie_D has pointed out the two target elements, the element to be hovered and the overlay element, need to adjacent siblings to use the sibling selector +. From what you have described and the comment responses they are not adjacent siblings.
I have setup a basic example for you using jQuery. This example displays the overlay as long as you are hovering any element in the .main-menu element.
HTML
<ul class="main-menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three
<ul class="sub-menu">
<li>Sub Item One</li>
<li>Sub Item Two</li>
<li>Sub Item Three</li>
<li>Sub Item Four</li>
<li>Sub Item Five</li>
</ul>
</li>
</ul>
<main>
Content here.
</main>
<footer>
<div class="overlay">This is my overlay.</div>
</footer>
CSS
body {
margin: 25px auto;
width: 500px;
}
ul,
li {
margin: 0;
padding: 0;
}
main {
min-height: 300px;
}
footer,
.overlay {
height: 50px;
}
footer {
position: realative;
background-color: yellow;
}
.main-menu {
list-style: none;
height: 50px;
}
.main-menu > li {
float: left;
padding: 0 10px;
position: relative;
}
.main-menu > li:hover .sub-menu {
display: block;
}
.sub-menu {
display: none;
list-style: none;
position: absolute;
left: 10px;
width: 150px;
}
.overlay {
display: none;
text-align: center;
}
jQuery
$overlay = $('.overlay');
$('.main-menu > li').hover(
// when hovered
function() {
$overlay.css('display','block');
},
// when NOT hovered
function() {
$overlay.css('display','none');
}
);
jsFiddle: http://jsfiddle.net/ednf2pzq/
Edit
You could simplify the jQuery hover selector to .main-menu.
jQuery
$('.main-menu > li').hover(
// same code as before
);
jsFiddle: http://jsfiddle.net/ednf2pzq/1/

Why does jQuery fail to match ":not(#menu *)"

I've homerolled a Javascript based nav bar (I want it to be click, not hover for mobile friendliness). I've tried to make the HTML, CSS, and Javascript as simple as possible.
I put a listener on the body to close the menu bars if you click anywhere else on the website. I'm trying to filter the listener so that it does not fire if you click on any part of the menu bar. This is to prevent the dropdowns from rolling back up when you click on an element in the dropdown.
I expect the below matcher to ONLY match items that are descendants of the top level menu element. Any advice on why this isn't working would be much appreciated.
EDIT: I understand that you can use an arbitrary function to evaluate the bubble coming up and decide on whether or not you should act on it, but I'm more interested in why the below .on() selector is not working the way I expect.
$("body").on("click", ":not(#menu *)", function (e) {
$("#menu a").next().slideUp(DROP_DOWN_TIME);
});
http://jsfiddle.net/auKzt/16/
HTML
<body>
<div>HEADER</div>
<ul id="menu" class="cf">
<li>FooafsdasiuhfauhfuahsdfFooaf sdasiuhfauhfuahsdfFooafsdasiuhfauhfuahsdf
<ul>
<li>Subitem asdasdasd 1 sadad
</li>
<li>Subitem 2</li>
<li>Subitem 3</li>
</ul>
</li>
<li>Bar
<ul>
<li>Subitem 1</li>
<li>Subitem 2</li>
<li>Subitem 3</li>
</ul>
</li>
<li>Qux</li>
</ul>
<div>CONTENT</div>
<div>FOOTER</div>
</body>
JAVASCRIPT
$(document).ready(function () {
var DROP_DOWN_TIME = 200;
//Setup hidden dropdowns
$("#menu > li > a").next().toggle();
//Hide or unhide dropdowns onclick
$("#menu > li > a").click(function (e) {
$("#menu a").next().not($(e.target).next()).slideUp(DROP_DOWN_TIME);
$(e.target).next().slideToggle(DROP_DOWN_TIME);
e.stopPropagation();
});
$("body").on("click", ":not(#menu *)", function (e) {
$("#menu a").next().slideUp(DROP_DOWN_TIME);
});
});
CSS
#menu {
width: 900px;
padding: 0;
margin: 0;
}
/* Top level menu container */
#menu li {
background-color: aqua;
border: 1px solid black;
padding: 2px;
}
/* Top level menu items */
#menu > li {
display: inline-block;
float: left;
position: relative;
}
/* Submenu container */
#menu > li > ul {
position:absolute;
padding: 0;
margin: 0;
top: 100%;
left: -1px;
}
/* Submenu Items */
#menu > li > ul > li {
display: block;
float: none;
white-space: nowrap;
}
.cf:before, .cf:after {
content:" ";
/* 1 */
display: table;
/* 2 */
}
.cf:after {
clear: both;
}
It is failing because the click is being caught on the menu element. The content inside is being caught.
You need to also add the menu element
$("body").on("click", ":not(#menu, #menu *)", function (e) {
^^^^^^
Try this instead
$("body").on("click", function (e) {
if( e.taget.id !== 'menu' && !$(e.target).closest('#menu').length) {
$("#menu a").next().slideUp(DROP_DOWN_TIME);
}
});

moving horizontal background line when hovering other links in the same list

Would you mind to take a look at my jsfiddle?
As you can see, I putted a horizontal line below an active list item anchor.
I want the horizontal line to be at the bottom** of an anchor, just like a border-bottom when hovering, not at where my cursor stands. Can anybody help me out?
Thank you in advanced!
With Kind Regards,
Jonathan
The problem is because you were using an li element for the line that it was stopping the mouseover of the ul and reversing the animation. Instead use a div inside a containing element, with a lower z-index to stop it intercepting the mouseover event.
HTML:
<div id="container">
<ul>
<li>sub nav</li>
<li>sub nav</li>
<li>sub nav</li>
<li>sub nav</li>
</ul>
</div>
Amended javascript:
var animation = $('<div>').css({
'position': 'absolute',
'height': active.outerHeight()-1,
'width': active.outerWidth(),
'marginTop': (active.parent().index() * active.outerHeight()),
'borderBottom': '1px solid #000',
'z-index': -10
});
Example fiddle
Also, you need to make the border-bottom transparent on the ul li a elements for the line to show through them. You could use margin-bottom: 1px if you prefer.
Not sure exactly what you're trying to achieve, but if it's just getting a line under the active <li> element then this jsfiddle might do the job.
It uses your css to apply the underline, with some simplified jQuery:
$(document).ready(function() {
$('ul').mouseout(function(){
$(this).removeClass('active');
}).
$('ul > li').mouseenter(function(){
$(this).addClass('active');
});
});
The problem is that the animated li has a higher z-index than the other list elements. And you need to remove the white border from the links.
Take a look at this fiddle: http://jsfiddle.net/YFUsJ/12/
CSS:
ul li {
display: block;
position:relative;
z-index:1;
}
ul li a {
text-decoration: none;
height: 30px;
line-height: 30px;
display: block;
padding:5px;
color: #555;
font-size: 1.4em;
}

Categories