Media query to detect if device is touchscreen

CssTouchMedia Queries

Css Problem Overview


What is the safest way, using media queries, to make something happen when not on a touchscreen device? If there is no way, do you suggest using a JavaScript solution such as !window.Touch or Modernizr?

Css Solutions


Solution 1 - Css

There is actually a property for this in the CSS4 media query draft.

> The ‘pointer’ media feature is used to query about the presence and > accuracy of a pointing device such as a mouse. If a device has > multiple input mechanisms, it is recommended that the UA reports the > characteristics of the least capable pointing device of the primary > input mechanisms. This media query takes the following values: > > ‘none’
> - The input mechanism of the device does not include a pointing device. > > ‘coarse’
> - The input mechanism of the device includes a pointing device of limited accuracy. > > ‘fine’
> - The input mechanism of the device includes an accurate pointing device.

This would be used as such:

/* Make radio buttons and check boxes larger if we have an inaccurate pointing device */
@media (pointer:coarse) {
	input[type="checkbox"], input[type="radio"] {
		min-width:30px;
		min-height:40px;
		background:transparent;
	}
}

I also found a ticket in the Chromium project related to this.

Browser compatibility can be tested at Quirksmode. These are my results (22 jan 2013):

  • Chrome/Win: Works

  • Chrome/iOS: Doesn't work

  • Safari/iOS6: Doesn't work

Solution 2 - Css

Nowadays, CSS Media queries can be used to define style for devices with specific interactive features and it's widely supported as well.

hover for example can be used to test whether the user's primary input mechanism can hover over elements (which would not be true in touch-enabled devices without emulating)

@media (hover: none) {
  a {
    background: yellow;
  }
}

Other interactive tests are: pointer, any-pointer, hover, and any-hover

Previous answer

I would suggest using modernizr and using its media query features.

if (Modernizr.touch){
   // bind to touchstart, touchmove, etc. and watch `event.streamId`
} else {
   // bind to normal click, mousemove, etc.
}

However, using CSS, there are pseudo class like, for example in Firefox. You can use :-moz-system-metric(touch-enabled). But these features are not available for every browser.

For Apple devices, you can simply use:

if (TouchEvent) {
   //...
}

Especially for iPad:

if (Touch) {
    // ...
}

But, these do not work on Android.

> Modernizr gives feature detection abilities, and detecting features is > a good way to code, rather than coding on basis of browsers.

Styling Touch Elements

Modernizer adds classes to the HTML tag for this exact purpose. In this case, touch and no-touch so you can style your touch related aspects by prefixing your selectors with .touch. e.g. .touch .your-container. Credits: Ben Swinburne

Solution 3 - Css

The CSS solutions don't appear to be widely available as of mid-2013. Instead...

  1. http://www.nczonline.net/blog/2012/07/05/ios-has-a-hover-problem/">Nicholas Zakas explains that Modernizr applies a no-touch CSS class when the browser doesn’t support touch.

  2. Or detect in JavaScript with a simple piece of code, allowing you to implement your own Modernizr-like solution:

     <script>
         document.documentElement.className += 
         (("ontouchstart" in document.documentElement) ? ' touch' : ' no-touch');
     </script>
    

    Then you can write your CSS as:

     .no-touch .myClass {
         ...
     }
     .touch .myClass {
         ...
     }
    

Solution 4 - Css

There is actually a media query for that:

@media (hover: none) { … }

Apart from Firefox, it's fairly well supported. Safari and Chrome being the most common browsers on mobile devices, it might suffice untill greater adoption.

Solution 5 - Css

Media types do not allow you to detect touch capabilities as part of the standard:

http://www.w3.org/TR/css3-mediaqueries/

So, there is no way to do it consistently via CSS or media queries, you will have to resort to JavaScript.

No need to use Modernizr, you can just use plain JavaScript:

<script type="text/javascript">
    var is_touch_device = 'ontouchstart' in document.documentElement;
    if(is_touch_device) alert("touch is enabled!");
</script>

Solution 6 - Css

In 2017, CSS media query from second answer still doesn't work on Firefox. I found a soluton for that: [-moz-touch-enabled][2]


So, here is cross-browser media query:

@media (-moz-touch-enabled: 1), (pointer:coarse) {
	.something {
		its: working;
	}
}

[2]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/-moz-touch-enabled "-moz-touch-enabled"

Solution 7 - Css

This will work. If it doesn't let me know

@media (hover: none) and (pointer: coarse) {
    /* Touch screen device style goes here */
}

edit: hover on-demand is not supported anymore

Solution 8 - Css

This solution will work until CSS4 is globally supported by all browsers. When that day comes just use CSS4. but until then, this works for current browsers.

browser-util.js

export const isMobile = {
  android: () => navigator.userAgent.match(/Android/i),
  blackberry: () => navigator.userAgent.match(/BlackBerry/i),
  ios: () => navigator.userAgent.match(/iPhone|iPad|iPod/i),
  opera: () => navigator.userAgent.match(/Opera Mini/i),
  windows: () => navigator.userAgent.match(/IEMobile/i),
  any: () => (isMobile.android() || isMobile.blackberry() || 
  isMobile.ios() || isMobile.opera() || isMobile.windows())
};

onload:

old way:

isMobile.any() ? document.getElementsByTagName("body")[0].className += 'is-touch' : null;

newer way:

isMobile.any() ? document.body.classList.add('is-touch') : null;

The above code will add the "is-touch" class to the body tag if the device has a touch screen. Now any location in your web application where you would have css for :hover you can call body:not(.is-touch) the_rest_of_my_css:hover

for example:

button:hover

becomes:

body:not(.is-touch) button:hover

This solution avoids using modernizer as the modernizer lib is a very big library. If all you're trying to do is detect touch screens, This will be best when the size of the final compiled source is a requirement.

Solution 9 - Css

I believe the better way to query a touch-screen with CSS (in 2022) is with (pointer:coarse), and definitely NOT with (hover:none), or a combination, as some suggest: (hover: none) and (pointer: coarse), because (hover:none) is unreliable - some devices emulate hover on long press (touch) so (hover:none) will not be true. I had such a problem, on a real touch device (a phone, not an emulation), without any other input (mouse or something), that "had" a hover capability, and my media query failed.

Probably the best way is to use Modernizr, or even both (Modernizr and CSS, though I didn't look what tests Modernizr does, might be the same as CSS :) like:

.modernizr-touch-class .my-class { // properties }
@media (pointer:coarse) { .my-class { // the same properties } }

But all in all, this is not considered reliable. When you add modernizr "Touch Events" test, they display a short info (with a few links) on this problem. This is probably a good thing to read to find the best solution to a particular problem, and then test it...

Anyway, I just wanted to say that (hover:none) is unreliable (in 2022). :D

Solution 10 - Css

adding a class touchscreen to the body using JS or jQuery

  //allowing mobile only css
    var isMobile = ('ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/));
    if(isMobile){
        jQuery("body").attr("class",'touchscreen');
    }

Solution 11 - Css

I was able to resolve this issue using this

@media (hover:none), (hover:on-demand) { 
Your class or ID{
attributes
}    
}

Solution 12 - Css

As of 5/5/2022:

var isTouch = "maxTouchPoints" in window.navigator && window.navigator.maxTouchPoints > 1;
var isTouchTwo = "ontouchstart" in window;
var isTouchThree = window.matchMedia && window.matchMedia("(pointer:coarse)").matches;
var isDesktopIE = !!window.MSInputMethodContext && !!document.documentMode && !isTouchTwo;
var uaDataIsMobile = window.navigator.userAgentData && window.navigator.userAgentData.mobile;
var isDevice = typeof uaDataIsMobile === 'boolean' ? window.navigator.userAgentData.mobile || (isTouchTwo && isTouchThree) : ((/android|avantgo|blackberry|googlebot-mobile|iemobile|opera mini|kitkat|palmos|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|iphone|ipod|phone|ipad|pie|tablet|silk|up\.browser|up\.link|playbook|webos|wos/i.test(window.navigator.userAgent.toLowerCase()) && !isDesktopIE) || window.navigator.platform === 'MacIntel' && isTouch);

console.log('1. '+isTouch+' 2. '+isTouchTwo+' 3. '+isTouchThree+' 4. '+/android|avantgo|blackberry|googlebot-mobile|iemobile|opera mini|kitkat|palmos|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|iphone|ipod|phone|ipad|pie|tablet|silk|up\.browser|up\.link|playbook|webos|wos/i.test(window.navigator.userAgent.toLowerCase())+' 5. isDevice: '+isDevice)

Redresses issues, a) where IE11 desktop navigator.userAgent string claims to be "tablet", and b) where iPadOS User Agent in Safari is same as on MacOS Catalina. (Untested by me, but it follows this line of argumentation

> quote

https://developer.apple.com/forums/thread/119186

> unquote

and should work. I'm depending on it. (See edit.)

Note that my answer is compatible with Client Hints. (Future answers should also be, I think.) For browsers that support navigator.userAgentData, you won't need navigator.userAgent.

Sorry about the long strings. In ES6 it looks prettier.

To do a media query, just attach a style sheet based on true or false output.

edit: https://stackoverflow.com/questions/57765958/how-to-detect-ipad-and-ipad-os-version-in-ios-13-and-up

if (navigator.maxTouchPoints > 1) {
  // browser supports multi-touch
}

I thought it was > 0. (Corrected in code.)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJJJollyjimView Question on Stackoverflow
Solution 1 - CssZnarkusView Answer on Stackoverflow
Solution 2 - CssStarxView Answer on Stackoverflow
Solution 3 - CssSimon EastView Answer on Stackoverflow
Solution 4 - CssBuzutView Answer on Stackoverflow
Solution 5 - CssAlex WView Answer on Stackoverflow
Solution 6 - CssSokołowView Answer on Stackoverflow
Solution 7 - Cssaleksa_95View Answer on Stackoverflow
Solution 8 - CssPatrick W. McMahonView Answer on Stackoverflow
Solution 9 - CssvIGGSView Answer on Stackoverflow
Solution 10 - CssMatoeilView Answer on Stackoverflow
Solution 11 - CssRobin MehdeeView Answer on Stackoverflow
Solution 12 - CssicemanView Answer on Stackoverflow