Skuami
Skuami

Reputation: 1624

CSS hover on mobile

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

Answers (3)

MLK.DEV
MLK.DEV

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

AleshaOleg
AleshaOleg

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

Ionut Necula
Ionut Necula

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

Related Questions