How to simulate :active css pseudo class in android on non-link elements?

26,183

Solution 1

Based on what @caffein said, here's a full implementation of this:

For all :active code, write CSS rules that look like this.

my-button:active, .my-button.fake-active {
 background-color: blue;
}

Then in your document ready event add this code:

if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
 $(".my-button")
 .bind("touchstart", function () {
     $(this).addClass("fake-active");
 })
 .bind("touchend", function() {
     $(this).removeClass("fake-active");
 });
}

This has the advantage of using the fast native :active class on iOS, and dropping back to JavaScript on Android.

Taken from my blog at http://pervasivecode.blogspot.com/2011/11/android-phonegap-active-css-pseudo.html

EDIT: I've since discovered that buttons can occasionally 'stick' in the fake-active state. The fix for this is to also handle the touchcancel event. E.g. add this to the above..

.bind("touchcancel",
 function() {
  var $this = $(this);
  $this.removeClass("fake-active");
 });

Solution 2

If you don't want to use any script, which adds and removes class for active state of an element, just add empty touchstart event to the body tag:

<body ontouchstart="">

This will tell the android device to handle touch events and pseudo class :active will work correctly on all elements.

Solution 3

No-jQuery version based on Ben Clayton's solution.

EDIT: added "touchmove" event.

function hasClass(ele,cls) {
  return ele.className.match(new RegExp("(\\s|^)"+cls+"(\\s|$)"));
}
function addClass(ele,cls) {
  if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
  if (hasClass(ele,cls)) {
    var reg = new RegExp("(\\s|^)"+cls+"(\\s|$)");
    ele.className=ele.className.replace(reg," ");
  }
}

window.onload = function() {
  if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
    var elements = document.getElementsByClassName("my-button");
    for(var i = 0; i < elements.length; i++) {
      var elm = elements[i];
      elm.addEventListener("touchstart", function() {
        addClass(this, "fake-active");}, false);
      elm.addEventListener("touchmove", function() {
        removeClass(this, "fake-active");}, false);
      elm.addEventListener("touchend", function() {
        removeClass(this, "fake-active");}, false);
      elm.addEventListener("touchcancel", function() {
        removeClass(this, "fake-active");}, false);
    }
  }
}

Solution 4

The ":active " pseudo class is triggered when you actually click or press an element. A workaround for smartphones is to use the Javascript events: "ontouchstart" & "ontouchend".

Try using ontouchstart to modify the style and ontouchend to actually trigger the action.

Solution 5

Since I can't comment, I'm going to add another answer here.

Nadzeya suggested the following solution:

<body ontouchstart="">

This does work as described, but I believe it may also have an unintended consequence.

There has been a problem on our site where buttons would occasionally stop working. In fact, the button would change colors (as if it was pressed) but the click event wouldn't fire. Even submit buttons on forms would fail to submit the form (no Javascript involved), even after appearing pressed.

Today, I saw the problem again. On a whim, I removed this attribute and the problem went away. I then added it again and the problem came back.

Since I can't reproduce the problem reliably, I can't be certain that this was the cause, but for now I'm going to leave the tag off and solve the :active problem another way.

Share:
26,183
chas s.
Author by

chas s.

Updated on March 29, 2020

Comments

  • chas s.
    chas s. about 4 years

    I'd like to be able to mimic the behavior of the :active pseudo class on all elements in Android webkit. Currently, the :active syntax only works on a elements (links). Nearly all of the actionable elements in the app I'm working on are something other than a standard link tag. iOS webkit supports :active on all elements.

    /* works on both android iOS webkit */
    a:active {
        color: blue;
    }
    /* works on iOS webkit, does not work on android webkit */
    div:active {
        color: red;
    }
    

    I've found a couple of resources [1,2] that solve similar problems, but they're both a bit heavy, and I'm wondering if there's a lighter weight solution that I'm just not able to find.

    1. http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
    2. http://code.google.com/intl/ro-RO/mobile/articles/fast_buttons.html
  • monsieur_h
    monsieur_h about 12 years
    It uses jQuery. A response without any external library would've been simplier.
  • MikeMurko
    MikeMurko over 11 years
    @caffein, it probably wouldn't have been "simplier". have you seen the native JS DOM api? also, you would be ruined with cross browser support. the whole point of jquery is to "simplierfy"
  • Titan
    Titan about 11 years
    Wow this fixed my issue with iOS not triggering active state! Thank you!
  • Codeversed
    Codeversed about 11 years
    This worked well for css :active to actually work correctly. If your using Jsoup this can easily be added like: final Document html = Jsoup.parseBodyFragment(content); html.body().attr("ontouchstart","");
  • Jad Joubran
    Jad Joubran almost 11 years
    yeah but using jQuery on mobile is a bad idea
  • unexist
    unexist about 10 years
    The whole thing is a bit weird, :active behaves like :hover on touch devices <Android 4.4, with 4.4 it stopped working properly and most of the time just keeps the active state until you touch the element again.Wonder if the current behaviour is a bug or if it was a bug before.
  • Christopher
    Christopher almost 10 years
    Yeah I'm suffering from the "stuck in active state" issue on Android now - super annoying. Why in the world did Android not enable the :active behavior?!
  • Boris van Schooten
    Boris van Schooten over 9 years
    I am using this now. Note, this.hasClass must be ele.hasClass. Still, the hasClass/addClass/removeClass code didn't work for me. Instead I used: developer.mozilla.org/en-US/docs/Web/API/element.classList
  • Robert Moore
    Robert Moore about 6 years
    This will disable scrolling as well, which is not what the OP wanted.