This simple code will work:
<!DOCTYPE html>
<html>
<body>
<br>
<div>
<a href="#a1">Link 1</a>
<a href="#a2">Link 2</a>
<a href="#a3">Link 3</a>
<a href="#a4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<br><br>
<div>
<a href="#b1">Link 1</a>
<a href="#b2">Link 2</a>
<a href="#b3">Link 3</a>
<a href="#b4">Link 4</a>
</div>
<a href="#c1">Link 1 <span>color me plz!</span></a>
<a href="#c2">Link 2 <span>color me plz!</span></a>
<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>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2"">Menu B.2</a>
<ul>
<li><a href="#B2.1">B.2 Sub 1</a></li>
<li><a href="#B2.2">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3">Menu B.3</a>
<ul>
<li><a href="#B3.1">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4">Menu B.4</a>
<ul>
<li><a href="#B4.1">B.4 Sub 1</a></li>
<li><a href="#B4.2">B.4 Sub 2</a></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>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></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>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></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>
<a href="#A1">Menu A.1</a>
<a href="#A2">Menu A.2</a>
</div>
<div class="right">
<div>
<a href="#B1">Menu B.1</a>
<ul>
<li><a href="#B1.1">B.1 Sub 1</a></li>
<li><a href="#B1.2">B.1 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B2">Menu B.2</a>
<ul>
<li><a href="#B2.1 ">B.2 Sub 1</a></li>
<li><a href="#B2.2 ">B.2 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B3 ">Menu B.3</a>
<ul>
<li><a href="#B3.1 ">B.3 Sub 1 Test Longer Text</a></li>
<li><a href="#B3.2 ">B.3 Sub 2</a></li>
</ul>
</div>
<div>
<a href="#B4 ">Menu B.4</a>
<ul>
<li><a href="#B4.1 ">B.4 Sub 1</a></li>
<li><a href="#B4.2 ">B.4 Sub 2</a></li>
</ul>
</div>
</div>
</nav>
<div style="float: left; margin-top: 1000px "></div>