Recently, I worked on a project where colored tiles (square blocks) were showing content on hover.
This is generally not recommended for accessibility reasons (using hover as a content interaction), but the effect is nice. The point was to link the hovered content to a product page.
I wanted to do this pure css because why not, and also because the logic seems quite simple at first, but would require a lot of logic after all (blocking click event after touch event, showing the link, allow touch & click, while hiding the previously ‘touched’ block, and so on).
With HTML5 “block links“, displaying a link as a “box” is trivial, but the touch experience soon became an interrogation, because of the hover being used as an access to content vs. a decorative / animation effect.
We used modernizr to detect the touch feature. But doing this only detect if the browser you’re testing on has the touch feature, not if a touch device is used. After some research, I decided to use it as follow :
In conjunction with Navigator.maxTouchPoint so that browsers that support it would return a value of more than 0 on a real touch device and 0 on a desktop browser.
For browsers that do not support this property (like Safari), we used it with a regular media query and the touch class added by modernizr (thus targeting < 1024px touch capable browsers).
So, now that we have our touch thingy detected, to the CSS.
The main problem is that the link appearing on hover should appear on touch, but would also trigger the click and load the new page :
The point here was to touch something that would simulate the hover, and trigger the apparition of the real link (and stay here). That something is a pseudo-element. An absolute-positionned pseudo-element covers the link block, and prevent the click. We can then show it. So now what ? If we can see it, but not click it, what’s the point ? Well, now that it’s correctly shown, we hide the pseudo element, by animating it’s visibility (which is an animatable property.) But as we are smart, the pseudo element is transparent, so actually always invisible.
So let’s wrap it up : on desktop, we hover over the container, and display a child block. On touch device, we “touch” a pseudo-element, so focus on the parent, show the child block, transition the pseudo-element back to an invisible state. Then we can click again, but this time, on the real link.
Note : It’s good practice to always add :focus (and maybe :active) to your :hover selector to maximize compatibility, especially on mobile/touch devices.
We couldn’t end that here without some fun debugging. Because it doesn’t work on iOs devices. Why ? I found the answer here. The crazy thing about it is that in order to make it work, you have to specify…believe it or not : You have to specify the cursor:pointer property. Like, it doesn’t make any sense, that the focus property start to work on iPad / iPhone only if we specify that the cursor on desktop should be a little hand.
So here is our css after we have done all that.
Hope this can help some of you looking for a similar solution (I haven’t found a lot related to this issue), and please advise if we can achieve this with a simpler/smarter/cleaner solution !