I know the title is too general. I couldn't find a specific title.
Here is the sample https://jsfiddle.net/Exlord/1soagsL5/
HTML
<ul>
<li>item1</li>
<li>item1</li>
<li>item with submenu >
<ul>
<li>item1</li>
<li>item1</li>
</ul>
</li>
<li>item1</li>
<li id='clickable'>item1</li>
</ul>
JavaScript
var el = document.getElementById('clickable');
el.addEventListener('click', function(e) {
console.log(e.target);
}, false);
CSS
ul {
list-style: none;
margin: 0;
padding: 0;
width: 200px;
max-width: 100%;
}
li {
background: gray;
padding: 5px;
border: solid 1px black;
position: relative;
}
li:hover > ul {
display: block;
}
#media all and (min-width: 481px) {
ul ul {
display: none;
position: absolute;
left: 100%;
top: 0;
}
}
#media all and (max-width: 480px) {
ul ul {
display: none;
}
}
Try it, it's a very simple menu, hover the middle item item with submenu, a simple submenu will be shown with simple CSS :hover.
Click on the last item, it has a click event, it will fire correctly.
Now open this in Chrome's mobile device mod with touch simulation.
Click/touch the item with submenu, the submenu will open inside the parent element. This is the expected behavior.
Now click/touch the last element. The click event will not fire.
How can I fix this with CSS only hover?
UPDATE : As far as I can tell the problem is that on first touch the last hovered element (li with submenu) gets unhovered and the submenu ul gets hidden and the parent ul's height shrinks and the li element that was under the touched point moves up, so its not under the touched point anymore and it does not get clicked/touched !!!!
I think you figured out the cause on your own. The click target does seem to move away before event reaches the element.
The easiest solution I see is to use some supplementary Javascript to open and close the submenu on clicks. You use Javascript for the #clickable event anyway so a little more won't be detrimental, just as long as you keep the :hover for cases where Javascript is fails to load.
Original Answer
Touch devices do not have a hover state, due to the hardware
interface. Browser makers chose a compromise to allow for sites which
rely on it. Whenever a hover event/style is defined for an element the
first tap will trigger that effect instead of the click. A second tap
should, at least in most cases, trigger the original click event.
For your particular case you don't have a ul within the
li#clickable, but the :hover is still detected and the browser
behaves as it was designed. Excluding your #clickable from the hover
event will theoretically fix it (I am not able to test it myself at
this time).
li:not(#clickable):hover > ul {
display: block;
}
Related
I have a navigation bar I've built with a few links in it (using a ul with li and anchors) and I'm trying to figure out how to make certain links dropdowns with more links inside of them. I tried following the w3schools example of dropdowns but it seems like my links are just "scrunching" together. Here's the code:
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
<nav class="main-nav-container">
<ul>
<div class="dropdown">
<li>
Climb
<div class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</li>
</div>
<li>News</li>
<li>Events</li>
<li>About</li>
<li>Donate</li>
<li>Merchandise</li>
</ul>
</nav>
What it looks like on my end is that the links are all scrunched together. I want it so that the dropdown appears on hover (so, display changes from none to block), but the actual content of the dropdown is appearing inline with the navigation links instead of underneath like it should be. What am I missing/doing wrong?
I created a stackblitz for you. Is this what you're looking for?
You can make you content display: flex; while using flex-direction: column; instead of display: block;.
If you want the dropdowns to animate in and out eventually, you'll need to use javascript unless you're a real css wizard. Basically, you'll add a visible class on mouseenter that changes the dropdown from display: none to display: block and sets the starting state of your animation, like opacity: 0. Then, after a requestAnimationFrame, you add an in class that sets the final state of your animation, like opacity: 1. The requestAnimationFrame is needed because going from none to block causes the browser to cancel any css animations.
The close animation is the same principle: you remove the in class on mouseout, then after a timeout for however long your animation is, you remove the visible class.
I want to be able to turn a simple unordered list into a nice menu when on mobile:
<ul class="jumpToList list-inline">
<li>Buttons</li>
<li>Select</li>
<li>Input</li>
<li>Checkboxes & Radios</li>
<li>Switches</li>
</ul>
So when I'm on mobile the above gets turned into a simple menu with the 3 bars when then folds down the links.
Similar to how the Bootstrap navigation menu works, but so it doesn't conflict with this.
I ideally want to use the built in stuff with Bootstrap for this, good example of what i am after:
http://ux.mailchimp.com/patterns/forms
If you shrink the browser you will see that list turn into a menu on mobile.
Thanks
Some simple modifications to your HTML, media-queries and Javascript should allow you to replicate this behaviour.
I would suggest that you begin by creating the media-query to alter the applied styles based on device width.
CSS - Mobile first
.list-inline {
display: none;
visibility: hidden;
}
.list-inline-active {
display: block;
visibility: visible;
}
.list-inline li {
display: block;
}
#media (min-width: 600px) {
.list-toggle {
display: none;
}
.list-inline {
display: block;
visibility: visible;
}
.list-inline li {
display: inline-block;
}
}
HTML - Add toggle button/icon
<button class="list-toggle">Show list</button>
Javascript/jQuery
$('.list-toggle').click(function(){
$('.list-inline').toggleClass('list-inline-active');
});
This method simply uses a button to toggle a class on the unordered-list element. The toggled class contains styles to make the list visible on mobile.
I've created a simple JSFiddle example to show this in action.
It's worth noting that this behaviour is almost entirely replicable without the use of Javascript at all. It would involve the use of checkboxes and the ':checked' pseudo selector. However Bootstrap 3 does use Javascript.
I hope this helps.
I'm trying to create a drop-down menu. I had it working for a minute.
My code is as follows:
<nav id="nav">
<ul>
<li class="subNav">Some Page1
<ul>
<li>Related Page1<li>
<li>Related Page2<li>
</ul>
<li>
</ul>
</nav>
My CSS is as follows:
#nav li.subNav ul{
display: none;
}
#nav li.subNav:hover ul{
display: block;
}
I have three CSS files that relate to this page. One is basically a web-kit for font, and the other two are bowlerplate.css and my custom file customFile.css. The tag <#nav li.subNav:hover ul> show up in customFile.css, and <#nav li.subNav ul> diplays in bout custom and boilerplate when I check computed styles.
There are two things I wish to fix; the submenu lines up horizontally (I need it to go vertical) and the submenu isn't hidden. I had to nest /li tag around the ul, so that took care of one problem (they're now aligned under the parent tag).
I also noticed that the height and width have changed on my parent li. I understand it expanding to accommodate the list items, but the increased height seems a little odd.
Here's my solution to the above problem
#nav li.subNav:hover ul li {
visibility: visible;
width: 171px;
padding: 0;
cursor: pointer;
float: none !important;
display: block !important;
}
This works correctly for hover, but I am after two other things:
1) a more scalable, generalized solution: every time I add a link and paired paragraph I don't want to have to also include specific CSS for each addition. It seems like I should be able to create the same behavior for each paired link and paragraph generally and apply it to all of the pairs. What I have seems very inefficient.
2) I'd like to also create the same behavior as the hover, but for a click and make it scalable and generalized (as #1 above). The desired behavior is click on link -> paired paragraph appears, click on link again -> paired paragraph disappears again (or something very similar).
Note: I want both click and hover because hover will work for a desktop, but not mobiles. If someone is on a smart phone they can use the click. I'd like solutions to be responsive, to avoid jQuery, and to use CSS only if possible.
Here is what I have now (using only two pairs links and paragraphs, for simplicity):
Markup:
<a id="a-1">link1</a>
<p id="p-1">para1</p>
<a id="a-2">link2</a>
<p id="p-2">para2</p>
CSS:
#a-1,#a-2{
display: block;
}
#p-1,#p-2{
display: none;
}
#a-1:hover ~ #p-1 ,#a-2:hover ~ #p-2{
display: block;
}
Here is a demo: http://jsfiddle.net/CzpZ6/
You can use :target attribute, in conjunction with specific IDs (see demo)
HTML
<a class="focus" href="#p1">
Click me or hover me
</a>
<p id="p1">I'm hidden</p>
<a class="focus" href="#p2">
Click me or hover me
</a>
<p id="p2">I'm another hidden paragraph</p>
CSS
.focus {
display: block;
}
.focus:focus, .focus:hover {
background-color: pink;
}
.focus + p {
display: none;
}
.focus:hover + p, p:target {
display: block;
}
Here is your generalized solution:
http://jsfiddle.net/8vA32/
a{
display: block;
}
p{
display: none;
}
a:hover + p {
display: block;
}
If you use plus that will select all the p values until it finds another element. So in this case + can work.
For mobile part you can use this:
/* #### Desktops #### */
#media screen and (min-width: 1024px){
/* some CSS here */
a{
display: block;
}
p{
display: none;
}
a:hover + p {
display: block;
}
}
#media handheld, only screen and (max-width: 480px), only screen and (max-device-width: 480px)
{
a{
display: block;
}
p{
display: none;
}
a:active + p {
display: block;
}
}
On desktop part it will trigger hover, on mobile part it will trigger click.
Example:
http://jsfiddle.net/8vA32/
I believe a jQuery solution is your ONLY solution. For both hover and touch events to work you will need to turn off click and bind touch. here is a piece of script I use in a Nav menu for tablet size when users may be using either touch or mouse. Perhaps if you know js you can modify this script to fit your need:
function medMenu() {
//reset the menu in case it's being resized from a small screen
// unbind click events
jQuery('.menuToggle a').off('click');
jQuery('.topMenu h3').off('click');
// remove any expanded menus
jQuery('.expand').removeClass('expand');
// remove the span tags inside the menu
jQuery('.topMenu h3').find('span.indicator').remove();
// remove the "menu" element
jQuery('.menuToggle').remove();
//check to see if the device supports touch
//we'll use touch events instead of click as it will allow us
//to support both a CSS-driven hover and touch enabled
//menu for this screen range
if ('ontouchstart' in document.documentElement)
{
//find all 'hover' class and strip them
jQuery('.topMenu').find('li.hover').removeClass('hover');
//add touch events to submenu headings
jQuery(".topMenu h3").bind('touchstart', function(e){
//find the current submenu
var currentItem = $(this).siblings('.submenu');
//remove the expand class from other submenus to close any currently open submenus
jQuery('ul.submenu').not(currentItem).removeClass('expand');
//open the selected submenu
$(this).siblings('.submenu').toggleClass('expand');
});
//close submenus if users click outside the menu
jQuery('html').bind('touchstart', function(e) {
jQuery('.topMenu').find('ul.submenu').removeClass('expand');
});
//stop clicks on the menu from bubbling up
jQuery('#mainNav').bind('touchstart', function(e){
e.stopPropagation();
});
}
//indicate current window state
windowState = 'medium';
}
Change out the id tag for a generic class
JSfiddle Demo
HTML
<a class="a1">link1</a>
<p>para1</p>
<a class="a1">link1</a>
<p>para2</p>
CSS
.a1 {
display: block;
}
p {
display: none;
}
.a1:hover + p, /* the first p after an .a1 anchor */
.a1:focus + p {
display: block;
}
I have a simple menu with a hover state:
<nav id="menu">
<div>Home</div>
<div>
1
<nav>
<div>1.1</div>
<div>1.2</div>
<div>1.3</div>
</nav>
</div>
</nav>
CSS:
#menu > div > nav {
display: none;
position: absolute;
z-index: 9999;
}
#menu > div:hover > nav {
display: block;
}
But the :hover state never ends. After another tap (somewhere else) :hover still stays. Can I get around this without javascript? (Fiddle)
It seems like the only way to get rid of :hover is to :focus somewhere (element.focus()) or hover on something else.
No. Hover states are partially broken on some mobile devices simply because you can't hover over an element. You will have to use javascript.
You can use the hover media query to disable hover states on iOS:
https://developer.mozilla.org/en-US/docs/Web/CSS/#media/hover