Question
Detect Mobile-Friendly Capabilities with jQuery and JavaScript
Question
Is there a way to determine whether a visitor is using a mobile device with jQuery, similar to a CSS @media query? I want to run different JavaScript when the browser is being used on a handheld device. The deprecated jQuery $.browser feature does not meet this need.
Short Answer
jQuery does not provide a reliable way to identify a “mobile device.” Instead of guessing the device from its name or browser string, detect the capability your code actually needs, such as a narrow layout, touch-friendly pointer, hover support, or a specific browser API. You can use CSS media queries for presentation and JavaScript’s matchMedia() when behavior must change.
Concept
A device is not the same thing as a screen size or an input method. For example:
- A tablet may have a large screen but be operated by touch.
- A laptop may have a touchscreen and a mouse.
- A desktop browser window can be resized to phone width.
- A phone can connect to a mouse, keyboard, or external display.
Because of these combinations, there is no dependable yes-or-no test for “is mobile” that produces the right result for every visitor. jQuery is a DOM utility library; it does not have special knowledge of the physical device.
Use capability detection instead. Ask a focused question that matches the behavior you are about to implement:
- Use CSS media queries when only the layout or appearance changes.
- Use
matchMedia()when JavaScript must react to a media query. - Use
(pointer: coarse)when controls should support less precise pointing, often touch. - Use
(hover: hover)when an interaction depends on hover. - Check whether a required API exists before using it.
This approach keeps an application usable on new devices and hybrid devices, rather than maintaining a fragile list of user-agent names.
Mental Model
Think of device detection as trying to identify a person by guessing from their coat. It may work sometimes, but it can easily be wrong.
Capability detection is like asking what the person can do right now:
- Can they hover a pointer over something?
- Is their pointing device broad and less precise?
- Is the available screen area narrow?
Your program should choose the right interaction based on those answers, not on a label such as “phone,” “tablet,” or “desktop.”
Syntax and Examples
Use CSS for visual differences whenever possible:
/* Base styles work everywhere. */
.menu-button {
display: block;
}
/* A wider layout can display the full navigation. */
@media (min-width: 48rem) {
.menu-button {
display: none;
}
}
When JavaScript needs the same type of condition, create a media-query list with window.matchMedia():
const compactLayout = window.matchMedia("(max-width: 47.99rem)");
if (compactLayout.matches) {
console.log("Use compact-layout behavior.");
} else {
console.log("Use wide-layout behavior.");
}
compactLayout.matches is true while the viewport matches the query. It means the available viewport is narrow; it does not prove that the visitor has a phone.
For an interaction that needs larger, touch-friendly controls, test the primary pointer:
const coarsePointer = window.matchMedia("(pointer: coarse)");
if (coarsePointer.matches) {
document.body.classList.add("touch-friendly-controls");
}
You can use jQuery normally after making the capability decision:
$(function () {
const supportsHover = window.matchMedia("(hover: hover)").matches;
if (supportsHover) {
$(".product-card").on("mouseenter", function () {
$(this).addClass("is-previewing");
});
}
});
Here, hover behavior is added only when the primary input can hover. A touch device should still have another usable way to reveal the preview, such as a button or click handler.
Step by Step Execution
Consider a navigation menu that must use click-to-open behavior in compact layouts.
const compactLayout = window.matchMedia("(max-width: 47.99rem)");
function updateMenuBehavior(event) {
if (event.matches) {
$(".site-menu").addClass("site-menu--compact");
} else {
$(".site-menu").removeClass("site-menu--compact");
}
}
updateMenuBehavior(compactLayout);
compactLayout.addEventListener("change", updateMenuBehavior);
Step by step:
matchMedia("(max-width: 47.99rem)")creates aMediaQueryListfor the viewport-width rule.compactLayout.matchesistrueif the viewport is currently no wider than47.99rem.updateMenuBehavior(compactLayout)runs immediately, so the page is correct on first load.- If the query matches, jQuery adds the
site-menu--compactclass. - Otherwise, jQuery removes that class.
- The
changelistener runs the same function if the browser window is resized, rotated, or moved to a display where the query result changes.
The event passed to the listener also has a matches property, so the same function can receive either the original media-query object or a later change event.
Real World Use Cases
- Responsive navigation: Show a menu toggle in compact widths and a full navigation bar in wider widths.
- Hover-only previews: Enable image previews on pointer hover only when the user can hover.
- Touch-friendly controls: Increase spacing around small controls when a coarse pointer is primary.
- Maps and dashboards: Avoid loading an optional, expensive visualization until there is enough viewport space.
- Drag-and-drop alternatives: Provide buttons such as “Move up” and “Move down” when a drag interaction would be difficult with touch.
- Progressive enhancement: Check for browser features such as geolocation, notifications, or
IntersectionObserverbefore enabling an optional feature.
Real Codebase Usage
In production code, developers usually define behavior in terms of requirements rather than device categories.
Keep presentation in CSS
Use CSS media queries for layout, visibility, spacing, and typography. This avoids duplicating styling rules in JavaScript.
Use JavaScript only for behavior
A common pattern is to create one named media-query object and subscribe to its changes:
const canHover = window.matchMedia("(hover: hover)");
function configureTooltips({ matches }) {
if (!matches) {
$("[data-tooltip]").off("mouseenter mouseleave");
return;
}
$("[data-tooltip]")
.off("mouseenter mouseleave")
.on("mouseenter", function () {
$(this).addClass("has-tooltip-open");
})
.on("mouseleave", function () {
$(this).removeClass("has-tooltip-open");
});
}
configureTooltips(canHover);
canHover.addEventListener("change", configureTooltips);
The early return prevents hover handlers from being attached when they are not appropriate. Calling .off() first also avoids duplicate handlers if the media query changes more than once.
Prefer an accessible fallback
Do not make hover the only way to access content. A tooltip, menu, or product preview should also work with a click, tap, keyboard focus, or visible button.
Treat user-agent checks as a last resort
Some server-side rendering or analytics tasks may need platform information. Browser-provided user-agent data can be reduced, changed, spoofed, or unavailable, so it should not be the main basis for interaction or layout decisions.
Common Mistakes
Using a user-agent regular expression as the main solution
// Fragile: device names change, strings can be spoofed, and hybrid devices exist.
const isMobile = /Android|iPhone|iPad/i.test(navigator.userAgent);
This guesses a device category rather than checking what the browser can do. Prefer matchMedia() for layout and input capabilities.
Treating a narrow viewport as proof of a phone
const isMobile = window.innerWidth < 768;
A narrow browser window can be on a desktop, and a phone may have a wide viewport in landscape or on an external display. Name this value by what it means instead:
const isCompactLayout = window.matchMedia("(max-width: 767px)").matches;
Detecting touch with "ontouchstart" in window
const isTouchDevice = "ontouchstart" in window;
A device may support touch and still be primarily used with a mouse. If you need to adapt a primary interaction, (pointer: coarse) and (hover: hover) better express the intent.
Running code only at page load
The viewport can change after loading due to resizing or rotation. Listen to the media query’s change event when the behavior must remain current.
Putting essential content only behind hover
Touch users and keyboard users may not be able to trigger hover. Provide a tap/click and keyboard-accessible alternative.
Depending on $.browser
$.browser was deprecated and removed from jQuery core. It also focuses on browser identification, which does not solve the broader device-capability problem.
Comparisons
| Approach | What it answers | Best use | Limitation |
|---|---|---|---|
CSS @media | Does the current presentation condition match? | Layout, spacing, visibility | CSS only; it does not directly run JavaScript |
window.matchMedia() | Does a media query currently match? | JavaScript behavior tied to viewport, hover, or pointer capabilities | Does not identify a physical device |
(pointer: coarse) | Is the primary pointer relatively imprecise? | Larger targets and touch-friendly interactions | Some touch-capable devices use a fine primary pointer |
(hover: hover) | Can the primary input hover? | Hover previews and hover menus | Do not use it as the only access method for important content |
| Feature detection | Is a specific browser API available? | Optional APIs such as geolocation or observers | It answers only about the checked feature |
| User-agent detection | What does the browser claim to be? | Rare platform-specific workarounds | Fragile, spoofable, and poor for UI decisions |
@media and matchMedia() can use equivalent query text. Use CSS for appearance and matchMedia() only when JavaScript behavior truly needs to change.
Cheat Sheet
// Is the viewport currently compact?
const compact = window.matchMedia("(max-width: 47.99rem)");
if (compact.matches) {
// Compact-layout behavior
}
// React when that condition changes.
compact.addEventListener("change", (event) => {
console.log(event.matches);
});
// Is the primary pointer coarse, often touch-oriented?
const coarsePointer = window.matchMedia("(pointer: coarse)").matches;
// Can the primary input hover?
const canHover = window.matchMedia("(hover: hover)").matches;
// Check a specific API before using it.
if ("geolocation" in navigator) {
// Geolocation is available.
}
- jQuery has no reliable built-in “is mobile” test.
- Prefer CSS
@mediaqueries for visual changes. matchesis a boolean result for the query right now.- Subscribe to
changeif behavior must respond to resizing or rotation. - Describe variables by the capability:
isCompactLayout,canHover,hasCoarsePointer. - Do not rely on user-agent strings for responsive UI behavior.
- Always provide non-hover and keyboard-accessible paths to important actions.
FAQ
Can jQuery detect whether a user is on a mobile device?
No reliable jQuery method can identify every mobile device correctly. jQuery can work with the result of JavaScript capability checks, but it does not provide a dependable mobile-device classification.
What should I use instead of $.browser?
Use CSS media queries for styling and window.matchMedia() for JavaScript behavior. Check browser APIs directly when you need a particular feature.
How do I check for a mobile-sized screen in JavaScript?
Use window.matchMedia("(max-width: 47.99rem)").matches. Call the result something like isCompactLayout, because it describes viewport width rather than the physical device.
Is (pointer: coarse) the same as detecting touch?
Not exactly. It indicates that the primary pointer is relatively imprecise, which is common on touch devices. A computer can support touch while still having a fine mouse pointer as primary input.
Should I use navigator.userAgent to detect iPhone or Android?
Avoid it for normal layout and interaction decisions. User-agent strings are not a reliable capability signal and can be modified or reduced. Use it only for a narrowly justified platform-specific workaround.
Why should I listen for matchMedia changes?
The viewport and input context can change after page load, such as when a device rotates or a desktop window is resized. The change event lets your behavior stay in sync.
Can CSS and JavaScript use the same media query?
Yes. Use the same breakpoint or capability query in CSS for presentation and in matchMedia() when JavaScript behavior also needs to respond.
Mini Project
Description
Build a responsive product-card interaction. On devices that support hover, moving the pointer over a card reveals its details. On non-hover devices, each card has a button that reveals the same details. The project demonstrates capability detection while keeping the essential action available to every user.
Goal
Create product cards whose details can be revealed with hover when available and with a button on every device.
Requirements
Requirement 1
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.