Style the Child and not Grandchild? - html

I am trying to make a 'fancy' navigation, with multiple ul/li. I think my problem is in the CSS with the child selector (>). If you run the code snippet provide you'll notice when you hover over li.first (item one) you can visibly see the div.hover-container although li:first>ul>li has the css with overflow: hidden; along with this div.hover-container is within li.one (example one) so why does it display when I hover over li.>one (other examples).
I am just confused and would love some input on this after staring and testing possible solutions for an hour.
EDIT: I apologize for how messy it looks in the snippet.
/* ================== Example ================ */
.example>ul {
display: flex;
position: relative;
height: 50px;
width: 800px;
margin: 50px auto;
list-style-type: none;
background-color: #5A827E;
}
.example>ul>li {
display: block;
height: 100%;
width: 33.3%;
border-right: 2px solid rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
color: white;
font-weight: bold;
text-align: center;
line-height: 50px;
font-style: italic;
}
.example>ul>li:hover {
overflow: visible;
background-color: #415E5B;
}
.first>ul {
display: block;
position: absolute;
top: 50px;
height: 400px;
width: 100.5%;
list-style-type: none;
background-color: #415E5B;
}
.first>ul>li {
display: block;
color: white;
line-height: 40px;
text-align: center;
height: 10%;
width: 100%;
border-top: 1px dotted rgba(255, 255, 255, 0.5);
font-weight: 400;
font-style: normal;
overflow: hidden;
}
.first>ul>li:hover {
background-color: white;
color: blue;
}
.hover-container {
display: flex;
justify-content: flex-start;
flex-flow: column wrap;
position: absolute;
left: 265px;
top: 0;
height: 400px;
width: 535px;
border: 3px solid gold;
}
.list-container {
display: block;
height: auto;
width: 30%;
border: 3px solid #F2D7E2;
}
.list-container h2 {
text-align: left;
color: darkgray;
font-weight: bold;
}
.list-container ul {
list-style-type: none;
text-align: left;
}
/* ------------------ Example END ---------------- */
<div class="example">
<ul>
<!-- first navigation container -->
<li class="first"> Item One
<ul>
<!-- dropdown -->
<li class="one"> Example 1
<!-- dropdown item -->
<div class="hover-container">
<!-- sidebar -->
<div class="list-container">
<!-- sidebar content box-->
<h2>Content Header One</h2>
<ul>
<li>Content One</li>
<li>Content Two</li>
<li>Content Three</li>
</ul>
</div>
<!-- sidebar content box END -->
<div class="list-container">
<!-- sidebar content box-->
<h2>Content Header One</h2>
<ul>
<li>Content One</li>
<li>Content Two</li>
<li>Content Three</li>
</ul>
</div>
<!-- sidebar content box END -->
</div>
<!-- sidebar END-->
</li>
<!-- dropdown item END -->
<li>Example 2</li>
<li>Example 3</li>
<li>Example 4</li>
<li>Example 5</li>
<li>Example 6</li>
<li>Example 7</li>
<li>Example 8</li>
<li>Example 9</li>
<li>Example 10</li>
</ul>
<!-- END of dropdown -->
</li>
<!-- main list item END -->
<li class="second">Item Two</li>
<li class="third">Item Three</li>
</ul>
</div>

If you want the hover-container div to be shown only when the first li(Example 1) is hovered, you need to replace the .hover-container you have added with the below CSS:
.first>ul>li:first-child:hover .hover-container{
display: flex;
justify-content: flex-start;
flex-flow: column wrap;
position: absolute;
left: 265px;
top: 0;
height: 400px;
width: 535px;
border: 3px solid gold;
}

Your child selectors seem okay. I think the problem is with your positioning. The .hover-container element has "position: absolute", meaning it's placed relative to its first positioned ancestor (see https://www.w3schools.com/css/css_positioning.asp). You want to determine if it's overflowing the .first>ul>li element above it, so that element needs a "position: relative."
Adding these rules should give the behavior you're looking for:
.first>ul>li {
position: relative;
...
}
.first>ul>li:hover {
overflow: visible;
...
}

The following CSS property rule defined on .hover-container set its position to absolute with respect to .example>ul>li which is the nearest ancestor that is a containing block (read about how the browser determines a containing block.)
.hover-container {
/*...*/
position: absolute;
/*...*/
}
The fix for this is to form a containing block with the li that is closest ancestor to .hover-container by setting its position to relative.
.first>ul>li {
/*...*/
position: relative;
/*...*/
}
Another fix for this is to set the overflow property to hidden for the closest containing block that is an ancestor to .hover-container.
.first>ul {
/*...*/
overflow: hidden;
/*...*/
}

Related

Hoverable menu goes out of page

I have a hoverable menu as you can see in the code. However, I got a problem when I hover, which the hover content goes out of the page. When I use "position: relative" for the div(content) it is okay but then the text "Example" goes to the left, wonder how to fix.
When I use position: absolute:
When I use position: relative:
ul {
float: right;
position: relative;
}
div {
display: none;
background-color: red;
position: relative;
width: 200px;
}
ul:hover div {
display: block;
}
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
due to lack of space u'r getting this issue make width:200px; for ul
ul {
float: right;
position: relative;
width: 200px;
}
div {
display: none;
background-color: red;
position: relative;
width: 200px;
}
ul:hover div {
display: block;
}
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
You could use position absolute, and manipulate its positions setting a negative margin...
ul {
float: right;
position: relative;
}
div {
display: none;
background-color: red;
position: absolute;
width: auto;
margin-left: -26px;
}
ul:hover div {
display: block;
}
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
Erase the div, apply the width to the ul and apply the display: none and hovering to the ol.
ul {
float: right;
width: 200px;
}
ol {
display: none;
background-color: red;
}
ul:hover ol {
display: block;
}
<ul>
<li>Example</li>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</ul>
Second version: If you want everything to be floated right, apply float: right; to ul and li in the HTML structure as used before:
ul {
float: right;
}
ol {
display: none;
background-color: red;
}
li {
float: right;
clear: right;
}
ul:hover ol {
display: block;
}
<ul>
<li>Example</li>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</ul>
It's natural behavior, it will depend on header text lenght, it will set your max lenght for below text, you'll need to define a fixed width for the header element and not on child one as you did.
Example of dynamic width (natural div property as a flex container):
ul {
float: right;
position: relative;
}
div {
display: none;
background-color: red;
position: relative;
}
ul:hover div {
display: block;
}
<ul>
<li>ExampleOfMagicMenu</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
Second example, setting fixed width to the parent box, letting child/s element/s with auto-width (they will never occupy more width than parent, as they can grow in height, overriding height auto with a fixed one will cause overflow):
ul {
float: right;
position: relative;
width: 100px;
text-align: right;
list-style: none;
}
div {
display: none;
background-color: red;
position: relative;
}
ul:hover div {
display: block;
}
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
You can do it with the Flexbox without unnecessary floats and positioning.
Solution with the container as you wrote in the comment:
.container {
max-width: 960px;
margin: 0 auto;
border: 1px solid;
}
ul {
display: flex; /* displays children inline by default that's why you need to change its direction */
flex-direction: column; /* stacks children vertically */
align-items: flex-end; /* places them far right */
}
ul > div { /* modified for accuracy */
display: none;
background-color: red;
width: 200px;
}
ul li:hover + div { /* modified for accuracy since the inner div is the next element after the li */
display: block;
}
li + div:hover {display:block} /* needs to be in order to be displayed when hovering over */
<div class="container">
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
</div>
If you don't fancy the above solution then you can simply add right: 0 to the absolutely positioned div:
.container {
max-width: 960px;
margin: 0 auto;
border: 1px solid;
}
.container:after {
content: "";
display: block;
clear: both;
}
ul {
float: right;
position: relative;
}
ul > div {
display: none;
background-color: red;
position: absolute;
right: 0; /* added */
width: 200px;
}
ul:hover div {
display: block;
}
<div class="container">
<ul>
<li>Example</li>
<div>
<ol>
<li>Link 1</li>
<li>Link 2</li>
</ol>
</div>
</ul>
</div>

When the parent is float:left and the child is fixed, how to set position?

I would like to change the picture above as shown below.
Please refer to the code below.
I'm wondering how to solve this problem without 'padding-left, margin-left'
.nav-wrap {
position: relative;
overflow: hidden;
top: -2px;
width: 33.33333333333333%;
float: left;
}
.sidebar-nav {
position: fixed;
width: 380px;
padding-top: 95px;
padding-bottom: 95px;
padding-left: 20px;
padding-right: 20px;
height: 100%;
float: left;
clear: both;
overflow-y: hidden;
display: block;
background: transparent;
background: rgba(0, 0, 0, 0.28);
z-index: 10;
}
.content-wrap {
width: 66.66666666666666%;
background: #fff;
float: left;
height: 100%;
position: relative;
padding: 45px 50px;
overflow: hidden;
}
<div class="nav-wrap">
<div class="sidebar-nav">
</div>
</div>
<div class="content-wrap">
</div>
Try this instead - I've created a barebone for you without bootstrap. You can start from here.
<ul id="mainWrapper">
<li class="left-wrap">
<div class="menuList">
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</div>
</li>
<li class="right-wrap">
Content here...
</li>
</ul>

Make div take the remaining height after another div take its height below it

I am trying to create a sidebar where year is displayed in the bottom and list of links on the top.
The year text should stay in the bottom and its height should be auto not absolute values (like 30px, 1em, 10% etc.)
The top links should remain inside the remaining height (screen height - height of year text).
When the links height exceeds, scrolling should be provided.
I have successfully achieved the first 2, but not the 3rd. When the links height exceeds, the year hides from the screen.
I have used table to achieve what I specified. (I could have used display: table; just being lazy here)
I want to achieve this using only CSS, no JavaScript.
/* Some styles */
.side-bar table {
color: #fff;
}
.side-bar-links {
background-color: #48c;
padding-top: 15px;
}
.side-bar-links li:nth-child(even) {
background-color: rgba(0,0,0,0.1);
}
.side-bar-links a {
display: block;
color: #fff;
padding: 5px 15px;
text-decoration: none;
}
.side-bar-links a:hover {
background-color: rgba(0,0,0,0.2);
}
.year {
background-color: #338;
font-size: 36px;
font-weight: 700;
padding: 5px 15px;
}
/* Positioning */
.side-bar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
}
.side-bar table {
height: 100%;
table-layout: fixed;
}
.side-bar table tr:last-child td {
height: 1px;
}
.side-bar table td {
vertical-align: baseline;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="side-bar">
<table>
<tr>
<td class="side-bar-links">
<ul class="list-unstyled">
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
</ul>
</td>
</tr>
<tr>
<td class="year">
<b>2016</b>
</td>
</tr>
</table>
</div>
Try the following CSS and see if it works:
.side-bar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
overflow: scroll;
overflow-y: auto;
overflow-x: auto;
}
You have to have something that determines the maximum height your container is going to be. Then you can handle overflow. I've modified your code a bit to change to a div layout and set up the overflow on the container. I believe this is what you're after.
The example in the snippet has a fixed height, so you may need to open it in full screen to see the whole example ('Run code snippet' - then 'full page').
You could also use percentages for heights to avoid using a fixed height.
/* Some styles */
.side-bar-links {
height: 300px;
max-height: 400px;
overflow:hidden;
background-color: #48c;
padding-top: 15px;
overflow-y: auto;
}
.side-bar-links li:nth-child(even) {
background-color: rgba(0,0,0,0.1);
}
.side-bar-links a {
display: block;
color: #fff;
padding: 5px 15px;
text-decoration: none;
}
.side-bar-links a:hover {
background-color: rgba(0,0,0,0.2);
}
.year {
background-color: #338;
font-size: 36px;
font-weight: 700;
padding: 5px 15px;
color: #fff;
}
/* Positioning */
.side-bar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="side-bar">
<div class="side-bar-links">
<ul class="list-unstyled">
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
</ul>
</div>
<div class="year">
<b>2016</b>
</div>
</div>
Try the following:
<html><head>
<title>Page Title</title>
<style>
/* Some styles */
.side-bar table {
color: #fff;
}
.side-bar-links {
background-color: #48c;
padding-top: 15px;
}
.side-bar-links li:nth-child(even) {
background-color: rgba(0,0,0,0.1);
}
.side-bar-links a {
display: block;
color: #fff;
padding: 5px 15px;
text-decoration: none;
}
.side-bar-links a:hover {
background-color: rgba(0,0,0,0.2);
}
.year {
background-color: #338;
font-size: 36px;
font-weight: 700;
padding: 5px 15px;
position: fixed;
bottom: 0px;
height: auto !Important;
width: auto;
}
/* Positioning */
.side-bar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
overflow: scroll;
overflow-y: auto;
overflow-x: auto;
height: calc(100% - 60px);
}
.side-bar tr:first-child{height:100%;}
.side-bar table {
height: 100%;
table-layout: fixed;
width:110px;
}
.side-bar table tr:last-child td {
height: 1px;
}
.side-bar table td {
vertical-align: baseline;
}
</style>
</head>
<body>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<div class="side-bar">
<table>
<tbody><tr>
<td class="side-bar-links">
<ul class="list-unstyled">
<li>> Link 1</li>
<li>> Link 2</li>
<li>> Link 3</li>
<li>> Link 4</li>
<li>> Link 5</li>
<li>> Link 5</li>
<li>> Link 5</li>
</ul>
</td>
</tr>
<tr>
<td class="year">
<b>2016</b>
</td>
</tr>
</tbody></table>
</div>
</body></html>

Fully justified horizontal menu with image and separators

I would like to achieve this fully justified horizontal menu:
Justifying is done with flexbox and works, but I could not get the separating mid-dots justified, too; they are made by using css-content via pseudo-class. Also, I am wondering if there's a better way to vertically center the items than faking it by adding a padding as I have done it.
Here's my code and the fiddle:
ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
}
li.home {
padding: 0;
}
li {
vertical-align: middle;
padding-top: 10px;
}
nav {
border-bottom: 1px solid black;
border-top: 1px solid black;
height: 40px;
}
li::after {
//padding: 0em 0.4em;
content: '\00b7';
pointer-events: none;
}
li.home::after,
li.last::after {
content: none;
text-align: justify;
}
<nav id="main-menu">
<ul>
<li class="home">
<img src="http://dummyimage.com/40x40/000/fff">
</li>
<li class="second">Item 1</li>
<li>Item 2</li>
<li>One more Item</li>
<li>Another Item</li>
<li class="last">Contact</li>
</ul>
</nav>
body { margin: 0; } /* 1 */
nav {
height: 40px;
border-bottom: 1px solid black;
border-top: 1px solid black;
}
ul {
display: flex;
justify-content: space-between; /* 2 */
align-items: center; /* 2 */
height: 100%;
list-style: none;
padding: 0;
margin: 0;
}
li:not(.home) {
flex: 1; /* 3 */
height: 100%;
border: 1px dashed red; /* 4 */
background-color: lightgreen; /* 4 */
}
li:not(.home) > a { /* 5 */
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
li img { vertical-align: bottom; } /* 6 */
li { position: relative; } /* 7 */
li:not(.home):not(:last-child)::before { /* 8 */
position: absolute;
content: '\26AB'; /* 4 */
left: 100%;
top: 50%;
transform: translate(-50%,-50%);
z-index: 1;
pointer-events: none;
}
<nav id="main-menu">
<ul>
<li class="home">
<img src="http://dummyimage.com/40x40/000/fff">
</li>
<li class="second">Item 1</li>
<li>Item 2</li>
<li>One more Item</li>
<li>Another Item</li>
<li class="last">Contact</li>
</ul>
jsFiddle
Notes:
Remove default margins on body element
Methods for Aligning Flex Items
Consume all remaining space with flex-grow property
Borders, background colors, and larger bullets for illustration purposes only
Enable anchor elements to fully cover list item space and align text with flex properties
Remove baseline alignment (i.e., whitespace underneath image)
Establish nearest positioned ancestor for absolute positioning
Use absolute positioning to align bullets
You can vertically center the items with align-self: center; but the dot separators are in my opinion impossible to achieve with pseudo elements like :before or :after.
I would recommend to use separate <li> tags for separators like below:
Note that your image element needs display: block; to have a proper height.
ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
}
img {
display: block;
}
li.home {
padding: 0;
}
li {
align-self: center;
}
nav {
border-bottom: 1px solid black;
border-top: 1px solid black;
height: 40px;
}
<nav id="main-menu">
<ul>
<li class="home">
<img src="http://dummyimage.com/40x40/000/fff">
</li>
<li class="second">Item 1</li>
<li class="separator">·</li>
<li>Item 2</li>
<li class="separator">·</li>
<li>One more Item</li>
<li class="separator">·</li>
<li>Another Item</li>
<li class="separator">·</li>
<li class="last">Contact</li>
</ul>
</nav>
Fiddle version

Need help in CSS nav Style

I am trying to build CSS nav bar but i am in a bit trouble. In my code, background box is collapsing with content inside it .My question is why it is collapsing and can it be solved by not giving height to the box.Here is my code.
HTML
<div class="item">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
CSS
body {
color: #648;
}
.item ul {
list-style: none;
padding: 0;
margin: 0;
}
* {
}
.item {
padding: 20px;
width: 70%;
/* height: 65px; */
background-color: blanchedalmond;
margin: 50px auto;
border-radius: 10px;
}
.item li {
float: left;
width: 45px;
margin: 10px;
border-radius: 10px;
padding: 20px;
background-color: aqua;
}
Use display:inline or display:inline-block instead of float:left.
http://jsfiddle.net/x2ubrrh3/
Update
When display:flex is used you have to stop the elements from floating afer your list is finished (clear:both)
See here: http://jsfiddle.net/x2ubrrh3/1/