Adjacent sibling selector element.querySelector("+element") is invalid - javascript

This simple code will work:
<!DOCTYPE html>
<html>
<body>
<br>
<div>
Link 1
Link 2
Link 3
Link 4
</div>
Link 1 <span>color me plz!</span>
<br><br>
<div>
Link 1
Link 2
Link 3
Link 4
</div>
Link 1 <span>color me plz!</span>
Link 2 <span>color me plz!</span>
<script>
testing = document.querySelectorAll("div + a");
for (let i = 0; i < testing.length; i++){
testing[i].addEventListener("mouseenter", function(){
const x = testing[i];
x.style.backgroundColor = "cyan";
x.querySelector("span").style.backgroundColor = "pink";
});
}
</script>
</body>
</html>
But my real problem is this:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style-test.css">
</head>
<body>
<nav>
<div>
Menu A.1
Menu A.2
</div>
<div class="right">
<div>
Menu B.1
<ul>
<li>B.1 Sub 1</li>
<li>B.1 Sub 2</li>
</ul>
</div>
<div>
Menu B.2
<ul>
<li>B.2 Sub 1</li>
<li>B.2 Sub 2</li>
</ul>
</div>
<div>
Menu B.3
<ul>
<li>B.3 Sub 1 Test Longer Text</li>
<li>B.3 Sub 2</li>
</ul>
</div>
<div>
Menu B.4
<ul>
<li>B.4 Sub 1</li>
<li>B.4 Sub 2</li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px"></div>
<script>
const menu = document.querySelectorAll("nav div > a");
console.log("Get all menu:");
console.log(menu);
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
console.log("mouseEnter");
console.log("menu[i].addEventListener:");
console.log(menu[i]);
//console.log(menu[i].querySelector("+ ul"));
const subMenu = menu[i].querySelector(` + ul`);
/* ^^^ The problem is here above ^^^ --- Everything stops here */
console.log("OK! 'querySelector' is valid"); //<-- this won't display...
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block") /*Corrected*/
if(subMenu.style.display === "block")
{
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX - 20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include padding?*/
// /*or just*/ subMenu.style.right = "0px";
console.log("When here successfully!");
}
else{
console.log("Failed...");
}
})
}
</script>
</body>
</html>
css:
body{
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a{
color: #cfc;
}
nav, nav div > a, nav div{
float: left;
}
nav{
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div{
margin: 0em 0.2em;
}
nav div:first-child{
margin-left: 0;
}
nav div div{
position: relative;
margin: 0;
}
nav a{
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover{
color: #fff;
background: #f90;
}
nav div > a + ul{
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover > a + ul{
display: block;
}
.right{
float: right;
}
I just want to get the sibling of <a> just next to it, the <ul> after <a>, which is a + ul in css
<div>
Menu B.1
<ul>
<li>B.1 Sub 1</li>
<li>B.1 Sub 2</li>
</ul>
</div>
Focus here:
<script>
const menu = document.querySelectorAll("nav div > a");
for (let i = 0; i < menu.length; i++) {
menu[i].addEventListener("mouseenter", function(){
//Problem is here...
const subMenu = menu[i].querySelector(" + ul");
/*Corrected*/
//if(window.getComputedStyle(subMenu).getPropertyValue("display") === "block")
if(subMenu != null && subMenu.style.display === "block")
{
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
if(posX > 0)
subMenu.style.left = (-posX -20) + "px";
/*padding problem (need -20): didn't .getBoundingClientRect() include
padding?*/
// /*or just*/ subMenu.style.right = "0px";
}
})
}
</script>
Now, what I done here:
First, I select all the <a> inside <nav>.
Then using for() loop and put mouseenter event to all the selected <a>.
When user hover over the <a>, the mouseenter know exactly which <a> was hover.
Now here's the problem: I want to select the a + ul of hovered <a>.
I have tried this:
console.log(document.querySelector("menu[i] + ul"));
gives me a null value
console.log(document.querySelector(menu[i] + " + ul"));
gives me SyntaxError: 'file:///C:/Users/path/path/thisPage.html + ul' is not a valid selector
console.log(menu[i].querySelector(" + ul"));
gives me SyntaxError: '+ul' is not a valid selector
How can I fix this? What is the right thing to do with .querySelector() for continuing selection but with adjacent sibling tag?

On one hand, on non-ancient browsers, you can use :scope to indicate the element on which the querySelector is being called on. But querySelector will only select elements which are children of the current element, and the <ul> you want is a sibling.
Take the nextElementSibling of the element instead, check that it exists, and check that it's a ul instead:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (subMenu.style.display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
Menu A.1
Menu A.2
</div>
<div class="right">
<div>
Menu B.1
<ul>
<li>B.1 Sub 1</li>
<li>B.1 Sub 2</li>
</ul>
</div>
<div>
Menu B.2
<ul>
<li>B.2 Sub 1</li>
<li>B.2 Sub 2</li>
</ul>
</div>
<div>
Menu B.3
<ul>
<li>B.3 Sub 1 Test Longer Text</li>
<li>B.3 Sub 2</li>
</ul>
</div>
<div>
Menu B.4
<ul>
<li>B.4 Sub 1</li>
<li>B.4 Sub 2</li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>
Because not all menus have sub-menus, you do need to test if the UL exists first before trying to do stuff with it.
Note that subMenu.style.display === "block" is never fulfilled in the given code because the <ul>s don't have style properties directly on the elements. If they did, the test would succeed. If you're trying to see if they currently are being displayed, use window.getComputedStyle instead:
for (const menu of document.querySelectorAll("nav div > a")) {
menu.addEventListener("mouseenter", function() {
console.log(menu, menu.nextElementSibling);
const subMenu = menu.nextElementSibling;
if (!subMenu || !subMenu.matches('ul')) {
return;
}
if (window.getComputedStyle(subMenu).display === "block") {
console.log("subMenu.style.display === block");
const subMenuBox = subMenu.getBoundingClientRect();
const posX = (subMenuBox.left + subMenuBox.width) - window.innerWidth;
subMenu.style.left = -posX;
console.log("When here successfully!");
} else {
console.log("Failed...");
}
})
}
body {
color: #fff;
font-size: 20px;
background: #999;
margin: 0;
}
a {
color: #cfc;
}
nav,
nav div>a,
nav div {
float: left;
}
nav {
width: 100%;
background: #4169E1;
white-space: nowrap;
}
nav div {
margin: 0em 0.2em;
}
nav div:first-child {
margin-left: 0;
}
nav div div {
position: relative;
margin: 0;
}
nav a {
color: #cff;
display: block;
font-weight: 600;
text-decoration: none;
padding: 0.5em 1em;
}
nav a:hover {
color: #fff;
background: #f90;
}
nav div>a+ul {
position: absolute;
top: 2.15em;
float: left;
background: #666;
list-style-type: none;
margin: 0;
padding: 0;
min-width: 180px;
display: none;
}
nav div:hover>a+ul {
display: block;
}
.right {
float: right;
}
<nav>
<div>
Menu A.1
Menu A.2
</div>
<div class="right">
<div>
Menu B.1
<ul>
<li>B.1 Sub 1</li>
<li>B.1 Sub 2</li>
</ul>
</div>
<div>
Menu B.2
<ul>
<li>B.2 Sub 1</li>
<li>B.2 Sub 2</li>
</ul>
</div>
<div>
Menu B.3
<ul>
<li>B.3 Sub 1 Test Longer Text</li>
<li>B.3 Sub 2</li>
</ul>
</div>
<div>
Menu B.4
<ul>
<li>B.4 Sub 1</li>
<li>B.4 Sub 2</li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>

Related

Shopify javascript Close Accordion on Clic

I'm customizing a Shopify store using Archetype Themes Motion v8.0.2. I have found a code to add tabs to my product pages. I've added media queries to my theme.css to display the tabs as an accordion at certain breakpoints. I would like to add code to close the accordion on click. I'm okay with HTML/CSS, but don't know any JS. I found the script online. Any help would be appreciated!
$(document).ready(function(){
$('ul.shopify-tabs > li').click(function(){
var tab_id = $(this).attr('data-tab');
$(this).parent().find('li').removeClass('current');
$('.shopify-tab-content').removeClass('current');
$(this).addClass('current');
$("#"+tab_id).addClass('current');
});
})
.section-tab-head {
background: #efefef;
color: #333;
display: block;
padding: 10px 10px;
cursor: pointer;
margin: 2px;
}
#media only screen and (min-width: 481px) and (max-width: 768px),
(min-width: 1051px) {
.section-tab-head {
background: none;
display: inline-block;
margin: inherit;
margin-top: 0;
}
}
.section-tab-head.current {
background: #dbdbdb;
color: #333;
}
.shopify-tab-content {
display: none;
background: none;
padding: 15px;
width: 100%;
}
.shopify-tab-content > p {
font-size: 10pt;
font-weight: 400;
}
.shopify-tab-content.current {
display: block;
font-size: 10pt;
background: white;
margin-top: 0px;
}
.shopify-tab-content > ul {
list-style: disc;
}
.shopify-tab-content > ul ul {
list-style: circle;
}
li,
.shopify-tab-content {
margin: 10px 0;
}
.shopify-tabs .shopify-tab-content {
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<ul class="shopify-tabs">
<li class="section-tab-head current" data-tab="section-tab-1"> Heading 1</li>
<div id="section-tab-1" class="shopify-tab-content current">
<p>some content goes here</p>
</div>
<li class="section-tab-head" data-tab="section-tab-2"> Heading 2</li>
<div id="section-tab-2" class="shopify-tab-content">
<p>more content in this tab</p>
</div>
<li class="section-tab-head" data-tab="section-tab-3"> Heading 3</li>
<div id="section-tab-3" class="shopify-tab-content">
<p>some content is in list form:</p>
<ul>
<li>product feature</li>
<li>product feature</li>
<li>product feature</li>
</ul>
</div>
</ul>
Add close button to each tab and add jquery code.
$('ul.shopify-tabs > li .close').click(function(){
$(this).parent().removeClass('current');
});

Adding more button for <ul> in responsive navigation - Angular

I have a navigation of 8 items (li), and when resolution gets smaller items drop in a new line. I need to make it so that when an item doesn't fit on a navigation anymore it should put a "MORE" dropdown button on the right side of nav and put the item that doesn't fit in a dropdown.
I don't know how I can do it with the Angular project, I don't need JQuery code.
This is my code:
<div id="mainMenu" class="main-menu">
<ul id="autoNav" class="main-nav">
<li>
home
</li>
<li>
about us
</li>
<li>
portfolio
</li>
<li>
team
</li>
<li>
blog
</li>
<li>
contact
</li>
<li id="autoNavMore" class="auto-nav-more">
more
<ul id="autoNavMoreList" class="auto-nav-more-list">
<li>
policy
</li>
</ul>
</li>
</ul>
</div>
Javascript Code:
const $mainMenu = $("#mainMenu");
const $autoNav = $("#autoNav");
const $autoNavMore = $("#autoNavMore");
const $autoNavMoreList = $("#autoNavMoreList");
autoNavMore = () => {
let childNumber = 2;
if($(window).width() >= 320) {
// GET MENU AND NAV WIDTH
const $menuWidth = $mainMenu.width();
const $autoNavWidth = $autoNav.width();
if($autoNavWidth > $menuWidth) {
// CODE FIRES WHEN WINDOW SIZE GOES DOWN
$autoNav.children(`li:nth-last-child(${childNumber})`).prependTo($autoNavMoreList);
autoNavMore();
} else {
// CODE FIRES WHEN WINDOW SIZE GOES UP
const $autoNavMoreFirst = $autoNavMoreList.children('li:first-child').width();
// CHECK IF ITEM HAS ENOUGH SPACE TO PLACE IN MENU
if(($autoNavWidth + $autoNavMoreFirst) < $menuWidth) {
$autoNavMoreList.children('li:first-child').insertBefore($autoNavMore);
}
}
if($autoNavMoreList.children().length > 0) {
$autoNavMore.show();
childNumber = 2;
} else {
$autoNavMore.hide();
childNumber = 1;
}
}
}
// INIT
autoNavMore();
$(window).resize(autoNavMore);
CSS Code:
.main-menu {
max-width: 800px;
}
.main-nav {
display: inline-flex;
padding: 0;
list-style: none;
}
.main-nav li a {
padding: 10px;
text-transform: capitalize;
white-space: nowrap;
font-size: 30px;
font-family: sans-serif;
text-decoration: none;
}
.more-btn {
color: red;
}
.auto-nav-more {
position: relative;
}
.auto-nav-more-list {
position: absolute;
right: 0;
opacity: 0;
visibility: hidden;
transition: 0.2s;
text-align: right;
padding: 0;
list-style: none;
background: grey;
border-radius: 4px;
}
.auto-nav-more:hover .auto-nav-more-list {
opacity: 1;
visibility: visible;
}
Any help to how I can do it with the Angular project (Typescript)?.
You can use the ng-repeat-start (ngRepeat directive)
https://docs.angularjs.org/api/ng/directive/ngRepeat
Example
<header ng-repeat-start="item in items">
Header {{ item }}
</header>
<div class="body">
Body {{ item }}
</div>
<footer ng-repeat-end>
Footer {{ item }}
</footer>

Javascript Drop Down Menu not working

I am trying to make a drop down menu with Javascript (no JQuery). In my HTML, I have an unordered list that contains two list items, each containing an anchor and an unordered list with more list items inside.
I am not concerned about the menus looking pretty, just that the Javascript works. Right now, I am trying to get it to set up event listeners through a
while loop so that when the top level list items are moused over, the class of the lower list itemsnwill change from one in which the CSS is set to display:none; to a class that has display:block; to make them appear.
I only have two tabs here, but that is because I shortened it from a list of ten tabs. I also don't care about any further submenus.
JS Fiddle: https://jsfiddle.net/xL5pukd5/
HTML:
<header>
<!-- <ul> <li><a></a><ul> <li><a></a></li> -->
<!-- dd-menu dd-menu-tab dd-menu-tab-anchor dd-submenu dd-submenu-tab dd-submenu-tab-anchor -->
<nav id="dd-menu-container">
<ul id="dd-menu">
<li class="dd-menu-tab">
Link 1
<ul class="dd-submenu">
<li class="dd-submenu-tab">
SubLink1a</li>
<li class="dd-submenu-tab">
Sublink1b</li>
</ul>
</li>
<li class="dd-menu-tab">
Link2
<ul class="dd-submenu">
<li class="dd-submenu-tab">
Sublimn2a</li>
<li class="dd-submenu-tab">
Sublink2b</li>
<li class="dd-submenu-tab">
Sublink2c</li>
</ul>
</li>
</nav>
</header>
JavaScript:
getTabs = function(elementClass) {
var tabs = document.getElementsByClassName(elementClass);
return tabs
};
getSubmenus = function(elementClass) {
var submenus = document.getElemenetsByClassName(elementClass);
return submenus;
};
window.onload = function {
var tabs = getTabs("dd-menu-tab");
var submenus = getSubmenus("dd-submenu");
var tabNumber = tabs.length - 1;
var currentTab = 0;
while (currentTab <= tabNumber) {
tabs[currentTab].onmouseover = function {
submenus[currentTab].className = "dd-submenu-onmouseover"
};
tabs[currentTab].onmouseout = function {
submenus[curenetTab].className = "dd-submenu"
};
currentTab += 1;
}
};
CSS:
.dd-submenu {
display: none;
}
.dd-submenu-onmouseover {
display: block;
}
I've tried using other prewritten drop down menu methods, but I couldn't get them to work, so I tried to create my own. Thanks in advance to any help :)
There are multiple issues with your script, including typos are said in the comment and wrong use of a closure variable in a loop.
But you really don't need js to fix this, you can use the :hover css selector to do it like
html,
body {
margin: 0;
padding: 0;
}
nav {
display: block;
padding: 0px;
margin: 0;
top: 0;
left: 0;
width: 100%;
background-color: beige;
}
.dd-menu-tab-anchor {
display: inline-block;
color: white;
}
.dd-menu {
position: absolute;
width: 100%;
top: 0;
left: 0;
}
.dd-menu-tab {
float: left;
padding-top: 10px;
padding-bottom: 10px;
padding-left: auto;
padding-right: auto;
width: 9%;
text-align: center;
}
.dd-submenu {
display: none;
}
.dd-menu-tab:hover .dd-submenu {
display: block;
}
li {
list-style-type: none;
background-color: #3300FF;
border: 2px;
border-color: white;
}
a {
text-align: center;
}
<header>
<!-- <ul> <li><a></a><ul> <li><a></a></li> -->
<!-- dd-menu dd-menu-tab dd-menu-tab-anchor dd-submenu dd-submenu-tab dd-submenu-tab-anchor -->
<nav id="dd-menu-container">
<ul id="dd-menu">
<li id="dd-menu-tab1" class="dd-menu-tab">
Link 1
<ul id="dd-submenu1" class="dd-submenu">
<li id="dd-submenu1-tab1" class="dd-submenu-tab">
SubLink1a
</li>
<li id="dd-submenu1-tab2" class="dd-submenu-tab">
Sublink1b
</li>
</ul>
</li>
<li id="dd-menu-tab2" class="dd-menu-tab">
Link2
<ul id="dd-submenu2" class="dd-submenu">
<li id="dd-submenu2-tab1" class="dd-submenu-tab">
Sublimn2a
</li>
<li id="dd-submenu2-tab2" class="dd-submenu-tab">
Sublink2b
</li>
<li id="dd-submenu2-tab3" class="dd-submenu-tab">
Sublink2c
</li>
</ul>
</li>
</nav>
</header>
<div>
<h1 id="site title">Website.com</h1>
</div>
<body>
<p>First paragraph sample text</p>
<p>Second paragraph sample text</p>
<p>Third paragraph sample text</p>
</body>
<footer>
<p>
References
</p>
<!-- <script src="file.js" type="text/javascript"></script> -->
</footer>
</html>
If you still want to continue using your logic
getTabs = function(elementClass) {
var tabs = document.getElementsByClassName(elementClass);
console.log(tabs);
return tabs
};
getSubmenus = function(elementClass) {
var submenus = document.getElementsByClassName(elementClass);
console.log(submenus);
return submenus;
};
window.onload = function() {
var tabs = getTabs("dd-menu-tab");
var submenus = getSubmenus("dd-submenu");
var tabNumber = tabs.length - 1;
var currentTab = 0;
[].forEach.call(tabs, function(el, idx) {
var submenu = submenus[idx];
el.addEventListener('mouseenter', function() {
submenu.className = "dd-submenu-onmouseover"
});
el.addEventListener('mouseleave', function() {
submenu.className = "dd-submenu"
});
})
};
html,
body {
margin: 0;
padding: 0;
}
nav {
display: block;
padding: 0px;
margin: 0;
top: 0;
left: 0;
width: 100%;
background-color: beige;
}
.dd-menu-tab-anchor {
display: inline-block;
color: white;
}
.dd-menu {
position: absolute;
width: 100%;
top: 0;
left: 0;
}
.dd-menu-tab {
float: left;
padding-top: 10px;
padding-bottom: 10px;
padding-left: auto;
padding-right: auto;
width: 9%;
text-align: center;
}
.dd-submenu {
display: none;
}
.dd-submenu-onmouseover {
display: block;
}
li {
list-style-type: none;
background-color: #3300FF;
border: 2px;
border-color: white;
}
a {
text-align: center;
}
<header>
<!-- <ul> <li><a></a><ul> <li><a></a></li> -->
<!-- dd-menu dd-menu-tab dd-menu-tab-anchor dd-submenu dd-submenu-tab dd-submenu-tab-anchor -->
<nav id="dd-menu-container">
<ul id="dd-menu">
<li id="dd-menu-tab1" class="dd-menu-tab">
Link 1
<ul id="dd-submenu1" class="dd-submenu">
<li id="dd-submenu1-tab1" class="dd-submenu-tab">
SubLink1a
</li>
<li id="dd-submenu1-tab2" class="dd-submenu-tab">
Sublink1b
</li>
</ul>
</li>
<li id="dd-menu-tab2" class="dd-menu-tab">
Link2
<ul id="dd-submenu2" class="dd-submenu">
<li id="dd-submenu2-tab1" class="dd-submenu-tab">
Sublimn2a
</li>
<li id="dd-submenu2-tab2" class="dd-submenu-tab">
Sublink2b
</li>
<li id="dd-submenu2-tab3" class="dd-submenu-tab">
Sublink2c
</li>
</ul>
</li>
</nav>
</header>
<div>
<h1 id="site title">Website.com</h1>
</div>
<body>
<p>First paragraph sample text</p>
<p>Second paragraph sample text</p>
<p>Third paragraph sample text</p>
</body>
<footer>
<p>
References
</p>
</footer>
Demo: Fiddle
getTabs = function(elementClass) {
var tabs = document.getElementsByClassName(elementClass);
console.log(tabs);
return tabs
};
getSubmenus = function(elementClass) {
var submenus = document.getElemenetsByClassName(elementClass);
console.log(submenus);
return submenus;
};
window.onload = function {
var tabs = getTabs("dd-menu-tab");
var submenus = getSubmenus("dd-submenu");
var tabNumber = tabs.length - 1;
var currentTab = 0;
while (currentTab <= tabNumber) {
tabs[currentTab].onmouseover = function {
submenus[currentTab].className = "dd-submenu-onmouseover"
};
tabs[currentTab].onmouseout = function {
submenus[curenetTab].className = "dd-submenu"
};
currentTab += 1;
}
};
html,
body {
margin: 0;
padding: 0;
}
nav {
display: block;
padding: 0px;
margin: 0;
top: 0;
left: 0;
width: 100%;
background-color: beige;
}
.dd-menu-tab-anchor {
display: inline-block;
color: white;
}
.dd-menu {
position: absolute;
width: 100%;
top: 0;
left: 0;
}
.dd-menu-tab {
float: left;
padding-top: 10px;
padding-bottom: 10px;
padding-left: auto;
padding-right: auto;
width: 9%;
text-align: center;
}
.dd-submenu {
display: none;
}
.dd-menu-tab:hover .dd-submenu {
position:absolute;
display: block;
}
li {
list-style-type: none;
background-color: #3300FF;
border: 2px;
border-color: white;
}
a {
text-align: center;
}
<header>
<!-- <ul> <li><a></a><ul> <li><a></a></li> -->
<!-- dd-menu dd-menu-tab dd-menu-tab-anchor dd-submenu dd-submenu-tab dd-submenu-tab-anchor -->
<nav id="dd-menu-container">
<ul id="dd-menu">
<li id="dd-menu-tab1" class="dd-menu-tab">
Link 1
<ul id="dd-submenu1" class="dd-submenu">
<li id="dd-submenu1-tab1" class="dd-submenu-tab">
SubLink1a</li>
<li id="dd-submenu1-tab2" class="dd-submenu-tab">
Sublink1b</li>
</ul>
</li>
<li id="dd-menu-tab2" class="dd-menu-tab">
Link2
<ul id="dd-submenu2" class="dd-submenu">
<li id="dd-submenu2-tab1" class="dd-submenu-tab">
Sublimn2a</li>
<li id="dd-submenu2-tab2" class="dd-submenu-tab">
Sublink2b</li>
<li id="dd-submenu2-tab3" class="dd-submenu-tab">
Sublink2c</li>
</ul>
</li>
</nav>
</header>
<div>
<h1 id="site title">Website.com</h1>
</div>
<body>
<p>First paragraph sample text</p>
<p>Second paragraph sample text</p>
<p>Third paragraph sample text</p>
</body>
<footer>
<p>
References
</p>
<!-- <script src="file.js" type="text/javascript"></script> -->
</footer>
</html>

Horizontal scrolling list center when needed

I have to move a horizontal navigation bar when clicked on a link in the list. I have created a JSFiddle to illustrate my problem.
When a user clicks on a link in the list, the list needs to scroll to the left or right. This part is already finished.
When you click on the link, the active link needs to be centered inside the list.
Link to JSFiddle:
https://jsfiddle.net/7yq0jq9s/2/
html
<div class="container">
<ul>
<li class="active"> 1
</li>
<li> 2
</li>
<li> 3
</li>
<li> 4
</li>
<li> 5
</li>
<li> 6
</li>
<li> 7
</li>
<li> 8
</li>
</ul>
CSS
div.container {
width: 600px;
overflow: hidden;
}
ul {
white-space: nowrap;
}
ul li {
display: inline-block;
background: green;
}
ul li a {
padding: 80px;
display: block;
color: white;
font-weight: bold;
text-decoration: none;
}
ul li.active {
background: blue;
}
JS
$(document).ready(function () {
var scrollTo = 0;
$('body').on('click', "a", function () {
var activeItem = $('li.active');
var selectedItem = $(this).parent()
var activeIndex = $('li').index(activeItem);
var selectedIndex = $('li').index(selectedItem);
if (selectedIndex > activeIndex) {
scrollTo -= selectedItem.position().left - activeItem.position().left;
console.log('Scroll right');
} else {
scrollTo += Math.abs(selectedItem.position().left - activeItem.position().left);
console.log('Scroll left');
if (scrollTo >= 0) {
scrollTo = 0;
}
}
$('ul').css('transform', 'translateX(' + scrollTo + 'px)');
activeItem.removeClass('active');
selectedItem.addClass('active');
});
});
I think it's easier to just get the absolute position of the clicked element and calculate the middle position of the container instead of checking if it needs to scroll left or right:
var scrollTo = 0;
$('body').on('click', "a", function () {
var activeItem = $('li.active');
var selectedItem = $(this).parent()
var activeIndex = $('li').index(activeItem);
var selectedIndex = $('li').index(selectedItem);
scrollTo =- selectedItem.position().left + $('.container').width() / 2 - selectedItem.width() / 2;
$('ul').css('transform', 'translateX(' + scrollTo + 'px)');
activeItem.removeClass('active');
selectedItem.addClass('active');
});
div.container {
width: 600px;
overflow: hidden;
}
ul {
white-space: nowrap;
transition: all ease 750ms;
position:relative;
}
ul li {
display: inline-block;
background: green;
}
ul li a {
padding: 80px;
display: block;
color: white;
font-weight: bold;
text-decoration: none;
}
ul li.active {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="container">
<ul>
<li class="active"> 1
</li>
<li> 2
</li>
<li> 3
</li>
<li> 4
</li>
<li> 5
</li>
<li> 6
</li>
<li> 7
</li>
<li> 8
</li>
</ul>
</div>
var scrollTo = 0;
$('body').on('click', "a", function () {
var activeItem = $('li.active');
var selectedItem = $(this).parent()
var activeIndex = $('li').index(activeItem);
var selectedIndex = $('li').index(selectedItem);
scrollTo =- selectedItem.position().left + $('.container').width() / 2 - selectedItem.width() / 2;
$('ul').css('transform', 'translateX(' + scrollTo + 'px)');
activeItem.removeClass('active');
selectedItem.addClass('active');
});
div.container {
width: 600px;
overflow: hidden;
}
ul {
white-space: nowrap;
transition: all ease 750ms;
position:relative;
}
ul li {
display: inline-block;
background: green;
}
ul li a {
padding: 80px;
display: block;
color: white;
font-weight: bold;
text-decoration: none;
}
ul li.active {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="container">
<ul>
<li class="active"> 1
</li>
<li> 2
</li>
<li> 3
</li>
<li> 4
</li>
<li> 5
</li>
<li> 6
</li>
<li> 7
</li>
<li> 8
</li>
</ul>
</div>
I think you just needed to change one little bit on line 10:
if (selectedIndex = activeIndex) {
https://jsfiddle.net/7yq0jq9s/3/

Fitting a <ul>'s width to accommodate the menu items

I have a menu that contains submenus. Its HTML source looks like this:
<ul id="menu">
<li>
Menu 1
<ul>
<li><a href="javascript:;">Item 1<a></li>
<li>
Subitem 1
<ul>
<li>Subsubitem 1</li>
</ul>
</li>
</ul>
</li>
</ul>
After applying some CSS and getting the JavaScript side of things in order with Superfish, the menu looks like this in the browser:
The second menu item is too big to fit into its space, so the remainder of the text is rendered onto the text of the next menu item. Is there a way to enlarge the <ul> to make sure that the text fits?
Update: here's the relevant CSS code:
ul#menu {
position: relative;
top: 160px;
left: 130px;
width: 700px;
}
ul#menu, ul#menu ul {
list-style-type: none;
}
ul#menu > li {
display: block;
float: left;
background: url(img/menuitem.png) top left;
width: 104px;
height: 37px;
margin-right: 5px;
text-align: center;
}
ul#menu > li:hover {
background-position: bottom left;
}
ul#menu > li > a {
height: 100%;
padding-top: 10px;
font-size: 80%;
font-weight: bold;
color: white;
}
ul#menu > li > a, ul#menu > li > ul a {
display: block;
text-decoration: none;
}
ul#menu > li ul {
min-width: 150px;
}
ul#menu > li > ul li {
color: black;
font-size: 10pt;
text-align: left;
padding-left: 5px;
padding-right: 5px;
height: 30px;
line-height: 30px;
background: url(img/menubg.png) repeat;
}
ul#menu > li > ul li:hover {
background-color: #9c938c;
}
ul#menu > li > ul a {
color: black;
}
ul#menu > li ul {
position: relative;
top: -10px;
}
ul#menu > li li.hoverItem > ul {
position: relative;
top: -30px;
}
ul#menu > li > a > span.sf-sub-indicator {
display: none;
}
ul#menu > li > ul > li a > span.sf-sub-indicator {
float: right;
margin-right: 5px;
}
span.sf-sub-indicator and li.hoverItem are used by Superfish. sf-sub-indicator is used to indicate that hovering over a menu item will cause a submenu to be opened like so:
<li>
Menu item with submenu<span class="sf-sub-indicator"> ยป</span>
<ul>
<!-- Etc -->
</ul>
</li>
li.hoverItem is applied to all menu items you passed to get to the menu where your mouse is positioned, plus the menu item your mouse is currently hovering on.
Ok, I put something together using the same css definitions that you posted above. This works for me - automatically detects the size of the largest element and adjusts the related CSS.
You'll need to adjust the li elements to have a predictable naming scheme, so that it can find the largest one. Depending on your font, you might need to adjust the *5 portion of the assignment for the newSize.
<html>
<head>
<title></title>
<meta content="">
<script type="text/javascript">
function changeSize() {
var html = document.getElementById("item"+1).innerHTML;
var newSize = html.length*5;
var num_menu_items = 3;
for (i=2; i<=num_menu_items; i++) {
var temp = document.getElementById("item"+i).innerHTML;
if (temp.length > newSize / 5)
newSize = temp.length*5;
}
var theRules = new Array();
var rule;
if (document.styleSheets[0].cssRules)
theRules = document.styleSheets[0].cssRules
else if (document.styleSheets[0].rules)
theRules = document.styleSheets[0].rules
for (i = 0; i<theRules.length; i++) {
if (theRules[i].selectorText.indexOf("ul#menu > li ul") > -1) {
rule = theRules[i];
}
}
rule.style.setProperty('min-width',newSize+"px",null);
}
</script>
</head>
<body onload='changeSize();'>
<ul id="menu">
<li>A-one</li>
<li>A-two</li>
<li>A-three
<ul>
<li id='item1'>B-one</li>
<li id='item2'>B-two-is-really-really-really-really-really-really-really-really-really-really-really-really long</li>
<li id='item3'>B-three</li>
</ul>
</li>
</ul>
</body>
</html>
This block here:
ul#menu > li ul {
min-width: 150px;
}
Is where the size for that item is. You will have to change that to something larger.
The reason it doesn't expand, is because its parent's width is small than that.

Categories