When designing a website for mobile devices, be careful about universal
*:hover, because it may hurt your iPhone / iPad visitors.
Consider a situation that both of the following conditions exist:
First, the CSS comes with a selector which contains a universal
:hover selector. For example:
Or not combined with other selector, just the universal part:
Second, the HTML contains a search input box:
Then, when visiting the page with iOS Safari:
- Every link needs double-tap to navigate instead of single-tap.
- Tap once, the link switches to hover state.
- Tap the same link again, the browser navigates to the target URL.
See Demo: http://cdpn.io/mpBrw (open with iOS Safari)
Tested on: iPhone 5 with iOS 6.1.4 and iPad 3 with iOS 6.1.3.
Note: In the first exmaple of CSS selector, no matter whether
.something matches any element or not, this bug will be triggered (i.e. this bug also happens when
<div class="something"> does not exist).
:hover more specific, and never use
*:hover. For example:
For those who are curious about how I get this solution and things about the spec, please read on.
I found this issue when applying a new template to a website. When I was testing it on iPhone Safari, I found some links need to tap twice to navigate.
At first I think there were some CSS that triggers content change so the browser did not fire simulated
type="search" attribute. By removing this search box, the bug disappeared.
Then I Google'd for a while and found a Chromium bug saying that "moving mouse into the window triggers layout on placeholder text in the input". I fired up Timeline and found that it did trigger layout. I wasn't sure if this is the reason of the double-tap bug, so I took an experiment:
|input type="text"||input type="search"|
That is, a search input triggers the double-tap bug, but a normal text input does not, no matter whether the placeholder attribute is present or not.
AFAIK, there are some pseudo elements in a search input, for example, the drop-down button, and the cancel button. I tried to hide them by setting
display: none one by one, and finally I found that when hiding the cancel button, the double-tap bug is not triggered:
But no, I don't wanna hide the cancel button. It's a feature, and there should not be any workaround depending on it.
I got no idea. I then tried removing some CSS from the assets package one by one, and I found that when a specific file is removed, the bug is not triggered. I took a look into that file (originally written in SCSS), and there was a strange selector:
Which compiles to:
By removing the
:hover selector, the bug is not triggered, even without the hack on search input's cancel button.
So how can we fix it? In SCSS, to be more specific, it should be sticked with the parent selector, e.g.:
which compiles to:
The Spec Says
The W3C CSS Validator does not raise any warning when there is a standalone
:hover selector, so it should be syntactically correct. I then looked up the CSS3 Selector Spec and the only thing I can understand is that
*:hover are equivalent:
6.2. Universal selector
If a universal selector represented by
*(i.e. without a namespace prefix) is not the only component of a sequence of simple selectors selectors or is immediately followed by a pseudo-element, then the
*may be omitted and the universal selector's presence implied.
Pseudo-classes are allowed in all sequences of simple selectors contained in a selector. Pseudo-classes are allowed anywhere in sequences of simple selectors, after the leading type selector or universal selector (possibly omitted). [...]
That is, these two selectors are equivalent and will trigger the double-tap bug on iOS Safari:
Is this a WebKit bug? Or should programmers be careful about the selector syntax? I don't know. I can't find such bug with relevant keywords
%w(universal hover search) in WebKit or Chromium's bug tracker.
If you're having such issue, you can check if there is any universal
:hover selector in your CSS.