On a recent project, Jeremy handed me a design that included some hip, slanted toggles in the responsive navigation for smaller screen sizes (similar to the image above). My first thought was to simply drop in a
background-image and go about my merry way. In actuality, getting a correct implementation was a little more challenging. The final solution removes the need for any image requests, and it maintains perfect target accuracy for touch devices. Here’s how we got there.
My first real attempt at implementing the slants was to use
:after pseudo classes and use background images to create the illusion of a slanted background. The main issue with this is that the click targets were all wrong. Clicking in the upper right or lower left corners of these faux slants resulted in a click on the element next to the targeted element. Also, this approach made four total requests for two toggles, which obviously isn’t winning any performance awards.
After talking it over with Ben, he recommended trying to use
transform: rotate on the elements. I had tried this before and was disappointed because the children elements also rotated (in this case, the text inside the toggle). At Ben’s urging, I gave it another go. After some Googling and thinking, I figured out that simply applying absolute positioning will not remove the parent’s rotation, but it will allow a second transform (a counter-rotate) to transform the child element. One issue I ran into with this approach was that elements had to be made larger than desired and then cropped with
overflow:hidden with their parent.
The elements were successfully rotated, their children counter-rotated, no images were loaded, and (most importantly) the rotate also changed the element’s touch target to correspond directly to its visual appearance. This is a big change from a solution that had required one to four images, one to four requests, and resulted in an inaccurate target. Pretty sweet, huh?
WebKit obviously handles this fine, as does Firefox. According to Can I Use, IE 9+ will handle the transforms just fine as well. We thought this was an acceptable level of browser support. For IE8 and lower we decided it wasn’t vital that they receive the slanted treatment, so they instead get standard square boxes.
A Few Alternatives
Now, after I got the slanted elements working, Rob and Ethan both suggested I should have used skew instead of rotate. Doh! They were right of course. Using skew greatly simplifies this approach. Going forward I’d recommend skew over rotate simply because you don’t have to do any sort of overflow cropping.
Another alternative, suggested by Mr. Jonathan Snook, was to use an image map and a single background image. I think this would work perfectly. However, since using skew removes the need for any image/request at all, and we’re fine with the browser support, I think skew is the best solution for this particular problem. Now, I’m sure that image maps would be great as a fallback for browsers that don’t support transforms or in a situation where browser support is more critical. As with anything on the web, it all depends on your particular project, use case, and constraints.
Feel free to check out this code pen to see the code and play around with the rendered touch targets.