Costa Michailidis
Costa Michailidis

Reputation: 8178

Forcing mobile devices to activate :hover CSS properties on first touch and activate link on second touch

: )

So, I'm trying to solve a hover effect issue. I have tooltips on some of my links. Code looks like this:

<a href="https://wikipedia.org/wiki/Space_Shuttle_Atlantis">
  <h6 class="has-tip">Space Shuttle
    <p class="tip">The space shuttle was invented by Santa Claus</p>
  </h6>
</a>

And the CSS is a bit more involved:

.tip {
  display: block;
  position: absolute;
  bottom: 100%;
  left: 0;
  width: 100%;
  pointer-events: none;
  padding: 20px;
  margin-bottom: 15px;
  color: #fff;
  opacity: 0;
  background: rgba(255,255,255,.8);
  color: coal;
  font-family: 'Ubuntu Light';
  font-size: 1em;
  font-weight: normal;
  text-align: left;
  text-shadow: none;
  border-radius: .2em;
  transform: translateY(10px);
  transition: all .25s ease-out;
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.28);
}

.tip::before {
  content: " ";
  display: block;
  position: absolute;
  bottom: -20px;
  left: 0;
  height: 20px;
  width: 100%;
}

.tip::after { /* the lil triangle */
  content: " ";
  position: absolute;
  bottom: -10px;
  left: 50%;
  height: 0;
  width: 0;
  margin-left: -13px;
  border-left: solid transparent 10px;
  border-right: solid transparent 10px;
  border-top: solid rgba(255,255,255,.8) 10px;
}

.has-tip:hover .tip {
  opacity 1;
  pointer-events auto;
  transform translateY(0px);
}

Now, on desktop this works wonderfully. You hover over the tiny title and you get a pretty looking tooltip, then if you click anywhere on the title or tooltip (unless you decide to put yet another link in the paragraph which works separately and nicely) you activate the link. Yay : )

Now on mobile, the whole thing gets funky. Touching just activates the link. If you have slow internet, or iOS, you might glimpse the tooltip just as the next page loads.

I would like the following behavior:

  1. User taps on tiny title (h6) which has class (has-tip)
  2. If this is the first tap, the tooltip shows, and nothing else happens. 3)
  3. If the tooltip is already showing when they tap (as in a subsequent tap) then the link is activate and the new page loads.

Any ideas how I might implement this? No jQuery if possible.

Upvotes: 1

Views: 1873

Answers (2)

Domino
Domino

Reputation: 6768

One way to do it is to save a reference to the last clicked has-tip link and to apply a class to it which forces the tip to show. When you click on a link and it matches the the last one clicked, you let the event pass.

EDIT: oh, I forgot to mention you might need a classList shim for old IE.

JSFiddle link.

HTML

<a href="http://jsfiddle.net/1tc52muq/5/" class="has-tip">
  JSFiddle<span class="tip">Click for some fun recursion</span>
</a><br />
<a href="http://google.com" class="has-tip">
  Google<span class="tip">Click to look for answers</span>
</a>

 JS

lastTip = null;

if(mobile) {
    var withtip = document.querySelectorAll(".has-tip");

    for(var i=0; i<withtip.length; ++i) {
        withtip[i].addEventListener("click", function(e) {
            if(lastTip != e.target) {
                e.preventDefault();
                if(lastTip) lastTip.classList.remove("force-tip");
                lastTip = e.target;
                lastTip.classList.add("force-tip");
            }
        });
    }
}

 CSS

.has-tip {
    position: abolute;
}
.tip {
    display: none;
    position: relative;
    left: 20px;
    background: black;
    color: white;
}

.has-tip:hover .tip, .force-tip .tip {
    display: inline-block;
}

Upvotes: 3

al .js
al .js

Reputation: 206

Edit: Just wanted to say that Jacques' approach is similar, but much more elegant.

On touch devices, you'll need to make a click/tap counter:

1) On first tap of any link, store the link and display the hover state.

2) On another tap, check to see if it's the same as the first, and then perform the normal tap action if it is. Otherwise, clear any existing hovers, and set the new tap target as the one to count.

3) Reset / clear any hovers if you tap on non-links.

I've made a rudimentary JSFiddle that console.logs these actions. Since we're not using jQuery, I didn't bother with adding/removing CSS classes on the elements.

Also, sorry about not writing taps instead of clicks.

var clickTarget;

var touchDevice = true;

if(touchDevice) {
    var links = document.getElementsByTagName('a');
    for(var i=0; i<links.length; i++) {
      links[i].onclick = function(event) {
        event.stopPropagation();
        event.preventDefault();  // this is key to ignore the first tap
        checkClick(event);
      };
    };

    document.onclick = function() {
      clearClicks();
    };
}


var checkClick = function(event) {
    if(clickTarget === event.target) {
      // since we're prevent default, we need to manually trigger an action here.
      console.log("Show click state and also perform normal click action.");
      clearClicks();
    } else {
      console.log("New link clicked / Show hover");
      clickTarget = event.target;
    }
}

var clearClicks = function() {
  console.log("Clearing clicks");
  clickTarget = undefined;
};

http://jsfiddle.net/doydLt6v/1/

Upvotes: 3

Related Questions