display flex creating extra space why - html

My understanding of flexbox, is that if you display a element as flex, that item become flex container and it direct children will become flex items and these flex items behave as inline block items,
so i am following this logic, and it was working fine, untill i added the last in my css, please read the comment i left the comment in my css code, which line is confusing me.
in short i was expecting similiar outcome, but i am confuse about the space, please see the image to understand as well,
HTML CODE
<ul class="menu">
<li>Home</li>
<li>About</li>
<li class="menu-item-has-children">Services
<ul class="sub-menu">
<li>Plumbing</li>
<li class="menu-item-has-children">Heating
<ul class="sub-menu">
<li>Residential</li>
<li>Commercial</li>
<li>Industrial</li>
</ul>
</li>
<li>Electrical</li>
</ul>
</li>
<li>Pricing</li>
<li>Contact Us</li>
</ul>
CSS CODE
/*basic style no need to pay attention*/
*{font-family:helvetica;
margin:0px;padding:0;
list-style-type:none;
}
ul{margin:5px;}
ul ul a:link{color:red;}
ul ul ul a:link{color:black}
/*displaying them as flex, work fine*/
.menu{display:flex;}
.menu li {flex:1;}
.menu li a {
display:block;
min-width:100%
}
/*this line is confusing to me*/
ul ul li{
display:flex;
}
First image
Second image

By default, flex organizes elements in rows, from left to right. In your case, that means that the two elements inside <li class="menu-item-has-children"> (the link and the sub-menu) will be positioned side by side.
You have to add flex-direction: column to fix your issue:
* {
font-family: helvetica;
margin: 0px;
padding: 0;
list-style-type: none;
}
ul {
margin: 5px;
}
ul ul a:link {
color: red;
}
ul ul ul a:link {
color: black
}
.menu {
display: flex;
}
.menu li {
flex: 1;
}
.menu li a {
display: block;
}
ul ul li {
display: flex;
flex-direction: column; /* <- specify the flex direction here */
}
<ul class="menu">
<li>Home</li>
<li>About</li>
<li class="menu-item-has-children">Services
<ul class="sub-menu">
<li>Plumbing</li>
<li class="menu-item-has-children">Heating
<ul class="sub-menu">
<li>Residential</li>
<li>Commercial</li>
<li>Industrial</li>
</ul>
</li>
<li>Electrical</li>
</ul>
</li>
<li>Pricing</li>
<li>Contact Us</li>
</ul>
The fact that your sub-menu appears to be outside your flex container is caused by the min-width: 100% setting on your .menu li a elements.

Related

How to align a dropdown in CSS

I am making a website and I want to make a drop-down list but I have a trouble.
I want to do something like this:
Option A Option B Option C Option D Option E
and a dropdown list to B with 4 options but when I do it, it looks like that:
Option A Option B
.....................Option 1
.....................Option 2
.....................Option 3
.....................Option 4
...........................................Option C Option D Option E
this is my code:
.option {
display: inline-block;
}
.option>li {
display: inline;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<nav>
<ul>
<div class="option">
<li>Home</li>
<li>Services
<ul>
<li>3D
<li>2D
<li>Websites
<li>IT help
</ul>
</li>
</div>
<div class="option">
<li>Gallery
<li>Contact
<li>About Me
</div>
</ul>
</nav>
</body>
</html>
</nav>
Restructure your HTML
Close your li tags. Make sure you are closing them properly like
this:
<li>Home</li>
Nest all of the top level menu items (Home, Services, Gallery, Contact, About Me) in a single ul
Your HTML should look something like this
<nav>
<ul>
<li>Home</li>
<li>Services
<ul>
<li>3D</li>
<li>2D</li>
<li>Websites</li>
<li>IT help</li>
</ul>
</li>
<li>Gallery</li>
<li>Contact</li>
<li>About Me</li>
</ul>
</nav>
Add style
Add a class to the Services li to indicate that it is a dropdown. I am calling mine dropdown
Remove those pesky dots on each list item using list-style: none; padding: 0;
To arrange the top level ul horizontally, make it a flexbox by applying display: flex; on the ul. I would also add flex-wrap: none; to make sure the list does not try to wrap its elements on small screens.
I recommend giving each element of the flexbox a constant width and aligning the text how you like like. I used width: 80px; text-align: center;
Lastly, hide the elements of your dropdown by setting the inner ul's display to none. And show the dropdown by setting display to block. I did this using the class open
ul {
list-style: none;
padding: 0;
}
nav > ul {
display: flex;
flex-wrap: none;
}
nav > ul > li {
width: 80px;
text-align: center;
}
nav > ul > li.dropdown > ul > * {
display: none;
}
nav > ul > li.dropdown.open > ul > * {
display: block;
}
<nav>
<ul>
<li>Home</li>
<li class="dropdown">Services
<ul>
<li>3D</li>
<li>2D</li>
<li>Websites</li>
<li>IT help</li>
</ul>
</li>
<li>Gallery</li>
<li>Contact</li>
<li>About Me</li>
</ul>
</nav>
Add interaction
Now if you want to actually make the submenu expand, I recommend using JavaScript. In the code snippet above, all you need to do is toggle the class open on any li with the dropdown class.
There are infinite possibilities, but a good place to start is this W3 Schools tutorial on building clickable dropdown menus. Be mindful of accessibility features as well by reading this W3 tutorial on building accessible flyout menues.
Here is a tutorial on building a CSS only accessible dropdown menu; although I recommend sticking to JS solutions, because they are more versatile.
Rudimentary example using JS
const dropdownMenuItems = document.querySelectorAll("li.dropdown");
const toggleDropdown = (e, el) => {
if (e.target.classList.contains("dropdown-control")) {
el.classList.toggle("open");
}
};
dropdownMenuItems.forEach((el) => {
el.addEventListener("click", (e) => toggleDropdown(e, el));
});
ul {
list-style: none;
padding: 0;
}
nav > ul {
display: flex;
flex-wrap: none;
}
nav > ul > li {
width: 80px;
text-align: center;
}
nav > ul > li.dropdown > ul > * {
display: none;
}
nav > ul > li.dropdown.open > ul > * {
display: block;
}
<nav>
<ul>
<li>Home</li>
<li class="dropdown">Services
<ul>
<li>3D</li>
<li>2D</li>
<li>Websites</li>
<li>IT help</li>
</ul>
</li>
<li>Gallery</li>
<li>Contact</li>
<li>About Me</li>
</ul>
</nav>
Closing thoughts
I kept the styling really barebones. You can of course style however you like. It seems like you are mostly asking about how to get the arrangement right.
It probably makes sense to change the Services a tag to a button if it does not behave like a link. This is important for screen readers to know how to treat that element.
Here's how I would do it: It's a little bare, but it works. I would make each li have the class of option and get rid of the divs so that it is more consistent and simpler. Also, you were missing all of your closing li tags, which messed some things up. I also added a simple :hover mechanism so that it will hide and show when you hover over it.
.option {
display: inline-block;
vertical-align: top;
width: 75px;
margin: 0;
padding: 0;
}
.dropdown {
display: none;
padding: 0;
list-style-type: none;
}
.contains-dropdown:hover > .dropdown{
display: block
}
option>li {
display: inline;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<nav>
<ul>
<li class="option">Home</li>
<li class="option contains-dropdown">
Services
<ul class="dropdown">
<li>3D</li>
<li>2D</li>
<li>Websites</li>
<li>IT help</li>
</ul>
</li>
<li class="option">Gallery</li>
<li class="option">Contact</li>
<li class="option">About Me</li>
</ul>
</nav>
</body>
</html>
</nav>

Moving css only menu items 1 by 1 when resizing window

I have the below shown css only menu, but am wondering how I can, when the browser window gets smaller and the menu items doesnt fit, how I can move them one by one! onto the last, right most item "more..." so they create a sub menu there instead. Please see the following pictures of how first item "seventh" and "eighth" are moved onto "more..." and the second picture shows what should happen when you hover over "seventh", it should reveal its original sub menu items.
My current code: (pen with same for easier resizing: https://codepen.io/anon/pen/oZoMbK)
* {box-sizing:border-box;}
.nav{
background-color:#d6336c;
font-size:20px;
}
.nav ul{
list-style: none;
}
.nav ul li{
padding:2px 20px;
float: left;
position:relative;
background: #1bc2a2;
white-space: nowrap;
}
.nav ul li ul {
display:none;
position: absolute;
background-color:orange;
left: 0;
}
.nav ul li ul, .nav li li {
min-width: 100%;
}
.nav ul li:hover > ul{
display: block;
}
.nav ul ul ul{
left:100%;
top:0;
}
.nav a{
color:#ffffff;
}
ul,li{
margin:0;
padding:0;
}
<div class="nav">
<ul>
<li>first</li>
<li>second
<ul>
<li>sub1 first</li>
<li>sub1 second
<ul>
<li>sub2 first</li>
<li>sub2 second
<ul>
<li>sub3 first</li>
<li>sub3 second</li>
<li>sub3 third</li>
</ul>
</li>
</ul>
</li>
<li>sub2 third</li>
</ul>
</li>
<li>third
<ul>
<li>.
<li>.
<li>.
</ul>
</li>
<li>fourth</li>
<li>fifth</li>
<li>sixth</li>
<li>seventh
<ul>
<li>cats</li>
<li>dogs
<ul>
<li>beagle</li>
<li>boxer</li>
</ul>
</li>
<li>birds</li>
</ul>
</li>
<li>eighth</li>
<li>more...</li>
</ul>
</div>
First image when hovering "more...":
Second image, when hovering "seventh" under "more...":
I cant figure out how its done, only with media queries but I dont want set specific values as the menu items width might change/be dynamic. The following two pens somehow moves the items one by one as they dont fit when resizing the screen:
https://codepen.io/VPenkov/pen/wMZBOg & https://codepen.io/tejasukmana/pen/bZKNrJ
I really want to keep this css only, no javascript.
thanks in advance for any help!
Frank

how to display a list inline using HTML and CSS [duplicate]

This question already has answers here:
How to make a <ul> display in a horizontal row
(9 answers)
Closed 1 year ago.
I am trying to create a menu using html, I have added my link in an unordered list (ul) has shown below. In my css i added a display:inline; to the links so that they would display in a link like a menu but for some reason it doesn't seem to work.
#menu a {
text-decoration: none;
}
#menu ul {
list-style: none;
}
#menu ul li a {
display: inline;
}
<div id="menu">
<ul>
<li>Home
</li>
<li>About Us
</li>
<li>Special Offers
</li>
<li>Meet Our Staff
</li>
<li>Contact
</li>
</ul>
</div>
You are targeting the anchors, which are already inline by default. I believe you mean to target the list items:
#menu ul li {
display: inline;
}
JSFiddle
You were very close!
The only thing wrong with your code, is that display: inline; should be on your <li> elements instead of your <a> elements :
#menu a {
text-decoration: none;
}
#menu ul {
list-style: none;
}
#menu ul li {
display: inline;
}
<div id="menu">
<ul>
<li>Home
</li>
<li>About Us
</li>
<li>Special Offers
</li>
<li>Meet Our Staff
</li>
<li>Contact
</li>
</ul>
</div>
(see also this Fiddle)
Try this: ul li { float: left; padding-right:10px; }
https://jsfiddle.net/n4aak3nk/1/

h3 and list dropdown menu CSS3

got an html list working as a dropdown menu with CSS when you hover through a < li > element like "Products" in my example. But what I want is the same effect when hover through < h3 > like "Contact" from my example. Is it possible?
Here's the html:
<h3>Contact</h3>
<ul>
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul>
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
And the CSS code:
ul li ul {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
Thank you very much in advance.
On hover you can only control the CSS of the element you hover over, or the CSS of elements within the element you hover over (one of its children).
So you can not make the ul change styles when you hover over the h3 because they 1) are not the same object and 2) do not have a parent-child relationship (they are siblings).
To show the menu when hovering over the h3, you can wrap both of them inside another object (div) and use this for the hover event. To distinguish between the two hovers you can add classnames to both the uls.
See this JSfiddle, or the code below:
<div class="container">
<h3>Contact</h3>
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul class="submenu">
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>
.container ul{
display: none;
}
.container:hover ul.menu{
display: block;
}
ul li ul.submenu {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
In short - you should nest ul inside the h3
<h3>
Contact
<ul>
<li>Home</li>
<li>About</li>
<li>
Products ▾
<ul>
<li>Laptops</li>
<li>Monitors</li>
<li>Printers</li>
</ul>
</li>
<li>Contact</li>
</ul>
</h3>
And in your css:
ul li ul {
display: none;
}
ul li:hover ul{
display: block; /* display the dropdown */
}
h3 > ul {
display: none;
}
h3:hover > ul {
display: block;
}
Here's the demo: https://jsfiddle.net/mscehjLf/1/

Horizontal CSS dropdown menu

I am trying to make a horizontal drop down menu in CSS. However, it appears vertically:
I want the two topmost menu items to be horizontal. What can I do, besides making a table with one row?
ul ul {
display: none;
}
ul li:hover > ul {
display: block;
}
<ul>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
</ul>
You can try floating the list items:
.root {
overflow: hidden; /* clear float */
}
.root > li {
float: left;
}
<ul class="root">
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
<li>
abc
<ul>
<li>abc</li>
<li>abc</li>
</ul>
</li>
</ul>
You can add submenu a class/id with
.inline-menu{
display: inline;
}
http://jsfiddle.net/dyaskur/fby9fan6/
The gist of your question is actually this: what is the difference between inline and block elements? This is a fundamental question that is important to understanding the basics of layout in CSS/HTML. There is a good write-up on this topic and some of the trade-offs of the various approaches at:
http://designshack.net/articles/css/whats-the-deal-with-display-inline-block/
Basically, <li> is block-level tag, meaning that it displays as its own "block" element: receives a layout (settable dimensions), by default takes the entire width of the parent element, and has a forced break after the rendered element (is on a line to itself).
So, that leaves us with a number of approaches for having your menu items sit side-by-side:
Use inline-level elements for your menu items
Use block-level elements and float them
Use block-level elements and style them as inline-block
All of these approaches are detailed in the above link. Personally, I prefer to use floated block elements. I have a fiddle with some rough css to give you an idea. Note that there are some considerations in how to display your submenus as well. You'll note that I've implemented these as having display: block, with no float, because we want them to stack vertically.
HTML
<ul class="menu">
<li>
foo
<ul class="submenu">
<li>subfoo1</li>
<li>subfoo2</li>
</ul>
</li>
<li>
bar
<ul class="submenu">
<li>subbar1</li>
<li>subbar2</li>
</ul>
</li>
</ul>
CSS
ul.menu {
list-style: none;
}
ul.menu > li{
float: left;
position: relative;
}
ul.menu li {
background-color: #cccccc;
padding: 5px 20px;
}
ul.menu > li + li {
border-left: solid black 2px;
}
ul.menu li:hover > ul {
display: block;
}
ul.menu li a,ul.menu li a:link, ul.menu li a:hover, ul.menu li a:visited {
color: black;
text-decoration: none;
}
ul.submenu{
display: none;
list-style: none;
position:absolute;
left: 0;
padding: 0;
}
ul.submenu li {
float:none;
display: block;
}
ul.submenu > li + li {
border-top: solid black 1px;
}
You can just remove some <li> tags:
<ul>
<li>
abc
<ul>
abc
abc
</ul>
</li>
<li>
abc
<ul>
abc
abc
</ul>
</li>
</ul>