I have found this menu and have integrated it into my local (wordpress) site.
Code pen Fork
Everything works as it should as far as the animation, ect.
However, when I add a link into the
I have tried both relative and absolute paths for the link as well. -- See the codepen link "start"-->"Menu 1"-->"Sub menu 1" -- as you hover over you can see I have added the link of http://www.google.com/ for a test, but when clicked it does not go to the site.
I appreciate any pointers - and sorry if it is simple.
Here is the full code: (Also contained on the code pen link)
HTML:
<div class="radmenu"><a href="#" class="show" >START</a>
<ul>
<li>
Menu 1
<ul>
<li>Sub Menu 1</li>
<li>Sub Menu 2</li>
<li>Sub Menu 3</li>
<li>Sub Menu 4</li>
<li>Sub Menu 5</li>
</ul>
</li>
<li>
Menu 2
<ul>
<li>Sub Menu 1</li>
<li>Sub Menu 2</li>
<li>Sub Menu 3</li>
<li>Sub Menu 4</li>
<li>Sub Menu 5</li>
</ul>
</li>
<li>
Menu 3
<ul>
<li>Sub Menu 1</li>
<li>Sub Menu 2</li>
<li>Sub Menu 3</li>
<li>Sub Menu 4</li>
<li>Sub Menu 5</li>
</ul>
</li>
<li>
Menu 4
<ul>
<li>Sub Menu 1</li>
<li>Sub Menu 2</li>
<li>Sub Menu 3</li>
<li>Sub Menu 4</li>
<li>Sub Menu 5</li>
</ul>
</li>
<li>
Menu 5
<ul>
<li>Sub Menu 1</li>
<li>Sub Menu 2</li>
<li>Sub Menu 3</li>
<li>Sub Menu 4</li>
<li>Sub Menu 5</li>
</ul>
</li>
</ul>
</div>
CSS:
#import "compass/css3";
$sub-menus : 5;
body {
background: url(http://www.scenicreflections.com/files/Hazy_Forest_Road_Wallpaper_qoek0.jpg)
}
.radmenu {
position: absolute;
display:flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
> a {
top: calc(50% - 60px);
left: calc(50% - 60px);
&.show {
display: flex !important;
}
}
li {
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
transition: all 1s ease;
}
a {
position: absolute;
width: 120px;
height: 120px;
background: rgba(white, 0.9);
text-align: center;
align-items: center;
justify-content: center;
border-radius: 120px;
display: none;
text-decoration: none;
color: #333;
transition: all 1s ease;
box-shadow: 0 0 15px #222;
font-family: "segoe ui";
font-weight: 200;
font-size: 16px;
}
.selected {
background: rgba(#333, 0.9);
display: flex;
top: calc(50% - 60px);
left: calc(50% - 60px);
color: #f1f1f1;
box-shadow: 0 0 10px #f1f1f1;
+ ul {
#for $i from 1 through $sub-menus {
> li:nth-child(#{$i}) {
$angle: 360deg / $sub-menus * $i;
-webkit-transform: rotate($angle) translateX(100px);
transform: rotate($angle) translateX(100px);
> a {
-webkit-transform: rotate(0 - $angle);
transform: rotate(0 - $angle);
}
}
}
> li > a {
display: flex
}
}
}
}
Javascript:
var buttons = document.querySelectorAll(".radmenu a");
for (var i=0, l=buttons.length; i<l; i++) {
var button = buttons[i];
button.onclick = setSelected;
}
function setSelected(e) {
if (this.classList.contains("selected")) {
this.classList.remove("selected");
if (!this.parentNode.classList.contains("radmenu")) {
this.parentNode.parentNode.parentNode.querySelector("a").classList.add("selected")
} else {
this.classList.add("show");
}
} else {
this.classList.add("selected");
if (!this.parentNode.classList.contains("radmenu")) {
this.parentNode.parentNode.parentNode.querySelector("a").classList.remove("selected")
} else {
this.classList.remove("show");
}
}
return false;
}
Just modify your javascript code to following,
function setSelected(e) {
if(this.getAttribute("href") == "#"){
if (this.classList.contains("selected")) {
this.classList.remove("selected");
if (!this.parentNode.classList.contains("radmenu")) {
this.parentNode.parentNode.parentNode.querySelector("a").classList.add("selected")
} else {
this.classList.add("show");
}
} else {
this.classList.add("selected");
if (!this.parentNode.classList.contains("radmenu")) {
this.parentNode.parentNode.parentNode.querySelector("a").classList.remove("selected")
} else {
this.classList.remove("show");
}
}
return false;
}
else{
return true;
}
}
Basically the return false; was preventing the page to perform the default action of going to the assigned href.
Related
I have three navigations in one page and I'm trying to show the active links for each nav. For some reason the third nav isn't working correctly. For example, if you click on "chapter 2" or "chapter 3" or "chapter 4", "chapter 1" stays active. I don't know if it's because "Chapter 1" and "sublink4" from the middle nav have the same url. I tried removing the active class of the third nav, but it's not working. Unfortunately the snipping isn't working as it is on my computer. I only used target="_blank" on the snippet, not only my local machine since you can't click on links on the snippet without restarting the snippet.Thanks
$(window).on('load', function () {
$('body').setActiveMenuItem();
$('body').setActiveMenuItem2();
$('body').setActiveMenuItem3();
});
$(document).ready(function () {
//first nav
$.fn.setActiveMenuItem2 = function () {
$.each($('.nav1').find('li'), function () {
$(this).toggleClass('active',
window.location.pathname.indexOf($(this).find('a').attr('href')) > -1);
});
}
//middle nav
$.fn.setActiveMenuItem3 = function () {
$.each($('.nav3').find('li'), function () {
$(this).toggleClass('active3',
window.location.pathname.indexOf($(this).find('a').attr('href')) > -1);
});
}
//third nav
$.fn.setActiveMenuItem = function () {
$.each($('.nav2').find('li'), function () {
$(this).removeClass('active2');
$(this).toggleClass('active2',
window.location.pathname.indexOf($(this).find('a').attr('href')) > -1);
});
}
});
li.active {
background-color: red;
}
li.active2 {
background-color: blue;
}
li.active {
background-color: yellow;
}
.nav1 ul, .nav3 ul {
display: flex;
justify-content: space-between;
}
nav {
margin-bottom: 50px;
}
.wrapper {
width: 400px;
margin: auto;
}
li {
list-style: none;
background-color: aliceblue;
padding: 10px;
}
li a {
padding: 10px;
}
li a:hover {
color: red;
background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<nav class="nav1">
<ul>
<li> Link 1 </li>
<li><a href="/link-2" target="_blank" >Link 2</a> </li>
<li>Link 3 </li>
<li>Link 4 </li>
</ul>
</nav>
<nav class="nav3">
<ul>
<li>Subink 1</li>
<li>Subink 2</li>
<li>Subink 3</li>
</ul>
</nav>
<nav class="nav2">
<ul>
<li>Chapter 1</li>
<li>Chapter 2</li>
<li>Chapter 3</li>
</ul>
</nav>
</div>
-> replace $ to j Query
->Either replace a latest jquery
Use preventDefault to let default event handler to open new link.
window.open() will let you open links in new tabs.
Note: This code won't work in sand-boxes.
Let me know if I'm missing something?
var links = document.querySelectorAll('a');
links.forEach((node) => {
node.addEventListener("click", (evt) => {
evt.stopPropagation();
evt.preventDefault();
evt.target.classList.add('active');
window.open(evt.target.href);
});
});
li.active {
background-color: red;
}
li.active2 {
background-color: blue;
}
li.active {
background-color: yellow;
}
.nav1 ul,
.nav3 ul {
display: flex;
justify-content: space-between;
}
nav {
margin-bottom: 50px;
}
.wrapper {
width: 400px;
margin: auto;
}
li {
list-style: none;
background-color: aliceblue;
padding: 10px;
}
li a {
padding: 10px;
}
li a:hover {
color: red;
background: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<nav class="nav1">
<ul>
<li> Link 1 </li>
<li>Link 2 </li>
<li>Link 3 </li>
<li>Link 4 </li>
</ul>
</nav>
<nav class="nav3">
<ul>
<li>Subink 1</li>
<li>Subink 2</li>
<li>Subink 3</li>
</ul>
</nav>
<nav class="nav2">
<ul>
<li>Chapter 1</li>
<li>Chapter 2</li>
<li>Chapter 3</li>
</ul>
</nav>
</div>
Can somebody tell me where my mistake was done? It's a dropdown menu but it doesn't do the transition thing. I played around with it several hours but cant find the bug.
var allHasChildren = document.querySelectorAll(".item-has-children a");
for (var x = 0; x < allHasChildren.length; x++) {
allHasChildren[x].onclick = function() {
// get the first submenu and toggle using classes
var subMenu = this.parentNode.getElementsByClassName("sub-menu")[0];
if (subMenu.classList.contains('selected')) {
subMenu.classList.remove("selected");
} else {
subMenu.classList.add("selected");
}
}
}
.sub-menu {
display: none;
}
.sub-menu.selected {
display: block;
transition: transform 0.2s;
}
<ul>
<li class="item-has-children">
December
<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>
<li>Sub Item Six</li>
</ul>
</li>
<li class="item-has-children">
November
<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>
<li>Sub Item Six</li>
</ul>
</li>
</ul>
Where is my mistake?
Thank you
You cannot set a transition on the display property as you can see in that question : Transitions on the display: property.
Instead you can play with the height, the visibility.
Transitioning display isn't possible, however, you can transition the opacity of the element. If you set the opacity to 0 when the section is hidden, and transition it to 1 when it is shown, you can get a fade in effect. To get other effects, you can toggle the max-height of the section as well. You also must change the visibility of the element to go it to behave as expected when hidden and shown:
var allHasChildren = document.querySelectorAll(".item-has-children a");
for (var x = 0; x < allHasChildren.length; x++) {
allHasChildren[x].onclick = function() {
// get the first submenu and toggle using classes
var subMenu = this.parentNode.getElementsByClassName("sub-menu")[0];
if (subMenu.classList.contains('selected')) {
subMenu.classList.remove("selected");
} else {
subMenu.classList.add("selected");
}
}
}
.sub-menu {
visibility: hidden;
opacity: 0;
max-height: 0;
transition: opacity 2.3s, max-height 0.6s ease-in;
-webkit-transition: opacity 2.3s, max-height 0.6s ease-in;
}
.sub-menu.selected {
visibility: visible;
opacity: 1;
max-height: 300px;
transition: opacity 2.3s, max-height 1.2s ease-out;
-webkit-transition: opacity 2.3s, max-height 1.2s ease-out;
}
<ul>
<li class="item-has-children">
December
<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>
<li>Sub Item Six</li>
</ul>
</li>
<li class="item-has-children">
November
<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>
<li>Sub Item Six</li>
</ul>
</li>
</ul>
You cannot transition display. However you can change the max-height and achieve a nice animation.
I have made a simple example on how to make it work
$("#myItem").on("click", function(){
if( $('.sub-menu').hasClass('reveal'))
{
$('.sub-menu').removeClass('reveal');
}
else {
$('.sub-menu').addClass('reveal');
$('.sub-menu').addClass('transition');
}
});
.sub-menu {
overflow:hidden;
display:block;
max-height:0;
}
.transition
{
transition:max-height 3.3s ease-out;
}
.reveal
{
max-height:200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li class="item-has-children">
December
<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>
<li>Sub Item Six</li>
</ul>
</li>
I have recently started designing a mobile website using media queries and browsing a few websites to see what they've done it seems accordion navigation menus are the way to go, scaling up to a normal horizontal navigation bar. I have browsed and browsed the internet looking for an accordion walkthrough but I can not seem to find one that explains it well enough.
A good example is the one from microsoft on their website. Here is my code so far:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
#topMenu {
height: 50px;
width: 100%;
background-color: #cde;
display: block;
}
nav {
width: 100%;
height: auto;
display: block;
margin: 0;
padding: 0;
}
nav a {
text-decoration: none;
padding-left: 40px;
}
nav ul {
list-style: none;
display: block;
margin: 0;
padding: 0;
background-color: #ccc;
}
nav ul li {
display: block;
width: 100%;
padding: 20px 0px 20px 0px;
border-top: 2px solid #abc;
}
nav ul ul {
height: 0;
overflow: hidden;
padding-top: 0px;
}
nav ul ul li a {
padding-left: 100px;
}
</style>
</head>
<body>
<div id="topMenu"></div>
<nav>
<ul>
<li>Link</li>
<li>Link
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
<li>Link 7</li>
</ul>
</li>
<li>Link
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
<li>Link 7</li>
</ul>
</li>
<li>Link
<ul>
<li>Link 1</li>
<li>Link 2</li>
</ul>
</li>
<li>Link</li>
<li>Link</li>
<li>Link</li>
</ul>
</nav>
</html>
These navigation bars have submenus [nav ul ul] that slide out when nav ul li is clicked. I was hoping somebody could point me in the right direction as to how I go about making a slide down sub menu on click, or help me with the code.
I thought there may have been a basic one people could start using and edit to customise themselves.
Thanks for any help.
There is no need for Javascript - you may use a Checkbox instead.
Check out: http://codepen.io/TimPietrusky/pen/CLIsl
If you still want to do it with Javascript go for something like this:
// asuming, that nav-items that should trigger slidedown will have "#" as href
// while actual nav-items will have URLs
$('nav li a[href="#"]').on('click', function (e) {
// prevent Click from redirecting
e.preventDefault();
// get the next ul after the li a clicked
if ($(this).hasClass('visible')) {
$(this).next('ul').slideUp(200).removeClass("visible");
} $(this).next('ul').slideDown(200).addClass("visible");
});
CSS animation for height form 0 to auto wont work. See: How can I transition height: 0; to height: auto; using CSS?
Check this out
https://jsfiddle.net/nqamazgz/3/
Unfortunately CSS does not have any click events, instead you will need to use JavaScript and/or jQuery. I used jQuery
All i did was add a class hide-nav to your nav with display none. And a button to click of course.
And a bit of jQuery
$(document).ready(function() {
$('#topMenu-btn').on('click', function() {
$('nav').slideToggle();
});
});
Try something like this:
http://jsfiddle.net/kb668aag/
You'll need to modify the code a bit.
<div id="topMenu"></div>
<nav>
<ul>
<li>Link</li>
<li class="has_children">Link
<ul class="sub-menu">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
<li>Link 7</li>
</ul>
</li>
<li class="has_children">Link
<ul class="sub-menu">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
<li>Link 6</li>
<li>Link 7</li>
</ul>
</li>
<li class="has_children">Link
<ul class="sub-menu">
<li>Link 1</li>
<li>Link 2</li>
</ul>
</li>
<li>Link</li>
<li>Link</li>
<li>Link</li>
</ul>
</nav>
CSS
body {
padding: 0;
margin: 0;
}
#topMenu {
height: 50px;
width: 100%;
background-color: #cde;
display: block;
}
nav {
width: 100%;
height: auto;
display: block;
margin: 0;
padding: 0;
}
nav a {
text-decoration: none;
padding-left: 40px;
padding: 20px 40px;
display: block;
}
nav ul {
list-style: none;
display: block;
margin: 0;
padding: 0;
background-color: #ccc;
}
nav ul li {
display: block;
width: 100%;
border-top: 2px solid #abc;
}
nav ul ul {
overflow: hidden;
padding-top: 0px;
}
nav ul ul li a {
padding-left: 100px;
}
ul.sub-menu{
display: none;
}
.has_children > a{
color: #ddd;
}
JS:
var $menu_with_children = $('.has_children > a');
$menu_with_children.on('click', function(e){
e.preventDefault();
var $this = $(this);
if (!$this.parent().find('> .sub-menu').hasClass('visible')) {
$this.parent().find('> .sub-menu').addClass('visible').slideDown('slow');
} else{
$this.parent().find('> .sub-menu').removeClass('visible').slideUp('slow');
}
});
Microsoft suggests using aria-haspop="true" to simulate hover on touch-enabled devices.
This is also the correct use in the W3 roles model spec.
Without including aria-haspop="true" I am unable to keep a submenu open when I click, and when I hold down a click it will fire a "right-click".
Codepen Example
HTML
<ul class="menu">
<li aria-haspopup="false">
aria-haspopup="false"
<ul class="sub-menu">
<li>Sub Menu Item 1</li>
<li>Sub Menu Item 2</li>
<li>Sub Menu Item 3</li>
</ul>
</li>
<li>
Menu Item 2
</li>
<li aria-haspopup="true">
aria-haspop="true"
<ul class="sub-menu">
<li>Sub Menu Item 1</li>
<li>Sub Menu Item 2</li>
<li>Sub Menu Item 3</li>
</ul>
</li>
</ul>
CSS
.menu > li {
display: inline-block;
position: relative;
background: #1abc9c;
}
.menu > li > a {
padding: 20px;
background: #1abc9c;
display: inline;
float: left;
}
.menu > li:hover .sub-menu {
display: block;
position: absolute;
background: #1abc9c;
top: 50px;
left: 0;
}
.menu .sub-menu {
display: none;
}
.menu .sub-menu li {
padding: 20px;
width: 140px;
}
Let's try to make the web a less accessible place. Is there any way to have the sub-menu work just as well without adding aria tags on a windows surface device? Preferably using only CSS. Javascript would be acceptable but less than ideal.
In the same Microsoft guide you linked, they recommend using the onclick event to show content.
The best practice is to not use hover to hide content that a user can interact with. Instead, consider using the onclick event to toggle the visibility.
The challenge, of course, is that your menu items are also links, and clicking on a link is likely to take you to another page. Only if they really are dead anchors that go nowhere (as in your example code) is it safe to use their onclick events to show or hide the submenus.
Here's some example code that uses onclick to show the submenus instead of using CSS :hover. Note that my example directly assigns the handlers for the sake of brevity, but better practice would be to use the addEventListener() method.
var parentMenuItems = document.querySelectorAll(".menu > li");
var len = parentMenuItems.length;
while (len--) {
parentMenuItems[len].onclick = showSubMenu;
parentMenuItems[len].onmouseenter = showSubMenu;
parentMenuItems[len].onmouseleave = hideSubMenu;
}
function showSubMenu() {
this.querySelector(".sub-menu").style.display = "block";
}
function hideSubMenu() {
this.querySelector(".sub-menu").style.display = "none";
}
.menu > li {
display: inline-block;
position: relative;
background: #1abc9c;
}
.menu > li > a {
padding: 20px;
background: #1abc9c;
display: inline;
float: left;
}
.menu > li .sub-menu {
position: absolute;
background: #1abc9c;
top: 50px;
left: 0;
}
.menu .sub-menu {
display: none;
}
.menu .sub-menu li {
padding: 20px;
width: 140px;
}
<ul class="menu">
<li aria-haspopup="false">
aria-haspopup="false"
<ul class="sub-menu">
<li>Sub Menu Item 1</li>
<li>Sub Menu Item 2</li>
<li>Sub Menu Item 3</li>
</ul>
</li>
<li aria-haspopup="true">
aria-haspop="true"
<ul class="sub-menu">
<li>Sub Menu Item 1</li>
<li>Sub Menu Item 2</li>
<li>Sub Menu Item 3</li>
</ul>
</li>
</ul>
I have a menu-submenu-subsubmenu construction in HTML like this:
<menu>
<li>Item 1</li>
<li><ul>
<li>Subitem 1</li>
<li>Subitem 2</li>
<li><ul>
<li>Sub-subitem 1</li>
<li>Sub-subitem 2</li>
<li>Sub-subitem 3</li>
</ul>
Subitem 3</li>
<li>Subitem 4</li>
</ul>
Item 2
</li>
<li>Item 3</li>
<li>Item 4</li>
...using whit this css formating:
menu {
display: block;
width: 200px;
}
/* hide subitems */
menu li ul,
menu li ul li ul {
display: none;
position: absolute;
}
/* set up positions */
menu li ul {
left: 200px;
width: 200px;
}
menu li ul li ul {
left: 400px;
width: 200px;
}
I use this jQuery code:
$(function() {
/* hide all submenu */
$('menu').find('ul').hide();
/* show submenu on mouseenter */
$('menu li a').mouseenter(function() {
$(this).parent().children('ul').show();
}).mouseleave(function() {
$(this).parent().children('ul').hide();
});
});
How can I detect mouse is leaving the element to their child? Or how can I get the child element to stay if it's necessary?
Change your code to be like this:
$(function() {
/* hide all submenu */
$('menu').find('ul').hide();
/* show submenu on mouseenter */
// here, just select the direct child
$('menu').find('li > a, li > ul').mouseenter(function() {
var time = new Date().getTime();
$(this).parent().find('ul').show().data('showing-time', time);
}).mouseleave(function() {
var leaveTime = new Date().getTime();
var $this = $(this);
window.setTimeout(function () {
var $ul = $this.parent().find('ul');
var beginTime = $ul.data('showing-time') || 0;
if (leaveTime > beginTime) {
$this.parent().find('ul').hide().data('showing-time', 0);
}
}, 100);
});
});
Hope this helps.
update
Code updated.
I suggest just put the sub menus next to the parent menu item(here, means li > a element) to get a better result.
Here's how I would go about it. You don't need javascript at all, at least not for simple hiding/showing. But, if you want to add delays, I would strongly suggest using jquery only to add/remove appropriate css classes with a settimeout.
css:
.menu {
position: relative;
display: inline-block;
}
.submenu {
display: none;
position: absolute;
left: 100%;
}
.menu li:hover > .submenu, .submenu.show {
display: inline-block;
}
html:
<ul class="menu">
<li>Item 1</li>
<li><ul class="submenu">
<li>Subitem 1</li>
<li>Subitem 2</li>
<li><ul class="submenu">
<li>Sub-subitem 1</li>
<li>Sub-subitem 2</li>
<li>Sub-subitem 3</li>
</ul>
Subitem 3</li>
<li>Subitem 4</li>
</ul>
Item 2
</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
js:
$('body').on('mouseleave','.submenu', function(e) {
var jTarget = $(e.currentTarget).addClass('show');
setTimeout(function() {
jTarget.removeClass('show');
}, 500);
})
Check out this jsfiddle with the js delay:
http://jsfiddle.net/LxL4N/1/