Consulta de mídia para detectar se o dispositivo é touchscreen

122

Qual é a maneira mais segura, usando consultas de mídia, de fazer algo acontecer quando não estiver em um dispositivo com tela de toque? Se não houver maneira, você sugere usar uma solução JavaScript como !window.TouchModernizr ou?

JJJollyjim
fonte
2
Fast forward para 2018, CSS é agora nativamente capaz de fazer isso stackoverflow.com/a/50285058/1717735
Buzut

Respostas:

37

Eu sugeriria o uso de modernizr e seus recursos de consulta de mídia.

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

No entanto, usando CSS, existem pseudo classes como, por exemplo, no Firefox. Você pode usar : -moz-system-metric (ativado por toque) . Mas esses recursos não estão disponíveis para todos os navegadores.

Para dispositivos Apple , você pode usar de maneira simples:

if(window.TouchEvent) {
   //.....
}

Especialmente para o Ipad:

if(window.Touch) {
    //....
}

Mas, eles não funcionam no Android .

O Modernizr oferece recursos de detecção de recursos e a detecção de recursos é uma boa maneira de codificar, em vez de codificar com base em navegadores.

Elementos de toque de estilo

O modernizador adiciona classes à tag HTML para esse fim exato. Nesse caso, touche no-touchpara que você possa estilizar os aspectos relacionados ao toque, prefixe seus seletores com .touch. por exemplo .touch .your-container. Créditos: Ben Swinburne

Starx
fonte
Estou certo ao pensar que nenhuma classe de psedo funciona com todos os dispositivos / navegadores modernos?
precisa saber é o seguinte
@ JJ56, Sim, nem todos os navegadores suportam pseudo classes. Mas é aí que modernizrserá perfeito :)
Starx
18
O Modernizr.touchteste indica apenas se o navegador suporta eventos de toque, o que não reflete necessariamente um dispositivo de tela de toque. Por exemplo, os telefones Palm Pre / WebOS (touch) não suportam eventos de toque e, portanto, são reprovados neste teste.
Numeroweb
5
Só para adicionar isso, se você estiver incluindo o modernizador de qualquer maneira; O modernizador adiciona classes à tag body para esse propósito exato. Nesse caso, touche no-touchpara que você possa estilizar os aspectos relacionados ao toque, prefixe seus seletores .touch. Por exemplo.touch .your-container
Ben Swinburne
2
Para mim, parece que modernizr adiciona classe de toque à tag html, não à tag body.
Robin Cox
162

Na verdade, existe uma propriedade para isso no rascunho da consulta de mídia CSS4 .

O recurso de mídia 'ponteiro' é usado para consultar a presença e a precisão de um dispositivo apontador, como um mouse. Se um dispositivo tiver vários mecanismos de entrada, é recomendável que o UA relate as características do dispositivo apontador menos capaz dos mecanismos de entrada primários. Esta consulta de mídia aceita os seguintes valores:

'none'
- O mecanismo de entrada do dispositivo não inclui um dispositivo apontador.

'grosso'
- O mecanismo de entrada do dispositivo inclui um dispositivo apontador de precisão limitada.

'fino'
- O mecanismo de entrada do dispositivo inclui um dispositivo apontador preciso.

Isso seria usado como tal:

/* 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;
    }
}

Eu também encontrei um ticket no projeto Chromium relacionado a isso.

A compatibilidade do navegador pode ser testada no Quirksmode . Estes são os meus resultados (22 de janeiro de 2013):

  • Chrome / Win: funciona
  • Chrome / iOS: não funciona
  • Safari / iOS6: não funciona
Znarkus
fonte
3
Como essa pode ser a resposta com mais pontos quando a solução fornecida não funciona mesmo de acordo com o pôster?
Erdomester 18/08
5
O suporte ao navegador para isso não é mais tão ruim: Edge, Chrome, Safari, iOS e Android. Veja: caniuse.com/#feat=css-media-interaction
Josa
3
Boa resposta. Além disso: developer.mozilla.org/pt-BR/docs/Web/CSS/@media/hover
aross
Funciona para mim;) Obrigado por pesquisar isso!
Verri
51

As soluções CSS não parecem estar amplamente disponíveis em meados de 2013. Em vez de...

  1. Nicholas Zakas explica que o Modernizr aplica uma no-touchclasse CSS quando o navegador não suporta o toque.

  2. Ou detecte no JavaScript com um simples trecho de código, permitindo implementar sua própria solução Modernizr:

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

    Então você pode escrever seu CSS como:

    .no-touch .myClass {
        ...
    }
    .touch .myClass {
        ...
    }
    
Simon East
fonte
O segundo é muito bom. Funciona um charme para mim! Obrigado.
Garavani
@ bjb568 Obrigado pela edição sugerida, que é uma alternativa mais moderna, mas como ela só funciona no IE 10 e acima, acho melhor manter essa versão por enquanto.
Simon East
Parece que essa classe estaria na tag html; o que significa que está desativado por padrão ao usar o CSP.
Leo
35

Os tipos de mídia não permitem detectar recursos de toque como parte do padrão:

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

Portanto, não há como fazê-lo de forma consistente por meio de CSS ou consultas de mídia, você precisará recorrer ao JavaScript.

Não é necessário usar o Modernizr, você pode simplesmente usar JavaScript simples:

<script type="text/javascript">
    var is_touch_device = 'ontouchstart' in document.documentElement;
    if(is_touch_device) alert("touch is enabled!");
</script>
Alex W
fonte
AFAIK, window.touch&& window.TouchEventfuncionam apenas para dispositivos Apple.
Starx 9/07/12
22
O @vsync Modernizr é uma ótima maneira de colocar todos os testes úteis para desenvolvedores em uma biblioteca mantida, para que eles não precisem acessar o Google sempre que precisam testar um recurso específico, como eventos de toque e ter que encontrar esta página. Para sua informação, existe uma versão Modernizr personalizada que você pode personalizar com os testes desejados. É uma ótima maneira de testar os recursos sempre da mesma maneira entre os projetos, ou você usa a sintaxe JS (por exemplo: Modernizr.touch) ou as classes CSS (.touch .my-element {}). Eu acho que é um insulto à inteligência humana não reconhecer que podemos fazer coisas sem reinventar a roda a cada vez.
Alejandro García Iglesias
11
Bem, eu trabalhei em centenas de projetos e nunca precisei disso, na maioria dos casos, tudo o que você precisa é de um conjunto muito pequeno de testes, nunca mais do que 5, eu diria (na maioria dos casos), então, encontre aqueles 5 e coloque-os no seu código diretamente, não é necessário acessar o site Modernizer, criar uma compilação personalizada, incluí-la na sua página ou o que for. Os desenvolvedores não devem ser tão preguiçosos. Um desenvolvedor web deve sempre ter a mentalidade de "como posso tornar o código mais leve?" .. IMHO e anos de experiência. desenvolvedores hoje em dia parece amor incluindo toneladas de roteiros: /
vsync
2
Alguns dizem preguiçoso. Eu digo por que reinventar a roda? E quando um novo dispositivo / versão / plataforma aparece e seu caso especial precisa ser alterado? Você a) tenta elaborar um código especial de detecção de caso e voltar ao seu código personalizado, familiarizando-se com ele no processo ou b) baixar uma versão mais recente do Modernizr e inseri-la? Eu sei o que eu faria. +1 para GarciaWebDev.
Sc0ttyD
@ Sc0ttyD Minha preferência pessoal é aprender a codificar as coisas inicialmente sem depender de bibliotecas como o Modernizr. Um dia, talvez você precise ser a pessoa que está codificando para o novo dispositivo e não quer ficar preso porque não pode fazê-lo sem uma biblioteca. Sem mencionar, provavelmente há muitas pessoas que simplesmente não têm tempo no trabalho para aprender uma nova biblioteca.
Alex W
28

Em 2017, a consulta de mídia CSS da segunda resposta ainda não funciona no Firefox. Encontrei uma solução para isso: -moz-touch-enabled


Então, aqui está a consulta de mídia entre navegadores:

@media (-moz-touch-enabled: 1), (pointer:coarse) {
    .something {
        its: working;
    }
}
Sokołow
fonte
isso deve ser mais alto e a resposta aprovada. firefox está trabalhando na implementação da especificação, por isso -moz-touch-enablednão será necessário em breve
Dogoku
@ user3445853 O OP pergunta como detectar (via consulta de mídia) o dispositivo com uma tela sensível ao toque. Se a regra "(ponteiro: nenhum)" for verdadeira, o dispositivo não terá uma tela de toque com certeza. Mas alguém deve confirmar minha opinião (ou não) :)
Sokolow
-moz-touch-enabledsupostamente não é suportado no Firefox 58+. Por exemplo, esta solução não abrange o Firefox 58-63 (já que o Firefox 64+ suporta a consulta de ponteiro). Fonte: developer.mozilla.org/pt-BR/docs/Web/CSS/@media/…
fgblomqvist
24

Na verdade, existe uma consulta de mídia para isso:

@media (hover: none) {  }

Além do Firefox, é bastante bem suportado . Sendo o Safari e o Chrome os navegadores mais comuns em dispositivos móveis, pode ser suficiente até uma adoção maior.

Buzut
fonte
2
... e apoio chegando nas próximas semanas também para FF.
retrovertigo
5

Isso vai funcionar. Se não me avisar

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

editar: pairar sob demanda não é mais suportado

aleksa_95
fonte
3

Esta solução funcionará até que o CSS4 seja globalmente suportado por todos os navegadores. Quando esse dia chegar, use CSS4. mas até então, isso funciona para navegadores atuais.

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())
};

carregando:

à moda antiga:

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

maneira mais recente:

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

O código acima adicionará a classe "is-touch" à etiqueta do corpo, se o dispositivo tiver uma tela de toque. Agora, qualquer local em seu aplicativo da Web onde você teria CSS para: pairar, você pode chamarbody:not(.is-touch) the_rest_of_my_css:hover

por exemplo:

button:hover

torna-se:

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

Esta solução evita o uso do modernizador, pois a biblioteca modernizadora é uma biblioteca muito grande. Se tudo o que você está tentando fazer é detectar telas sensíveis ao toque, será melhor quando o tamanho da fonte compilada final for um requisito.

Patrick W. McMahon
fonte
0

adicionando uma tela de toque de classe ao corpo usando JS ou jQuery

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

Consegui resolver esse problema usando este

@media (hover:none), (hover:on-demand) { 
Your class or ID{
attributes
}    
}
Robin Mehdee
fonte
FYI, on-demandfoi removido das especificações e dos navegadores: github.com/w3c/csswg-drafts/commit/…
retrovertigo