<nav> resizing to fit child contents - javascript

I have tried every CSS trick in the book today to get my parent nav tag home-main-nav-menu to resize according to it's children and grand children, but I can't for the life of me get it to work. If someone can provide and explanation of how the fix this that would be much terrific, and an explanation of why elements don't naturally expanded to fit it's child contents would be even better. Thanks! [see image and css for reference]
$(document).ready(function(){
$('.main-ul').children('li').on('click', function() {
$(this).children('ul').slideToggle('slow');
});
});
.home-main-nav-menu{
border-style: double;
border-color: cyan;
}
.A{
display: inline-block;
text-align: center;
padding-left: 5px;
margin-right: 10px;
border-style: double;
border-color: purple;
}
.B{
list-style-type: none;
text-align: left;
margin-left: -40.5px;
}
.A > ul {
display: none;
}
.main-ul{
border-style: double;
border-color: green;
width: 95.5%;
margin-left: -3px;
}
ul{
text-align: center;
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class = "home-main-nav-menu">
<ul class = "main-ul">
<li class = "A">a</li>
<li class = "A">b
<ul>
<li class = "B">c</li>
<li class = "B">d</li>
</ul>
</li>
<li class = "A">e</li>
<li class = "A">f
<ul>
<li class = "B">f</li>
<li class = "B">g</li>
</ul>
</li>
<li class = "A">h
<ul>
<li class = "B">i</li>
<li class = "B">j</li>
</ul>
</li>
<li class = "A">k
<ul>
<li class = "B">l</li>
<li class = "B">m</li>
</ul>
</li>
</ul>
</nav>
see CSS for color map

The problem is that your class:
ul{
text-align: center;
position: absolute;
}
Is positioning all the the ul as absolute and pulling all those elements out of the normal flow of the document and into its own layer. This effectively disconnects the nav from its child uls even though the HTML structure shows them as a group.
Changing it to:
ul{
text-align: center;
position: relative;
}
Solves the issue. This still pulls the ul elements out of the flow, but without specifying a specific position, keeps the element where it is in the flow and holds the original position within the main flow of the document.
From MDN:
absolute
The element is removed from the normal document flow; no
space is created for the element in the page layout. Instead, it is
positioned relative to its closest positioned ancestor if any;
otherwise, it is placed relative to the initial containing block. Its
final position is determined by the values of top, right, bottom, and
left. This value creates a new stacking context when the value of
z-index is not auto. Absolutely positioned boxes can have margins, and
they do not collapse with any other margins.
relative
The element is positioned according to the normal flow of the
document, and then offset relative to itself based on the values of
top, right, bottom, and left. The offset does not affect the position
of any other elements; thus, the space given for the element in the
page layout is the same as if position were static. This value creates
a new stacking context when the value of z-index is not auto. The
effect of relative on table-*-group, table-row, table-column,
table-cell, and table-caption elements is undefined.
Also, removing:
width: 95.5%;
from the .main-ul class keeps the ul elements from overflowing the parent.
$(document).ready(function(){
$('.main-ul').children('li').on('click', function() {
$(this).children('ul').slideToggle('slow');
});
});
.home-main-nav-menu{
border-style: double;
border-color: cyan;
}
.A{
display: inline-block;
text-align: center;
padding-left: 5px;
margin-right: 10px;
border-style: double;
border-color: purple;
}
.B{
list-style-type: none;
text-align: left;
margin-left: -40.5px;
}
.A > ul {
display: none;
}
.main-ul{
border-style: double;
border-color: green;
margin-left: -3px;
}
ul{
text-align: center;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class = "home-main-nav-menu">
<ul class = "main-ul">
<li class = "A">a</li>
<li class = "A">b
<ul>
<li class = "B">c</li>
<li class = "B">d</li>
</ul>
</li>
<li class = "A">e</li>
<li class = "A">f
<ul>
<li class = "B">f</li>
<li class = "B">g</li>
</ul>
</li>
<li class = "A">h
<ul>
<li class = "B">i</li>
<li class = "B">j</li>
</ul>
</li>
<li class = "A">k
<ul>
<li class = "B">l</li>
<li class = "B">m</li>
</ul>
</li>
</ul>
</nav>

Related

How to remove simultaneously both elements in DOM with the same ids in JavaScript?

What I am trying to do is, when I click on green element I want the purple one with the same id be removed. Now my problem is I can not loop through purple element's id and find the one which match with green one and then remove it from the DOM. I tried to use querySelectorAll but it doesn't work with addEventListener and when I use querySelector it just returns always the first element.So the goal is to remove both elements green and purple that has the same id.
if you see in HTML code inside the ul tag there is another one with the id container actually this is the problem the first ul tag with id main is the original one and the one inside it with id container it will be generated automatically with jQuery plugin if I set any new attribute to class main the class container will copy it. my goal is to click on green one and delete two elements from DOM. The one which I am clicking and another with same id. is there any way for that?
Has anyone solution for that how to remove simultaneously another element with the same id of clicked element?
document.addEventListener("DOMContentLoaded", () => {
document.querySelector("ul").addEventListener("click", getItem)
})
function getItem(e) {
let li = e.target.closest(".visible")
let span = e.target
let getID = span.attributes.id.value
console.log("This is visible element", getID)
if (li) {
li.remove()
}
}
#main {
background-color: skyblue;
}
.hidden {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #7d34eb;
}
#container {
background-color: #3483eb;
margin-top: 15px
}
.visible {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #12a370;
}
span {
position: relative;
left: 1rem;
padding: 50%;
color: red;
cursor: pointer;
}
<div class="content">
<ul id="main">
<li class="hidden">
<span id="1">A</span>
</li>
<li class="hidden">
<span id="2">B</span>
</li>
<li class="hidden">
<span id="3">C</span>
</li>
<ul id="container">
<li class="visible">
<span id="1">A</span>
</li>
<li class="visible">
<span id="2">B</span>
</li>
<li class="visible">
<span id="3">C</span>
</li>
</ul>
</ul>
</div>
I changed all your spans to div to fill up the LI element. I also changed all id to data-id, because id should be a unique.
EDIT: Based on the comment. In your original post, you added a click listener on the first UL that querySelector returns, which is #main. I made that more clear in the code. As the comment, in my answer, suggest, it's better to add a click listener to ul#container instead.
EDIT 2: Based on another comment. :P I added code for looping through and removing all elements with matching data-id.
document.addEventListener("DOMContentLoaded", () => {
document.querySelector("ul#main").addEventListener("click", getItem);
})
function getItem(e) {
let divEl = e.target;
let dataset = divEl.dataset;
let visibleLi = divEl.parentElement;
let isVisibleElement = visibleLi.classList.contains('visible');
let matchingDatasetDivs = document.querySelectorAll(`[data-id="${dataset.id}"]`);
if (isVisibleElement)
console.log("This is visible element", dataset.id);
if (isVisibleElement && matchingDatasetDivs.length) {
for (let i = 0; i < matchingDatasetDivs.length; i++) {
let containerLi = matchingDatasetDivs[i].parentElement;
containerLi.remove();
}
}
}
#main {
background-color: skyblue;
}
.hidden, .visible {
border: solid 2px black;
list-style: none;
margin: 2px;
background-color: #7d34eb;
}
.visible {
background-color: #12a370;
}
#container {
background-color: #3483eb;
margin-top: 15px
}
li > div {
position: relative;
left: 1rem;
/* padding: 50%; */
color: red;
cursor: pointer;
text-align: center; /* ADDED */
}
<div class="content">
<ul id="main">
<li class="hidden">
<div data-id="1">A</div>
</li>
<li class="hidden">
<div data-id="2">B</div>
</li>
<li class="hidden">
<div data-id="3">C</div>
</li>
<ul id="container">
<li class="visible">
<div data-id="1">A</div>
</li>
<li class="visible">
<div data-id="2">B</div>
</li>
<li class="visible">
<div data-id="3">C</div>
</li>
</ul>
</ul>
</div>

<ul> display inline-block not working

My jsFiddle is here : https://jsfiddle.net/r1s6651y/1/
I am not able to get Navigation with Numerals to be aligned horizontally.
I have applied display : inline-block for upper ul but still the next menu item begins on the second line.
Any clues ?
It should be stacked as :
1111111 22222222
AAAAAAAAAAAAA
BBBBBBBBBBBBB
You can't have li with width: 100%; and then expect them to align next to eachother. Ofcourse they naturally fall to 2 lines instead of 1, they're inline elements after all (Think of it like this: the <p> tag is also "inline" bu default. When the text in a <p> is too long, the text "breaks" to a new line. As will your li when it is set to be inline). You also want the li to next to eachother, not the ul which is what contains the li. So apply the display: inline-block; to the (correct) li elements
ul#myRow li {
width: auto; //could also be set to 50% if it's just 2 li elements
display: inline-block;
}
Two things. As already noted, you want the li items to be display:inline. You also need to remove the width:100% from the lis of #myRow. Then it will collapse and display inline as long as the container is wide enough for them (otherwise it will wrap).
li {
background: #00945f;
border-bottom: 1px solid #016e39;
clear: both;
float: none;
height: 62px;
margin: 0;
padding: 0 30px 30px;
width: 100%;
}
ul {
list-style-type: none;
}
ul#myRow li {
display:inline-block;
width: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section>
<ul id="myRow" class="row">
<li>
11111111
</li>
<li>
2222222
</li>
</ul>
<ul class="row">
<li>
AAAAAAAAAAAAAAa
</li>
<li>
BBBBBBBBBBBBBBB
</li>
</ul>
</section>
Man, you do some mistakes.
I fixed it at: https://jsfiddle.net/r1s6651y/4/
li {
display: inline-block;
background: #00945f;
border-bottom: 1px solid #016e39;
margin: 0;
padding: 10px 20px;
}
put a class on the li you want horizontal, then add css display: inline
.horiz {
display: inline;
}
<section>
<ul id="myRow" class="row">
<li class="horiz">
11111111
</li>
<li class="horiz">
2222222
</li>
</ul>
<ul class="row">
<li>
AAAAAAAAAAAAAAa
</li>
<li>
BBBBBBBBBBBBBBB
</li>
</ul>
</section>

Give submenu full column width using jQuery or CSS?

I am trying to make a menu that has some links in two levels.
What I am trying to do is to make it so that when you click on the top level then level 2 opens.
Right now my problem is that I want to have two columns but I want level two to be one full width column.
See my codepen here: http://codepen.io/mathiasha/pen/KdzmBL
I don't know if it's easiest to make it in CSS or jQuery.
I dont have control of the HTML.
<div class="block block-menu-block">
<ul class="menu">
<li>
1
</li>
<li>
2
<ul class="menu">
<li>2.1</li>
<li>2.2</li>
<li>2.3</li>
<li>2.4</li>
</ul>
</li>
<li>
3
<ul class="menu">
<li>3.1</li>
<li>3.2</li>
<li>3.3</li>
<li>3.4</li>
</ul>
</li>
<li>
4
</li>
<li>
5
</li>
<li>
6
<ul class="menu">
<li>6.1</li>
</ul>
</li>
</ul>
</div>
See the CSS below:
.block-menu-block {
width: 100%;
border: 5px solid red;
overflow: hidden;
}
ul.menu {
list-style-type: none;
padding: 0;
margin: 0;
font-weight: bold;
}
ul.menu li {
display: block;
width: 50%;
border: 1px solid #000;
margin: -1px;
float: left;
text-align: center;
}
ul.menu li a {
display: block;
padding: 20px;
text-decoration: none;
}
li a ~ ul a {
color: green;
}
As long as first level LIs are set to be width:50%, children are bounded. Setting sub-level absolutely positionned could have been a solution, but in your case, it breaks the desired effect.
So a "dirty" solution that I can give you is to use this :
.block-menu-block ul li ul{ width:200%; margin-left:-100%; }
.block-menu-block ul li ul li{ width:100%; background:#fff;}
Sub-level UL width will be multiplied by two, and then has the same width as the menu. Used negative margin to make a translation, otherwise, it will start under the parent LI and will expend out of the menu boundaries.
And finally, reset the sub LIs width to 100% (background is used to hide parent borders).
Updated Codepen

AngularJS top menu submenu dropdowns on hover (persist showing whilst moving to submenu)

I have a top menu with various links. On hover, each should show a dropdown with additional menu items. I have tried attached onmouseover and onmouseleave events to the menu item to hide/show the sub menu; however, when transitioning off of the menu item and into the sub menu, the onmouseleave fires and hides the sub menu and the user doesn't have a chance to actually interact with the sub menu.
<nav>
<div class="container-fluid">
<ul class="">
<li>
<a ui-sref="home.person" ng-init="showPersonSubMenu=false" ng-mouseenter="showPersonSubMenu=true" ng-mouseleave="showPersonSubMenu=false">People</a>
<ul class="person-sub-menu" ng-show="showPersonSubMenu">
<li>Add Person</li>
</ul>
</li>
<li><a ui-sref="home.company">Companies</a></li>
<li><a ui-sref="home.job">Jobs</a></li>
<li><a ui-sref="home.report">Reports</a></li>
</ul>
</div>
</nav>
How can I show the sub menu on hover, and hide it on leaving... whilst still allowing the user to actually access the sub menu so it doesn't hide before they can interact with it.
You were on the right track.
Make sure there is no space between your menu item and your absolute sub-menu. To ensure that there is no space, make the menu item bigger (using height or line-height), or add a padding to it...
Here's a working example:
http://codepen.io/jlowcs/pen/QwJwJZ
HTML:
<ul class="menu">
<li>
<a>People</a>
<ul class="sub-menu">
<li>Add Person</li>
<li>Action 2</li>
</ul>
</li>
<li><a ui-sref="home.company">Companies</a></li>
</ul>
CSS:
ul, li {
list-style-type: none;
margin: 0;
padding: 0;
}
.menu {
background: lightblue;
height: 30px;
padding: 0 10px;
}
.menu > li {
display: inline-block;
width: 100px;
line-height: 30px;
}
.sub-menu {
position: absolute;
display: none;
background-color: lightgreen;
padding: 5px;
}
.sub-menu > li {
display: block;
cursor: pointer;
}
li:hover .sub-menu {
display: block;
}
EDIT: if you want your submenu to float lightly lower, here's a way of doing that:
http://codepen.io/jlowcs/pen/dPQPxW
Just add the following CSS:
.sub-menu {
margin-top: 10px;
}
.menu > li:hover {
padding-bottom: 10px;
}

different height to li tag

i want to Design Menu bar as shown below, i have created whole list in ul but how to set different height ,width for center .Please help i tried code below but middle part is not increasing,
<nav id="Edit_panel">
<ul>
<li class="menubar" title="redo">
<div id="link">redo</div>
</li>
<li class="menubar" title="undo">
<div id="link">undo</div>
</li>
<li class="menubar" title="cut">
<div id="link">Cut</div>
</li>
<li class="menubar" title="copy">
<div id="link">Copy</div>
</li>
<li class="menubar" title="paste">
<div id="link">paste</div>
</li>
<li class="menubar" title="select">
<div id="link">select</div>
</li>
<li class="menubar" title="hand">
<div id="link">hand</div>
</li>
<li class="menubar" title="zoomin">
<div id="link">zoomin</div>
</li>
<li class="menubar" title="zoomout">
<div id="link">zoomout</div>
</li>
<li class="menubar" title="addimage">
<div id="link">Add img</div>
</li>
</ul>
</nav>
css:
#Edit_panel {
background-color: gray;
height:25px;
display: inline;
}
ul
{
background-color: #D8D8D8;
height:30px;
}
li {
display: inline-block;
margin-right: 10px;
margin-left: 10px;
text-align: center
}
Just add another class to elements You want to increase and set diferent height.
And remove duplicated ids.
First of all, you cannot have multiple elements with the same id, so you should change all
id = "link"
to
class = "link"
or delete those id's
Another mistake is putting height to the ul in css. The 30px height of ul means, that you want the whole list to be 30px high. You want to define the height for li elements, not the whole ul.
Instead of:
ul
{
background-color: #D8D8D8;
height:30px;
}
li {
display: inline-block;
margin-right: 10px;
margin-left: 10px;
text-align: center
}
Should be:
ul
{
background-color: #D8D8D8;
}
li {
height:30px;
display: inline-block;
margin-right: 10px;
margin-left: 10px;
text-align: center
}
If you want some elements to have different height or width, you can add some class to them, and define height for the class, for example:
<li class="menubar higher" title="paste">
<div id="link">paste</div>
</li>
And then in CSS you add:
.higher {
height: 50px;
}
Then your elements will be 30px high, and elements witch also have "higher" class, will he higher than others;]
you can give different heights to your elements by jquery. Use this demo for it.
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<style>
.test
{
height:25px;
}
</style>
<script>
$(document).ready(function(e) {
$("li").eq(5).addClass("test"); // In 'eq' 5 is a index of li element and it starts from 0 to n-1
});
</script>

Categories

Resources