Overflow: scroll; only the y-axis whilst keeping x-axis visible - html

Problem case
I'm trying to create a scrolling, fixed-height list with flyouts for each list item.
I've used overflow-y: scroll; so that it can be scrolled in the y-axis.
However when I also try to use overflow-x: visible (in order to display the overflowing flyouts) it seems to be ignored
Code
Example 1 - List can be scrolled, but flyouts are clipped
As you can see, the flyouts (in-pink) are clipped
.list {
width: 72px;
height: 132px;
overflow-x: visible;
overflow-y: scroll;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
.flyout {
position: absolute;
top: 0;
bottom: 0;
left: 64px;
width: 128px;
background: pink;
}
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
Example 2 - List cannot be scrolled, flyouts displayed just fine
Removing overflow-y: scroll shows the flyouts just fine, but as expected, the list can no longer be scrolled height-wise.
.list {
width: 72px;
height: 132px;
overflow-x: visible;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
.flyout {
position: absolute;
top: 0;
bottom: 0;
left: 64px;
width: 128px;
background: pink;
}
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
A possible solution
I could of course make my .list have a width just enough so the flyouts don't overflow it.
I'd like to avoid that, as the list would be placed on top of a drawing canvas, thus it would block painting on the canvas via the mouse.
Using pointer-events: none so as not to block painting wouldn't work in this case as the pointer-events are necessary in order to detect the scroll-event for the list in the first place.

You will need to remove position: relative. Then the absolute positioned flyouts won't be restricted by overflow.
However, they won't scroll properly. You will need to trigger a relayout with JS.
// Force relayout
var li = document.querySelector('li:last-child');
setInterval(function() {
var parent = li.parentNode;
var next = li.nextSibling;
parent.removeChild(li);
parent.insertBefore(li, next);
}, 60);
.container {
position: relative;
overflow: hidden;
margin: 1em 0;
}
.list {
width: 72px;
height: 132px;
overflow-y: scroll;
background: lightgray;
margin: 0;
}
.list li {
margin-bottom: 6px;
}
.flyout {
display: inline-block;
position: absolute;
width: 128px;
background: pink;
}
<div class="container">
<ul class="list">
<li>
Item 1
<div class="flyout">Item 1 Flyout</div>
</li>
<li>
Item 2
<div class="flyout">Item 2 Flyout</div>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
</div>

Since you cannot force a child to exit an overflow parent - and control it's position - here's a
jQuery solution
jQuery creates dynamically a <div class="flyout"></div> element.
On LI hover it calculates the position and shows the flyout element.
The content is taken from the hovered LI data-flyout attribute:
var $flyout = $("<div/>", {
class: "flyout",
appendTo: "body",
hover: function(e) {
$(this).toggle();
}
});
$("[data-flyout]").hover(function(e) {
var par = this.parentNode; // The overlfow parent element
$flyout.css({
left: this.offsetLeft + this.offsetWidth,
top: this.offsetTop - par.scrollTop,
}).html( this.dataset.flyout ).toggle();
});
.list {
width: 72px;
height: 132px;
overflow-x: hidden;
overflow-y: scroll;
background: lightgray;
}
.list li {
position: relative;
margin-bottom: 6px;
}
/* Created in "body" by jQuery */
.flyout {
position: absolute;
z-index:99999;
display: none;
background: pink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li data-flyout="Item 1 Flyout">Item 1</li>
<li data-flyout="Item 2 Flyout">Item 2</li>
<li>No fly</li>
<li data-flyout="Item 4 Flyout">Item 4</li>
<li data-flyout="Item 5 Flyout">Item 5</li>
<li data-flyout="Item 6 Flyout">Item 6</li>
<li data-flyout="Item 7 Flyout">Item 7</li>
<li data-flyout="Item 8 Flyout">Item 8</li>
</ul>

Maybe you could leverage something like Superfish's vertical menu and call it a day.
I agree with the above comments in that I don't see a pure CSS way to accomplish this.

Related

Pseudo class with column count not working in the safari browser

Pseudo class with column count not working in the safari browser.
I have two screenshots.
1. Firefox browser screenshot
2. Sarari browser screenshot
You can check in the screenshot, The first one screenshot is working in with columns count but in the second screenshot, it's not displaying the dots. Is there any issue with my code?
.columnBox {
width: 500px;
margin: auto;
}
ul {
list-style: none;
}
.column-count {
column-count: 2;
}
.accord-mobile-data li {
position: relative;
}
.accord-mobile-data li::before {
content: "";
color: #094CB2;
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50px;
position: absolute;
background-color: #094CB2;
left: -15px;
top: 4px;
}
<div class="columnBox">
<p>Without Column count</p>
<ul class="accord-mobile-data">
<li>Demo 1</li>
<li>Demo 2</li>
<li>Demo 3</li>
<li>Demo 4</li>
<li>Demo 5</li>
<li>Demo 6</li>
</ul>
<p>With Column count</p>
<ul class="column-count accord-mobile-data">
<li>Demo 1</li>
<li>Demo 2</li>
<li>Demo 3</li>
<li>Demo 4</li>
<li>Demo 5</li>
<li>Demo 6</li>
</ul>
</div>
Your code works fine, I checked it in firefox and chrome. In this case the problem is with safari, this browser does not support the ::before and ::after pseudo-elements. You can check this out here: ::before | ::afrer. Sometimes we just can't have it all ;-)

absolute positioning ul inside another ul

Starting from this situation:
<div id="wrapper">
<ul class="menu">
<li>item 1</li>
<ul>
<li>item 1.1</li>
<li>item 1.2</li>
</ul>
<li>item 2</li>
</ul>
</div>
#wrapper {
/*width: 218px;*/
margin: 0px auto;
background-color: #cccccc;
overflow:hidden;
position: absolute;
top: 100px;
left: 0;
z-index: 999;
width: 31px;
}
The second level menu is visible only on click on the first level item (say item 1). The first level list will make room to show the sublevel one.
First level list have a width of 31px; when I hover an item it gets 187 extra width on the right showing labels (item 1 for example) with css3 transition. The other items will keep the 31px width.
My goal is to style the second level list so that:
width is 187px;
it is positioned with top=0 and right=0 relative to the first level item (in other words it is aligned on the right with the first level item)
has a z-index higher than wrapper so that it will not move the other items when displayed.
I tried to give position relative to the first level item and absolute to the sublevel but with no luck.
The first level menu when hovered:
The second level menu displayed actually:
A simple demo of what you are looking for is here
<div id="wrapper">
<ul class="menu">
<li>item 1
<ul class="l2">
<li>item 1.1</li>
<li>item 1.2</li>
</ul>
</li>
<li>item 2</li>
</ul>
</div>
and the css:
ul.l2 {
background-color: grey;
display: none;
position: absolute;
z-index: 99;
}
.menu li:hover ul.l2{display:block;}
If this is the kind of behavior you want, we can take it further.

Show/Hide Different Divs Only

I have two divs. When I rollover on a link, I want to hide one div and show the other so it appears as if the background color has changed. Here is some example HTML:
<div id="main-nav">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div id="sub-nav">
<ul>
<li>SubItem 1</li>
<li>SubItem 2</li>
<li>SubItem 3</li>
</ul>
</div>
The sub-nav div is EXACTLY the same as the main-nav div, except the background-color is different.
#main-nav {
width: 500px;
height: 250px;
background-color: black;
display: block;
}
#sub-nav {
width: 500px;
height: 250px;
background-color: white;
display: none;
}
All I want to do is show the #sub-nav div whenever an item in the #main-div is hovered over. So the effect will be that the background-color appears to change from black to white on hover.
Can I do this using only CSS?
Basically I am wanting to know if I can change the display property of a containing div whenever an element inside that div (the <a> tag) is hovered over? That is, hovering on a link should cause its containing div #main-nav to change to display: none and the #sub-nav div to become display:block
No you can't do this just with CSS. You would need the subnav to be a child of the element you are hovering or directly adjacent to it.
You could use css selectors like
#main-nav li:hover .sub-nav{}
or
#main-nav li:hover + .sub-nav{}
Alternatively you could use javascript
Why not just change the background color? Like this:
<div id="main-nav">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
#main-nav:hover { background-color: black; }
Edit you can do exactly what you asked, but you'd need a wrapper for that:
<div class="navigation-wrapper">
<div class="main">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div class="sub">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</div>
And in your css:
.navigation-wrapper .sub { display: none; }
.navigation-wrapper:hover .main { display: none; }
.navigation-wrapper:hover .sub { display: block; }
Fiddle demo

How to move UL tags inside of a div to form a menu

I'm trying to achieve a shopping menu in my html code,
Here is the simple piece of html I am working with so far
<html>
<head>
<style>
.category-list
{
width: 300px;
background-color: #CCC;
}
body {background-image: url("images/background.gif");}
</style>
</head>
<body>
<div class="category-list">
<ul>
<li>Item 1-1</li>
<li>Item 1-2</li>
<li>Item 1-3</li>
</ul>
<ul>
<li>Item 2-1</li>
<li>Item 2-2</li>
<li>Item 2-3</li>
<li>Item 2-4</li>
<li>Item 2-5</li>
</ul>
<ul>
<li>Item 3-1</li>
<li>Item 3-2</li>
</ul>
<ul>
<li>Item 4-1</li>
<li>Item 4-2</li>
<li>Item 4-3</li>
</ul>
</div>
</body>
</html>
If you take a look at the image below,
The image on the left is what is displaying at the moment,
the image in the middle is what I would like my menu to look like,
The image on the right is just a template to show you what I mean.
So basically the first UL will display, the second UL will display, in one row, then the third UL will be drawn just below the first UL, and then the fourth UL will be drawn below the second UL.
Add this to your CSS:
ul:nth-child(2n-1) {
float:left;
margin: 0;
}
ul:nth-child(2n) {
margin-left: 150px; /* Or how many px you want */
}
JSFiddle
You can try float left and float right, so
<ul class="columnLeft"> 1. ....</ul>
<ul class="columnRight"> 2. ....</ul>
<ul class="columnLeft"> 3. ....</ul>
<ul class="columnRight"> 4. ....</ul>
with stylesheet
columnLeft { float: left;}
columnRight { float: right;}
At your picture, the first UL and the second UL have different heights and the preceding ULs are directly sticked to the bottom of the upper one.
This is why you may create "columns" by classing-left/right.
Or use this sample
<style>
.category-list{
width: 300px;
background-color: #CCC;
}
body {
background-image: url("images/background.gif");
}
.red{
border: solid 1px red;
}
.green{
border: solid 1px green;
}
.blue{
border: solid 1px blue;
}
.yellow{
border: solid 1px yellow;
}
.left{
float: left;
}
.right{
float: right;
}
</style>
<div class="category-list">
<div class="left">
<ul class="red">
<li>Item 1-1</li>
<li>Item 1-2</li>
<li>Item 1-3</li>
</ul>
<ul class="green">
<li>Item 2-1</li>
<li>Item 2-2</li>
<li>Item 2-3</li>
<li>Item 2-4</li>
<li>Item 2-5</li>
</ul>
</div>
<div class="right">
<ul class="blue">
<li>Item 3-1</li>
<li>Item 3-2</li>
</ul>
<ul class="yellow">
<li>Item 4-1</li>
<li>Item 4-2</li>
<li>Item 4-3</li>
</ul>
</div>
firstly float your <ul>'s
give them a width e.g. width: 50%; for two columns, width: 33% for 3 columns
finally clear the outer div category-list so that your layout is maintained and doesn't messup the rest of the page.
here it is in its entirety:
.category-list:after{
clear: both;
display:block;
content: '';
}
.category-list ul{
float:left;
width: 50%
}

How can I horizontally center an element with siblings, and retain the flow?

Current Render: http://i.imgur.com/UNPCOfc.pngDesired Render: http://i.imgur.com/8t6c2XM.png
Hello,
In the example below, I would like my logo element (id="logo") to appear between my 3rd and 4th li element. That is, I want to make it appear exactly in the center of its parent, but still reside in the normal flow with its siblings.
I cannot simply place the logo element in the correct position, because the li elements are automatically generated and are of an unknown amount.
A CSS-only solution would be preferable, if possible.
Thanks!
<style type="text/css">
ul {
width: 100%;
display: table;
}
li {
display: table-cell;
}
#logo {
width: 100px;
height: 100px;
background-color: black;
}
</style>
<ul>
<li>Nav 1</li>
<li>Nav 2</li>
<li>Nav 3</li>
<li>Nav 4</li>
<li>Nav 5</li>
<li>Nav 6</li>
<li id="logo"></li>
</ul>
As CSS solution you can do it like the following code:
Note: you need to add different id attribute for each li element
<style type="text/css">
ul {
display: block;
width: 700px;
overflow: hidden;
zoom: 1;
}
li {
width: 100px;
}
li#menu-item-80,
li#menu-item-81,
li#menu-item-82,
li#logo {
float: left;
}
li#menu-item-83,
li#menu-item-84,
li#menu-item-85 {
float: right;
}
#logo {
width: 100px;
height: 100px;
background-color: black;
}
</style>
<ul>
<li id="menu-item-80">Nav 1</li>
<li id="menu-item-81">Nav 2</li>
<li id="menu-item-82">Nav 3</li>
<li id="menu-item-83">Nav 4</li>
<li id="menu-item-84">Nav 5</li>
<li id="menu-item-85">Nav 6</li>
<li id="logo"></li>
</ul>
As Javascript jQuery solution, you can reorder menu items by appending the last item after the third item as the following jQuery code
<script>
jQuery(document).ready(function ($) {
$('ul li:eq(2)').after($('li#logo'));
});
</script>