101

I am trying to make a button, such that when the user clicks on it, it changes its style while the mouse button is being held down. I also want it to change its style in a similar way if it is touched in a mobile browser. The seemingly-obvious thing to me was to use the CSS :active pseudo-class, but that didn't work. I tried :focus, and it didn't work too. I tried :hover, and it seemed to work, but it kept the style after I took my finger off the button. All of these observations were on an iPhone 4 and a Droid 2.

Is there any way to replicate the effect on mobile browsers (iPhone, iPad, Android, and hopefully others)? For now, I am doing something like this:

<style type="text/css">
    #testButton {
        background: #dddddd;
    }
    #testButton:active, #testButton.active {
        background: #aaaaaa;
    }
</style>

...

<button type="button" id="testButton">test</button>

...

<script type='text/javascript' src='http://code.jquery.com/jquery-1.6.1.min.js'></script>
<script type='text/javascript'>
    $("*").live("touchstart", function() {
      $(this).addClass("active");
    }).live("touchend", function() {
      $(this).removeClass("active");
    });
</script>

The :active pseudo-class is for desktop browsers, and the active class is for touch browsers.

I am wondering if there is a simpler way to do it, without involving Javascript.

Knu
  • 14,806
  • 5
  • 56
  • 89
Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
  • 2
    Almost every touch browser handles things such as `hover` and `mousedown`/`mouseup` differently, its hard to accommodate them all. – Chad May 19 '11 at 18:39
  • Android and iOS both have :touchstart, :touchmove, :touchend, and :touchcancel pseudoclasses that you can use. – Paul Hanbury May 19 '11 at 18:47
  • 2
    I tried setting styles for the :touchstart and :touchend pseudo-classes and they didn't work on the iPhone or the Droid. @Paul Hanbury, are you sure you are not confusing CSS pseudo-classes with Javascript events? – Elias Zamaria May 19 '11 at 18:59
  • @mikez302 You are right, they are definitely DOM events in both. Sorry. – Paul Hanbury May 19 '11 at 19:03
  • 1
    @mikez302 - I think your right. http://plugins.jquery.com/plugin-tags/touchstart – Doug Chamberlain May 19 '11 at 19:03
  • 2
    I would feel silly submitting this as an answer, but in fact, the answer is "No, it's not possible, you have to use Javascript." What you're asking for isn't part of CSS2 or CSS3. I think the fact that :active doesn't work is a user-agent problem you could potentially report as a bug in the iOS and Android browsers, but just to solve your end-user problem ... yeah, you have to use JS. You could wrap your compatibility code in a [check for ontouchstart support](http://stackoverflow.com/questions/2915833/how-to-check-browser-for-touchstart-support-using-js-jquery). – joelhardi May 19 '11 at 19:57
  • there for exist jQuery mobile. http://api.jquerymobile.com/?s=touch – Ol Sen Apr 15 '13 at 04:10

4 Answers4

58

There is no such thing as :touch in the W3C specifications, http://www.w3.org/TR/CSS2/selector.html#pseudo-class-selectors

:active should work, I would think.

Order on the :active/:hover pseudo class is important for it to function correctly.

Here is a quote from that above link

Interactive user agents sometimes change the rendering in response to user actions. CSS provides three pseudo-classes for common cases:

  • The :hover pseudo-class applies while the user designates an element (with some pointing device), but does not activate it. For example, a visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element. User agents not supporting interactive media do not have to support this pseudo-class. Some conforming user agents supporting interactive media may not be able to support this pseudo-class (e.g., a pen device).
  • The :active pseudo-class applies while an element is being activated by the user. For example, between the times the user presses the mouse button and releases it.
  • The :focus pseudo-class applies while an element has the focus (accepts keyboard events or other forms of text input).
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Doug Chamberlain
  • 11,192
  • 9
  • 51
  • 91
  • 9
    I knew there wasn't such a thing as :touch. I was wondering if there was something similar. :active seemed reasonable but it didn't work in my tests. – Elias Zamaria May 19 '11 at 18:56
  • @mikez302 - I figured you knew that I wanted to cite my source. I agree with you I don't see any reason it would not work, other than my point about the order being very important. I did see that someone posted something about the css pseudo selectors for IOS and Android, but I couldn't speak to those technologies. – Doug Chamberlain May 19 '11 at 19:02
  • I switched around the :active and :hover rules in my example and it didn't seem to do anything. – Elias Zamaria May 19 '11 at 19:18
  • I've tested on the iPad and what happens is that it only changes to the active state when one releases the button. Not really an active state, more and "on release" state, which is completely useless because it lasts for about a millisecond. – HotFudgeSunday Jul 25 '11 at 20:24
  • 40
    @mikez302 : use the `:active` pseudoclass. It should work, but in some browsers you need a small hack to make it work : attach an event handler to the `touchstart` event on the body (ex:``) – gion_13 Feb 16 '12 at 13:49
  • 6
    Just to touch on @mikez302 comment in the last answer, their is a neat fix in the HTML5 Mobile Boilerplate which links to this article - http://alxgbsn.co.uk/2011/10/17/enable-css-active-pseudo-styles-in-mobile-safari/ – Giles Butler Oct 09 '12 at 00:36
  • Was looking for a solution for :hover like behavior on mobile devices and that helped me out! Thanks! – tfE Nov 05 '16 at 21:32
  • At least based on testing in Chrome and Safari mobile, it looks the best approach currently for displaying hidden content on tap (like a menu) is to continue using the `:hover` pseudo-class in the CSS and include `onclick=""` in any elements that `:hover` is being applied to, which results in tapping on mobile device working like hovering on a desktop display. Has anyone found a better approach? – embden Sep 26 '17 at 17:54
23

Since mobile doesn't give hover feedback, I want, as a user, to see instant feedback when a link is tapped. I noticed that -webkit-tap-highlight-color is the fastest to respond (subjective).

Add the following to your body and your links will have a tap effect.

body {
    -webkit-tap-highlight-color: #ccc;
}
Abdo
  • 13,549
  • 10
  • 79
  • 98
  • This seems to be the most reliable, but it doesn't look the best. The background colour seems to extend a little out of the element, making it look bigger for a split moment. – Adam Nov 20 '14 at 12:26
  • @Adam yup, I couldn't work around that as I remember but this being only for a fraction of a second wasn't too big of a deal for me, especially that it would let the user get feedback that he clicked (which is what matters for them during this fraction of time) – Abdo Nov 20 '14 at 20:28
  • I actually got the :active pseudo styles working in the end by just binding a function to the document.ontouchstart event (through jQuery), with an empty callback. – Adam Nov 20 '14 at 23:47
  • Not a bad idea :-) I was avoiding javascript altogether for this purpose. – Abdo Nov 21 '14 at 17:57
  • The worst of all is that Chrome does set it silently. Be aware when testing with mouse only ) – Konstantin Nov 16 '17 at 14:07
  • 2
    Just sharing that `-webkit-tap-highlight-color` is a [Non standard CSS feature](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-tap-highlight-color), I'm using `:active` instead, it really fits & makes sense. – Ricardo Fornes Nov 28 '17 at 19:55
  • 1
    `-webkit-tap-highlight-color` was exactly what I was looking for i.e. controlling the background color of a div when it was being touched (under Chrome/Electron at least). :active/hover/focus didn't work for this. Thanks a lot! – Greg Sadetsky Jun 29 '21 at 12:32
1

I was having trouble with mobile touchscreen button styling. This will fix your hover-stick / active button problems.

body, html {
  width: 600px;
}
p {
  font-size: 20px;
}

button {
  border: none;
  width: 200px;
  height: 60px;
  border-radius: 30px;
  background: #00aeff;
  font-size: 20px;
}

button:active {
  background: black;
  color: white;
}

.delayed {
  transition: all 0.2s;
  transition-delay: 300ms;
}

.delayed:active {
  transition: none;
}
<h1>Sticky styles for better touch screen buttons!</h1>

<button>Normal button</button>

<button class="delayed"><a href="https://www.google.com"/>Delayed style</a></button>

<p>The CSS :active psuedo style is displayed between the time when a user touches down (when finger contacts screen) on a element to the time when the touch up (when finger leaves the screen) occures.   With a typical touch-screen tap interaction, the time of which the :active psuedo style is displayed can be very small resulting in the :active state not showing or being missed by the user entirely.  This can cause issues with users not undertanding if their button presses have actually reigstered or not.</p>

<p>Having the the :active styling stick around for a few hundred more milliseconds after touch up would would improve user understanding when they have interacted with a button.</p>
TillyJonesy
  • 131
  • 6
0

The much upvoted comment by @gion_13 solved the issue for me:

Add ontouchstart="" to your page's body element and the :active selector will work more as expected on touch screens. Still not perfect in Chrome.

魔大农
  • 100
  • 8