The CSS Media Query That Changed How I Approach Responsive Desig
I was working on the responsiveness of my portfolio website when I discovered a CSS media query that changed how I think about responsive design.
I initially thought I needed a way to detect whether the website was being viewed on a mobile device or tablet.
I did that by checking if the height of the document body was greater than its width hoping it would be a reliable solution.
const isVertical= document.body.clientHeight > document.body.clientWidth;
I realized that I was checking the device’s portrait orientation instead of checking for the device type.
While researching the issue, I encountered this CSS media query that checks if the user’s primary input device can conveniently hover over DOM elements.
@media (hover: hover) {
/* styles for devices that support hover */
}
Tailwind also supports this through arbitrary variants
<Card className="[@media(hover:hover)]:bg-teal-800" />
Devices that match
- Desktops with mouse
- Laptops with trackpad
- Most devices with a mouse pointer
Devices that do not match
- Touch-only phones
- Touch-only tablets
However, devices with an attached mouse or trackpad may behave differently
For example,
.button{
opacity: 1;
}
@media (hover: hover) {
.button{
opacity: 0;
}
.card:hover .button{
opacity: 1;
}
}
On mobile devices,
- The button is always visible
:hoverrules are ignored
On a laptop,
- The button starts hidden
- Appears when the card is hovered
This can also be used the other way around to explicitly check if the device is unable to hover over DOM elements.
@media (hover: none) {
/* styles for devices that do not support hover */
}
or in tailwind as [@media(hover:none)]:bg-teal-800
Another useful media feature is @media (pointer: fine), which checks pointer precision of the primary pointing device. A table below describes how both the queries respond with primary input devices.
| Device | Hover | Pointer |
|---|---|---|
| Mouse | hover | fine |
| Trackpad | hover | fine |
| Finger touch | none | coarse |
| Stylus | usually hover; could be none depending on the device | fine |
Pointer characteristics are implementation-dependent and may vary across browsers and operating systems.
Since we have already discussed hover and pointer there are two important properties that I believe must be mentioned.
@media (any-hover: hover) {
/* styles */
}
@media (any-pointer: fine) {
/* styles */
}
These differ from
hover
pointer
because they consider all available inputs rather than just the primary one.
For example,
- Tablet + mouse attached
might report
hover: none
but
any-hover: hover
This was a small discovery, but it changed the way I approach responsive design. If you're building interactions that depend on hover or pointer precision, these media queries are worth keeping in mind.
Discussion in the ATmosphere