Clicking on buttons through a container mask - html

I have a container with some clickable items, and at the bottom of the container, there is a gradient that I'm adding with .container:after to create a fade effect. I would still like the items at the bottom to be clickable, but also to be affected by the fade, so putting the fade behind the clickable items won't work.
http://jsfiddle.net/mwjj7hff/1/
HTML:
<div class="container">
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
</div>
CSS:
.container {
border: 1px solid #ccc;
font-family: sans-serif;
height: 400px;
overflow: hidden;
position: relative;
width: 200px;
}
.container:after {
background: linear-gradient(to bottom, rgba(255, 255, 255, .3) 0%, white 100%);
bottom: 0;
content: " ";
height: 150px;
display: block;
position: absolute;
width: 100%;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
cursor: pointer;
margin: 3px;
padding: 3px;
text-align: center;
}
li:hover {
background: #99d;
}

A quick, easy solution would be to add pointer-events: none to the pseudo-element.
In doing so, you can essentially click through it:
MDN - pointer-events: none
The element is never the target of mouse events; however, mouse events may target its descendant elements if those descendants have pointer-events set to some other value. In these circumstances, mouse events will trigger event listeners on this parent element as appropriate on their way to/from the descendant during the event capture/bubble phases.
Updated Example
.container:after {
background: linear-gradient(to bottom, rgba(255, 255, 255, .3) 0%, white 100%);
bottom: 0;
content: " ";
height: 150px;
display: block;
position: absolute;
width: 100%;
pointer-events: none;
}
Browser support for pointer-events can be found here - currently 87.29%.

Related

How to I prevent dropdown menu from closing when moving cursor away from parent element?

What's a good solution in this case if I want to prevent dropdown menu from closing as mouse moves away from parent to dropdown menu. Dropdown menu should be further away from parent li element but should not close when I want to access dropdown menu. If cursor is moved away from nav completely then dropdown should close.
My html
<nav>
<ul class="primary-menu">
<li>item
<ul class="sub-menu">
<li>item 6</li>
<li>item 7</li>
</ul>
</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
</ul>
</nav>
My SCSS
nav {
.primary-menu {
display: flex;
gap: 24px;
position: relative;
li {
color: black;
.sub-menu {
position: absolute;
display: none;
background: red;
border-radius: 4px;
padding: 12px 24px;
top: calc(100% + 24px);
&:before {
position: absolute;
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 0 12px 12px 12px;
border-color: transparent transparent red transparent;
top: -12px;
}
li {
padding: 8px 12px;
}
}
&:hover {
.sub-menu {
display: block;
}
}
}
}
}
Example
https://jsfiddle.net/xs9wzr5h/2/
I've tried to push dropdown menu away with border-top: solid 24px transparent; but with this solution border-radius disappears from top corners. With this solution I tried to create fake padding so cursor will be always on parent/dropdown element which prevents dropdown from closing as cursor is moved from one element to another.
I also tried to use outline but this doesn't push element away from parent and can't be hovered.
I hope that my explanation was understandable. Cheers!
I managed to fix this with adding an after element to sub-menu
&:after {
position: absolute;
content: "";
width: 100%;
height: 26px;
top: -26px;
left: 0;
}
This will add a "fake padding" rectangle to top of div which on hover will keep sub-menu open.

Detect if a list has overflown and give it a class, in css

I would like to do this in CSS if this is possible with no javascript.
I have a list with x amount of items, it could anything. Here is a picture
The container is a % of the screen, so as i resize, the ul gets smaller, therefore the list items go on a new line.
What I would like to do is give the ul an text alignment of center if there is 1 line and text align of left if there is 2.
Is this possible with css only?
I cant do media queries as the number of items could be anything.
Are you looking for something like this?
body {
background: #11b5c3;
font-family: sans-serif;
padding: 50px;
}
h1 {
color: #fff;
text-align: center;
font-weight: 100;
}
/*
.container {
border-top: 1px solid #fff;
padding: 10px 0;
margin: 0 auto;
list-style: none;
display: flex;
justify-content: center;
flex-wrap: wrap;
width:75%;
}
.container li {
background: #fefefe;
margin: 3px;
padding: 5px 10px;
border-radius: 3px;
font-size: 14px;
color: #999;
}*/
.container {
border-top: 1px solid #fff;
padding: 10px 0;
margin: 0 auto;
list-style: none;
/* display:flex; */
/*justify-content:center;*/
flex-wrap: wrap;
max-width: 500px;
text-align: justify;
}
.container li {
background: #fefefe;
;
margin: 3px 0;
padding: 5px 10px;
border-radius: 3px;
font-size: 14px;
color: #999;
display: inline-block;
font-size: 16px;
}
<h1>Tools</h1>
<ul class="container">
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
I am piggy-backing off #Mobarak Ali but I think in this case you want to use grid and not flexbox. If you use flexbox with flexwrap: wrap; and justify-content: center; the items will always be centered. But the OP wants the items to be centered if they don't wrap but then justify on the left side on each subsequent row. Because grid is used for 2d layouts it can achieve this pretty easily.
Add or delete list items to see the effect. Here is a codepen if you prefer that.
https://codepen.io/zenRyoku/pen/rgWBEp
body {
background: teal;
font-family: sans-serif;
padding: 50px;
}
h1 {
color: #fff;
text-align: center;
font-weight: 100;
}
.container {
border-top: 1px solid #fff;
padding: 10px 0;
margin: 0 auto;
list-style: none;
display: grid;
justify-items: center;
grid-template-columns: repeat( auto-fit, minmax(50px, 1fr) );
grid-gap: 1rem;
max-width: 500px;
}
.container li {
width: 50px;
background: #fefefe;
padding: 5px 10px;
border-radius: 3px;
font-size: 14px;
color: #999;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>Tools</h1>
<ul class="container">
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</body>
</html>

Style the Child and not Grandchild?

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;
/*...*/
}

z-index & width issue with nested absolute, fixed and relative elements

I am building a complex webapp using React and I'm trying to figure out the smartest way to handle a complex positioning and layering situation.
I'm wondering if I need to rethink my entire structure or just tweak some css values.
The code below explains my issues:
aside {
position: absolute;
top: 0;
left: 0;
width: 20%;
height: 100vh;
background: blue;
color: white;
}
main {
position: absolute;
overflow: hidden;
background-image: url('https://i.ytimg.com/vi/6sta6Gkpgcw/maxresdefault.jpg');
background-size: cover;
top: 0;
left: 20%;
width: 80%;
height: 100vh
}
.page-wrap {
position: relative;
width: 100%;
height: 100vh;
overflow: auto;
}
.overlay {
position: fixed;
z-index: 1;
padding: 40px;
color: white;
font-size: 24px;
width: calc(80% - 80px);
height: 100vh;
background-color: rgba(0, 0, 0, .5);
}
ul {
position: relative;
z-index: 2;
list-style: none;
color: white;
font-size: 24px;
line-height: 2em;
padding-top: 100vh;
}
ul li {
display: inline-block;
width: 200px;
height: 200px;
text-align: center;
padding: 20px;
background: #ccc;
color: red;
margin: 50px;
}
button {
padding: 10px 30px;
background: green;
color: white;
font-size: 24px;
}
<aside>
SIDEBAR
</aside>
<main>
<section class="page-wrap">
<div class="overlay">
<button>
This needs to be clickable even though the list is on top
</button>
<div>
<h1>My issues here are:</h1>
<ol>
<li>the green button is covered (disabled) by the list</li>
<li>the overlay covers the scrollbar on its parent page-wrap section</li>
</ol>
</div>
</div>
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>6</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>vew</li>
<li>Item</li>
</ul>
</section>
</main>
FIDDLE
My solution was to restructure the DOM so the body had the overflow. I had been trying to avoid this because it's a large webapp with a lot of components and pages, many of which suffered collateral damage, but ultimately, it solved my problem.

Making unordered list scrollable

I have an unordered list which is inside a div tag and initially the list is empty. When items are added on to it, it will expand and I want it to be scroll-able once it the length of the list exceeds that of the web page, i.e I do not want the web page to scroll, I want only the unordered list to scroll. However currently, the scroll bar for my unordered list is not appearing.
My html code is:
<div style="width: 25%; float: right; " class="online_users">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> Online Users
<ul id="ListOfOnlineUsers" style="overflow: auto;height:100%; word-wrap: break-word;" class="list-group">
</ul>
</div>
</div>
</div>
My CSS code is
html{
height: 100%
}
{
margin: 0;
padding: 0;
}
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
height: 100%;
}
a {
color: #00B7FF;
}
.chat
{
list-style: none;
margin: 0;
padding: 0;
}
.chat li
{
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px dotted #B3A9A9;
}
.chat li.left .chat-body
{
/*margin-left: 60px;*/
}
.chat li.right .chat-body
{
/*()margin-right: 60px;*/
}
.chat li .chat-body p
{
margin: 0;
color: #777777;
word-wrap: break-word;
}
.panel .slidedown .glyphicon, .chat .glyphicon
{
/*margin-right: 5px;*/
}
.panel-body
{
overflow-y: scroll;
top: 1em;
left: 1em;
height: 250px;
}
::-webkit-scrollbar-track
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
background-color: #F5F5F5;
}
::-webkit-scrollbar
{
width: 12px;
background-color: #F5F5F5;
}
::-webkit-scrollbar-thumb
{
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
background-color: #555;
}
/* CSS used here will be applied after bootstrap.css */
body, html {
height: 100%;
background-repeat: no-repeat;
background-image: linear-gradient(rgb(154, 145, 162), rgb(12, 97, 33));
}
.card-container.card {
width: 350px;
padding: 40px 40px;
}
.card {
background-color: #F7F7F7;
/* just in case there no content*/
padding: 20px 25px 30px;
margin: 0 auto 25px;
margin-top: 50px;
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.btn {
font-weight: 700;
height: 36px;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
cursor: default;
}
.form-signin input[type=text],
.form-signin button {
width: 100%;
display: block;
margin-bottom: 10px;
z-index: 1;
position: relative;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.btn.btn-signin:hover,
.btn.btn-signin:active,
.btn.btn-signin:focus {
background-color: rgb(12, 97, 33);
}
Set the list's max-height to the height of its parent (or whatever you need it to be) and then set its overflow property to auto.
Here's a quick example:
div{
border:1px solid #000;
font-family:arial;
height:100px;
width:200px;
}
ul{
list-style:none;
max-height:100px;
margin:0;
overflow:auto;
padding:0;
text-indent:10px;
}
li{
line-height:25px;
}
li:nth-child(even){
background:#ccc;
}
<div>
<ul>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>
</div>
Try to add a wrapper and set max-height to the wrapper
Html
<div class="listWrapper">
<ul>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
<li>content</li>
</ul>
</div>
Css
ul, li {
list-style:none;
padding:0;
margin:0;
}
.listWrapper {
max-height:100px;
overflow-y:auto;
}
Fiddle Demo
You can change the height of the ul to max-height: 100vh, that way the ul will always have the size of the viewport.
For browser support check this : http://caniuse.com/#search=vh
In case you want it inside a div that doesn't have the viewport height, follow #Shaggy answer.
With height set to 100% your container will not display scrollbars.
https://developer.mozilla.org/en-US/docs/Web/CSS/overflow
.panel {
width: 200px;
}
.list-group {
overflow: auto;
height: 200px;
}
<div class="online_users">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> Online Users
<ul id="ListOfOnlineUsers" class="list-group">
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
<li>some item</li>
</ul>
</div>
</div>
</div>
You have the right CSS properties defined for class .panel-body but you do not use it in your HTML yet. Move the <ul> into a separate div with the class .panel-body. That should do the trick:
<div style="width: 25%; float: right; " class="online_users">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span> Online Users
</div>
<div class="panel-body">
<ul id="ListOfOnlineUsers" style="height:100%; word-wrap: break-word;" class="list-group">
</ul>
</div>
</div>
</div>
Edit: You should drop the overflow: auto from the <ul> or you get double scroll bars
Edit2: Yet another optimization: set margin: 0 for the <ul> and change the the .panel-body to overflow: auto, so the div's scroll bar is only visible if needed. See my fiddle
No need for the outer div (NOTE this is for horizontal scrollbars. Just change max-width to max-height and overflow-x to overflow-y
ul, li {
list-style:none;
padding:0;
margin:0;
white-space:nowrap;
max-width:300px;
}
ul{overflow-x:scroll;}
CodePen Live Example
Just set the height of your <ul and give it an overflow: scroll;.
That should do it.
Try this >>>
<div class = "list"></div>
and the css property >>>
/* Hide scrollbar for Chrome, Safari and Opera */
.list::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.list {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}