A common issue web developers run into is how hover effects on desktop transition to a mobile device. Since obviously there is no hover on mobile a discussion needs to be had about whether that hover effect is still vital/functional to the design or not. A good example of this is an effect we use on our About page.
Now, as with anything regarding web development, there are many ways to skin a cat, this is just my approach. If you have done something similar in a different way please share in the comments below.
The Solution (*no cats were harmed in this development)
To start things off, here is what the HTML looks like for one team member:
<div class="team-member">
<figure>
<img class="member-image" src="<?php echo SITE_URL; ?>assets/images/pages/about/team/team-mike.jpg" alt="" />
<figcaption>
<h2>Mike</h2>
<h3>Principal, Creative Director</h3>
<p>Mike launched King Design out of the spare bedroom in his apartment in 2002, and the rest, as they say, is history. He’s a family man with a taste for beer, grilling, great design, working with his hands, guitar and photography.</p>
</figcaption>
</figure>
</div>
Now, since on mobile hover does try to initiate the hover when you click on an element, we need to disable that. I used a combination of javascript and CSS for that. The javascript uses a media query for anything below 1024px wide and adds a “disable” class to the figure element.
To preface my CSS, it is written in SASS. If you want to learn more about SASS go here. I’ll share all of my CSS for the figure element but you should only need to pay attention to the bottom section:
figure {
position: relative;
float: left;
overflow: hidden;
margin: 0;
width: 100%;
background: #3085a3;
text-align: center;
cursor: pointer;
background: #ff4800;
img {
position: relative;
display: block;
max-width: 100%;
opacity: 1;
max-width: none;
width: -webkit-calc(100% + 20px);
width: calc(100% + 20px);
transition: opacity 0.35s, transform 0.35s;
transform: translate3d(-10px,0,0);
backface-visibility: hidden;
}
figcaption {
padding: 2em;
color: #fff;
font-size: 1.25em;
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: left;
&:before, &:after {
pointer-events: none;
}
@media (max-width: 400px){
padding: 1em;
}
}
h2, h3 {
transition: transform 0.35s;
transform: translate3d(-100%,0,0);
position: relative;
overflow: hidden;
}
h2, h3, p {
margin: 0;
color: white;
opacity: 0;
}
h2 {
font-size: 1.7em;
padding: 0 0 0.1em;
}
h3 {
font-family: $sans-serif;
text-transform: uppercase;
font-weight: 100;
font-size: 0.7em;
padding: 0 0 1em;
letter-spacing: 1px;
}
h3::after {
position: absolute;
bottom: 0;
left: 0;
width: 30%;
height: 2px;
background: #fff;
content: '';
transition: transform 0.35s;
transform: translate3d(-100%,0,0);
}
p {
letter-spacing: 1px;
font-size: 68.5%;
padding: 1em 0;
transition: opacity 0.35s, transform 0.35s;
transform: translate3d(100%,0,0);
@media (max-width: $nav-break){
line-height: 1.5em;
}
}
&:not(.disable):hover {
img {
opacity: 0.3;
transform: translate3d(0,0,0);
}
h2, h3, h3:after, p {
transform: translate3d(0,0,0);
opacity: 1;
}
}
}
The important part here is the &:not(.disable):hover section. What it is doing is applying my “hover effect” to the figure elements that do not have the .disable class applied on hover. Now, if you remember in the javascript, we applied the “disable” class for mobile devices. So this creates the effect on desktop sizes but not mobile devices. We now need to add a little more javascript to the existing code:
<script>
var mq = window.matchMedia('all and (max-width: 1024px)');
if (mq.matches) {
$("figure").addClass("disable");
$("figure").on('click', function(e) {
e.preventDefault();
if ($(this).hasClass("hover")) {
$(this).removeClass("hover");
} else {
$("figure.hover").removeClass("hover");
$(this).addClass("hover");
}
});
}
</script>
This code creates a click event on the figure element and applies a “hover” class to it if there isn’t already one on it (if there is one on it, it’s because it has already been clicked). Next, we have to add this new “hover” class into our CSS (for sanity’s sake, I’m just showing the modified section):
&:not(.disable):hover, &.hover {
img {
opacity: 0.3;
transform: translate3d(0,0,0);
}
h2, h3, h3:after, p {
transform: translate3d(0,0,0);
opacity: 1;
}
}
All this does is add the new “hover” class to the existing hover effect. This is the final solution:
Wrapping Up
Hover effects on mobile are fairly common issues that have a pretty straight-forward workaround but still aren’t perfect. This generation of web developers are still trying to wade through the sea of new mobile device development. When I was researching this problem, I was really surprised at the lack of documentation I was finding. Hopefully this will help anyone else that has run into a similar use case.
Also, browser support for the :not psuedo selector is:
Chrome | Safari | Firefox | Opera | IE | Android | iOS |
14+ | 4.0+ | 3+ | 11.1+ | 9+ | 2.1+ | 3.0+ |