Reputation: 1624
I've created a web application where a use can vote images. When the user hovers with the mouse over a "gridItem" I'll hide an overlay layer and display an other overlay layer with two buttons on it. To get it working on touch devices I also added the :focus pseudo classes.
This works perfectly fine in any desktop browser and it works sort of on touch. The problem I'm facing now is when I try to click on a button on the "hover" overlay, this overlay disappears before I get the click event.
Here's some html code and my css classes:
<div class="gridItem">
<img class="..." src="..." alt="">
<div class="likeLabelOverlay">
small content
</div>
<div class="likeButtonOverlay ghost-center">
<div>
<h3>large content</span>
<button type="button" id="..." class="btn btn-default">button 1</button>
<button type="button" id="..." class="btn btn-default">button 2</button>
</div>
</div>
</div>
I handle the hover on the gridItem:
.gridItem:hover .likeButtonOverlay, .gridItem:focus .likeButtonOverlay {
display: block;
}
.gridItem:hover .likeLabelOverlay, .gridItem:focus .likeLabelOverlay {
display: none;
}
Upvotes: 0
Views: 18155
Reputation: 453
We just had to solve this issue for a client at the agency I work with.
I'll also describe the code here so just in case anything happens with the fiddle, it's here in perpetuity.
The Fiddle
https://jsfiddle.net/GrafikMatthew/7nx53twL/
The Libraries
I'm using the 2.2 jQuery library for this, though I'm pretty sure an earlier version could be used if needed.
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
The CSS
This is just a barebones presentation so these are the minimum styles required for this approach. You can modify these all you want to match your page design.
<style type="text/css">
.nav-wrapper ul
{
margin: 0;
padding: 0;
list-style-type: none;
}
.nav-wrapper > ul::after
{
content: "";
clear: both;
display: block;
float: none;
height: 0;
}
.nav-wrapper > ul > li
{
display: block;
float: left;
padding: 10px;
position: relative;
}
.subnav-wrapper
{
display: none;
background: #000;
position: absolute;
top: 100%;
left: 0;
}
.subnav-wrapper > ul > li {
padding: 10px;
}
.subnav-wrapper > ul > li > a
{
white-space: nowrap;
color: #fff;
}
.nav-wrapper > ul > li:hover
, .nav-wrapper > ul > li.hover
{
background: #000;
}
.nav-wrapper > ul > li:hover > a
, .nav-wrapper > ul > li.hover > a
{
color: #fff;
}
.nav-wrapper > ul > li:hover > .subnav-wrapper
, .nav-wrapper > ul > li.hover > .subnav-wrapper
{
display: block;
}
</style>
The HTML
I'm using a fairly straight forward markup for this menu structure, though since everything aside from the list and anchors, targeting is done via class name, so the elements can be swapped out for ones that work better for your project.
<div class="nav-wrapper">
<ul class="nav">
<li><a href="#link-a">Link A</a>
<div class="subnav-wrapper">
<ul class="subnav">
<li><a href="#link-a-a">Sublink A A</a></li>
<li><a href="#link-a-b">Sublink A B</a></li>
<li><a href="#link-a-c">Sublink A C</a></li>
</ul>
</div>
</li>
<li><a href="#link-b">Link B</a></li>
<li><a href="#link-c">Link C</a>
<div class="subnav-wrapper">
<ul class="subnav">
<li><a href="#link-c-a">Sublink C A</a></li>
<li><a href="#link-c-b">Sublink C B</a></li>
<li><a href="#link-c-c">Sublink C C</a></li>
</ul>
</div>
</li>
<li><a href="#link-d">Link D</a></li>
</ul>
</div>
<hr />
<div class="dummy">
<p>Dummy content...</p>
</div>
The JS
I'm using a standard anonymous enclosure and exposing jQuery
via $
.
<script type="text/javascript">
(function($){
function MH_ResetAll() {
$( '.nav-wrapper .hover' ).removeClass( 'hover' );
}
function MH_Init() {
// >
// > Environment
// >
$( document ).on( 'touchstart', function( e ) {
MH_ResetAll();
} );
// >
// > Primary Navigation
// >
$( '.nav-wrapper > ul > li > a' ).on( 'touchstart', function( e ) {
// Cancel default event behaviors...
e.preventDefault();
e.stopPropagation();
// Hook the important elements for this event...
var ThisA = $( this );
var ThisParentLI = $( ThisA.parents( 'li' ).get( 0 ) );
// Is there a subnav-wrapper in the parent list item?
if( ThisParentLI.find( '.subnav-wrapper').length ) {
// Is the parent list item already hovered?
if( ThisParentLI.hasClass( 'hover' ) ) {
// Handle the event as a link click...
window.location.href = ThisA.attr( 'href' );
} else {
// Reset all other hover states...
MH_ResetAll();
// Add the hover class to the parent list item...
ThisParentLI.addClass( 'hover' );
}
} else {
// Handle the event as a link click...
window.location.href = ThisA.attr( 'href' );
}
} );
// >
// > Secondary Navigation
// >
$( '.subnav-wrapper' ).on( 'touchstart', function( e ) {
// Prevent secondary navigation from bubbling up...
e.stopPropagation();
} );
$( '.subnav-wrapper > ul > li > a' ).on( 'touchstart', function( e ) {
// Cancel default event behaviors...
e.preventDefault();
e.stopPropagation();
// Hook the important elements for this event...
var ThisA = $( this );
// Handle the event as a link click...
window.location.href = ThisA.attr( 'href' );
} );
}
$( document ).on( 'ready', function() {
MH_Init();
} );
} )( jQuery );
</script>
Upvotes: 0
Reputation: 2211
Mobile devices support :active
. With your :hover
use :active
. Here a demo.
.gridItem:hover .likeButtonOverlay, .gridItem:active .likeButtonOverlay {
display: block;
}
.gridItem:hover .likeLabelOverlay, .gridItem:active .likeLabelOverlay {
display: none;
}
<div class="gridItem">
<img class="..." src="..." alt="">
<div class="likeLabelOverlay">
small content
</div>
<div class="likeButtonOverlay ghost-center">
<div>
<h3>large content</span>
<button type="button" id="..." class="btn btn-default">button 1</button>
<button type="button" id="..." class="btn btn-default">button 2</button>
</div>
</div>
</div>
Upvotes: 2
Reputation: 11480
There is no hover on mobile. What you can do is bind some events with jquery on touch.
Like this:
$(document).ready(function() {
$('.gridItem').bind('touchstart touchend', function(e) {
e.preventDefault();
$(this).toggleClass('hover_effect');
});
});
CSS
.gridItem:hover, .gridItem.hover_effect {
rule:properties;
}
Upvotes: 2