Как удалить / игнорировать: наведите курсор на стиль css на сенсорных устройствах

141

Я хочу игнорировать все :hoverобъявления CSS, если пользователь заходит на наш сайт через сенсорное устройство. Потому что :hoverCSS не имеет смысла, и это может даже беспокоить, если планшет запускает его при нажатии / нажатии, потому что тогда он может застрять, пока элемент не потеряет фокус. Честно говоря, я не знаю, почему сенсорные устройства чувствуют необходимость срабатывать :hoverв первую очередь - но это реальность, поэтому и эта проблема тоже реальность.

a:hover {
   color:blue;
   border-color:green;
   // etc. > ignore all at once for touch devices
}

Итак, (как) я могу удалить / игнорировать все :hoverобъявления CSS сразу (без необходимости знать каждое) для сенсорных устройств после их объявления?

Саймон Ферндригер
источник
Это похоже на « Как предотвратить эффекты
закрепления
1
Я обхожу это с помощью решения php, где я обнаруживаю, мобильное устройство просмотра или нет, и использую правильную таблицу стилей с различными изменениями, основанными на этом. Это не отвечает на ваш вопрос, хотя. Вы могли бы потенциально использовать запросы @media, но это не гарантировано, если телефоны и планшеты имеют полное разрешение HD.
TomFirth

Ответы:

171

tl; dr используйте это: https://jsfiddle.net/57tmy8j3/

Если вам интересно, почему или какие есть другие варианты, читайте дальше.

Quick'n'dirty - удалить: парить стили, используя JS

Вы можете удалить все правила CSS, содержащие :hoverс помощью Javascript. Преимущество этого в том, что вам не нужно трогать CSS и быть совместимым даже с более старыми браузерами.

function hasTouch() {
  return 'ontouchstart' in document.documentElement
         || navigator.maxTouchPoints > 0
         || navigator.msMaxTouchPoints > 0;
}

if (hasTouch()) { // remove all the :hover stylesheets
  try { // prevent exception on browsers not supporting DOM styleSheets properly
    for (var si in document.styleSheets) {
      var styleSheet = document.styleSheets[si];
      if (!styleSheet.rules) continue;

      for (var ri = styleSheet.rules.length - 1; ri >= 0; ri--) {
        if (!styleSheet.rules[ri].selectorText) continue;

        if (styleSheet.rules[ri].selectorText.match(':hover')) {
          styleSheet.deleteRule(ri);
        }
      }
    }
  } catch (ex) {}
}

Ограничения: таблицы стилей должны размещаться в одном и том же домене (это означает, что нет CDN). Отключает зависания на смешанных мышах и сенсорных устройствах, таких как Surface или iPad Pro, что вредно для UX.

Только CSS - используйте медиазапросы

Поместите все свои правила: hover в @mediaблок:

@media (hover: hover) {
  a:hover { color: blue; }
}

или, альтернативно, переопределите все ваши правила наведения (совместимые со старыми браузерами):

a:hover { color: blue; }

@media (hover: none) {
  a:hover { color: inherit; }
}

Ограничения: работает только на iOS 9.0+, Chrome для Android или Android 5.0+ при использовании WebView. hover: hoverустраняет эффекты парения в старых браузерах, hover: noneтребует переопределения всех ранее определенных правил CSS. Оба несовместимы со смешанными мышью и сенсорными устройствами .

Самое надежное - обнаруживать касания с помощью JS и добавлять CSS: правила наведения

Этот метод требует добавления всех правил наведения body.hasHover. (или имя класса по вашему выбору)

body.hasHover a:hover { color: blue; }

hasHoverКласс может быть добавлен с помощью hasTouch()из первого примера:

if (!hasTouch()) document.body.className += ' hasHover'

Однако это может иметь те же недостатки со смешанными сенсорными устройствами, что и в предыдущих примерах, что приводит нас к окончательному решению. Включить эффекты наведения при каждом перемещении курсора мыши, отключить эффекты при наведении при каждом касании.

function watchForHover() {
  // lastTouchTime is used for ignoring emulated mousemove events
  let lastTouchTime = 0

  function enableHover() {
    if (new Date() - lastTouchTime < 500) return
    document.body.classList.add('hasHover')
  }

  function disableHover() {
    document.body.classList.remove('hasHover')
  }

  function updateLastTouchTime() {
    lastTouchTime = new Date()
  }

  document.addEventListener('touchstart', updateLastTouchTime, true)
  document.addEventListener('touchstart', disableHover, true)
  document.addEventListener('mousemove', enableHover, true)

  enableHover()
}

watchForHover()

Это должно работать в основном в любом браузере и включать / отключать стили при наведении.

Вот полный пример - современный: https://jsfiddle.net/57tmy8j3/
Legacy (для использования со старыми браузерами): https://jsfiddle.net/dkz17jc5/19/

лопасть
источник
Спасибо! Только один комментарий: не лучше ли сначала проверить, если document.styleSheetsсуществует, а не использовать try/catch?
Саймон Ферндригер
1
Я использовал try/catchтолько в случае, если появляется какая-то странная ошибка, которая может привести к сбою скрипта, например, deleteRule не работает из-за политики того же источника или нестабильной поддержки в IE (отредактировал комментарий, чтобы отразить это). Но да, в большинстве случаев достаточно простой проверки.
клинок
1
Стоит отметить, что браузеры для настольных компьютеров, включая Firefox, не приведут к «notouch». Они сообщают о понимании сенсорных событий.
Гарри B
3
Это решение не работает для смешанных устройств, где hover должен работать для мыши, но не для сенсорных событий
nbar
2
@Haneev это верно для большинства случаев, хотя не для вашего конкретного. Работа с вашими правилами усложнит код, что затруднит понимание ответа. Я бы предложил либо разделить правила, либо использовать 2-е решение, которое в любом случае является более надежным. Однако вы можете предложить редактирование, если вы можете улучшить первое решение, не усложняя его.
клинок
43

Указатель адаптации к спасению!

Поскольку это не было затронуто некоторое время, вы можете использовать:

a:link {
   color: red;
}

a:hover {
   color:blue;
}

@media (hover: none) {
   a:link {
      color: red;
   }
}

Посмотрите эту демонстрацию как в браузере своего компьютера, так и в браузере телефона . Поддерживается современными сенсорными устройствами .

Примечание . Имейте в виду, что поскольку основным входом (возможностью) Surface PC является мышь, он в конечном итоге станет синей ссылкой, даже если это отдельный экран (планшет). Браузеры всегда будут (по умолчанию) использовать наиболее точные возможности ввода.

Джейсон Т Ферингем
источник
Спасибо, это было бы удобно! Тем не менее, я попробовал это с Chrome в мобильном режиме, но это не сработало - когда я «нажал» на него, оно все равно стало синим ...
Саймон Ферндригер
1
@SimonFerndriger Это ограничение Chrome devtools. Попробуйте открыть ссылку в реальном устройстве только для касания.
Джейсон
1
Отлично работает на iPad Chrome / Safari против OS X Chrome / Safari. Спасибо! Наконец элегантное решение, которое вы хотели бы для такой небольшой визуальной проблемы.
rakaloof
3
Я только что попробовал это на моем настоящем iPhone 6S под управлением iOS 11, и ссылка стала синей.
Лукас Петр
1
Также попробовал это с Nexus 5X под управлением Android 8.1.0 и Chrome 68.0.3440.91. Ссылка стала синей.
Тревин Эйвери
12

Я столкнулся с той же проблемой (в моем случае с мобильными браузерами Samsung) и поэтому наткнулся на этот вопрос.

Благодаря ответу Calsal я нашел то, что, как мне кажется, исключит практически все настольные браузеры, потому что оно, кажется, распознается мобильными браузерами, которые я пробовал (см. Скриншот из скомпилированной таблицы: таблица обнаружения функций указателя CSS) ).

В веб-документах MDN говорится, что

Функция CSS @media указателя может использоваться для применения стилей в зависимости от того, является ли основной механизм ввода пользователя указательным устройством, и если да, то насколько он точен

,

Я обнаружил, что указатель: грубый - это то, что неизвестно всем браузерам на рабочем столе в прилагаемой таблице, но известно всем мобильным браузерам в одной таблице. Это кажется наиболее эффективным выбором, потому что все другие значения ключевых слов указателя дают противоречивые результаты.

Следовательно, вы могли бы создать медиа-запрос, как Calsal описано но слегка измененный. Он использует обратную логику, чтобы исключить все сенсорные устройства.

Sass mixin:

@mixin hover-supported {    
    /* 
     * https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer 
     * coarse: The primary input mechanism includes a pointing device of limited accuracy.
     */
    @media not all and (pointer: coarse) {
        &:hover {
            @content;
        }
    }
}

a {
    color:green;
    border-color:blue;

    @include hover-supported() {
        color:blue;
        border-color:green;
    }
}

Скомпилированный CSS:

a {
  color: green;
  border-color: blue;
}
@media not all and (pointer: coarse) {
  a:hover {
    color: blue;
    border-color: green;
  }
}

Это также описано в этой сущности, которую я создал после исследования проблемы. Codepen для эмпирических исследований.

ОБНОВЛЕНИЕ : На момент написания этого обновления, 2018-08-23, и было отмечено @DmitriPavlutin, этот метод больше не работает с настольным компьютером Firefox.

ProgrammerPer
источник
Спасибо @DmitriPavlutin, согласно таблице (когда она была скомпилирована), она должна, но я мог бы взглянуть по-другому.
ProgrammerPer
@DmitriPavlutin Вы действительно правы. Обновлю ответ
ProgrammerPer
1
Вы имеете в виду, что он не работает на Firefox Desktop, если используется только с сенсорным устройством? Это прекрасно работает со всем, что я пробовал.
FuzzeeLowgeek
@FuzzeeLowgeek Звучит хорошо! Последний раз, когда я проверял, был 2018-08-23, так что, если вы можете подтвердить это наверняка, возможно, я смогу обновить ответ снова?
ProgrammerPer
9

Согласно ответу Джейсона, мы можем обращаться только к тем устройствам, которые не поддерживают hover, с чисто медиа-запросами CSS. Мы также можем обращаться только к устройствам, поддерживающим зависание, например, к ответу moogal на аналогичный вопрос @media not all and (hover: none). Это выглядит странно, но это работает.

Из этого я сделал миксин Sass для более легкого использования:

@mixin hover-supported {
    @media not all and (hover: none) {
        &:hover {
            @content;
        }
    }
}

Обновление 2019-05-15 : я рекомендую эту статью из Medium , в которой рассматриваются все различные устройства, на которые мы можем ориентироваться с помощью CSS. По сути, это микс этих медиа-правил, объединяющий их для определенных целей:

@media (hover: hover) {
    /* Device that can hover (desktops) */
}
@media (hover: none) {
    /* Device that can not hover with ease */
}
@media (pointer: coarse) {
    /* Device with limited pointing accuracy (touch) */
}
@media (pointer: fine) {
    /* Device with accurate pointing (desktop, stylus-based) */
}
@media (pointer: none) {
    /* Device with no pointing */
}

Пример для конкретных целей:

@media (hover: none) and (pointer: coarse) {
    /* Smartphones and touchscreens */
}

@media (hover: hover) and (pointer: fine) {
    /* Desktops with mouse */
}

Мне нравятся миксины, вот как я использую свой парящий миксин только для целевых устройств, которые его поддерживают:

@mixin on-hover {
    @media (hover: hover) and (pointer: fine) {
        &:hover {
            @content;
        }
    }
}

button {
    @include on-hover {
        color: blue;
    }
}
Calsal
источник
это не работает вообще. у вас есть hover: ни один в медиа-запросе для миксина с поддержкой hover? вам нужен указатель: грубый согласно другому ответу здесь.
Аллан Нинхёйс
Вы даже пробовали это или просто говорите, что это не работает, потому что выглядит странно? Вот почему я написал «Это выглядит странно» .. И это работает для меня без указателя: грубый.
Calsal
У меня были некоторые противоречивые результаты с CSS-подходом к этому на моем OnePlus 5T (как в Chrome, так и в Firefix). Это работало нормально на iOS, но я не мог заставить его работать на OnePlus. Я тщательно протестировал, используя любой указатель и любой указатель
Зет
6

Я имею дело с подобной проблемой в настоящее время.

У меня сразу возникает два основных варианта: (1) проверка пользовательских строк или (2) ведение отдельных мобильных страниц с использованием другого URL и предоставление пользователям выбора того, что лучше для них.

  1. Если вы можете использовать язык интернет-клейкой ленты, такой как PHP или Ruby, вы можете проверить пользовательскую строку устройства, запрашивающего страницу, и просто использовать тот же контент, но с <link rel="mobile.css" />обычным стилем вместо.

Пользовательские строки содержат идентифицирующую информацию о браузере, рендерере, операционной системе и т. Д. Вам решать, какие устройства являются «сенсорными», а не не сенсорными. Возможно, вы сможете найти эту информацию где-нибудь и отобразить ее в своей системе.

О. Если вам разрешено игнорировать старые браузеры , вам просто нужно добавить одно правило в обычный немобильный css, а именно: EDIT : Erk. После выполнения некоторых экспериментов, я обнаружил , что ниже правила также отключает способность следовать ссылки на WebKit-браузеров в дополнение к просто вызывает эстетический эффект будет отключен - см http://jsfiddle.net/3nkcdeao/
Таким образом , вы будете иметь быть немного более избирательным в отношении того, как вы изменяете правила для мобильного случая, чем то, что я показываю здесь, но это может быть полезной отправной точкой

* { 
    pointer-events: none !important; /* only use !important if you have to */
}

В качестве идентификатора, отключение событий указателя на родительском элементе и затем явное включение их на дочернем элементе в настоящее время приводит к тому, что любые эффекты наведения на родительский элемент снова становятся активными, если входит дочерний элемент :hover.
Смотрите http://jsfiddle.net/38Lookhp/5/

Б. Если вы поддерживаете устаревшие веб-рендереры, вам придется проделать немного больше работы, удаляя любые правила, которые устанавливают специальные стили во время :hover. Чтобы сэкономить время, вам может понадобиться создать команду автоматического копирования + sed, которую вы запускаете в своих стандартных таблицах стилей для создания мобильных версий. Это позволило бы вам просто написать / обновить стандартный код и удалить все правила стиля, которые используются :hoverдля мобильной версии ваших страниц.

  1. (I) В качестве альтернативы просто сообщите своим пользователям, что у вас есть m.website.com для мобильных устройств в дополнение к вашему website.com . Хотя поддомен является наиболее распространенным способом, вы можете также иметь некоторые другие предсказуемые модификации данного URL, чтобы позволить мобильным пользователям получать доступ к измененным страницам. На этом этапе вы хотели бы убедиться, что им не нужно изменять URL-адрес каждый раз, когда они переходят на другую часть сайта.

Опять же, здесь вы можете просто добавить одно или два дополнительных правила к таблицам стилей или сделать что-то более сложное, используя sed или аналогичную утилиту. Возможно, это будет проще всего применить: не к вашим правилам стиля, например, к которым div:not(.disruptive):hover {...вы добавляете class="disruptive"элементы, которые раздражают мобильных пользователей, использующих js или язык сервера, вместо манипулирования CSS.

  1. (II) Вы можете на самом деле объединить первые два и (если вы подозреваете, что пользователь перешел на неправильную версию страницы), вы можете предложить им переключаться на / из дисплея мобильного типа или просто иметь ссылку где-нибудь, что позволяет пользователям шлепаться взад и вперед. Как уже говорилось, запросы @media также могут быть полезны при определении того, что используется для посещения.

  2. (III) Если вы готовы к решению jQuery, когда вы знаете, какие устройства являются «сенсорными», а какие нет, вам может оказаться полезным игнорирование наведения мыши на устройствах с сенсорным экраном .

SeldomNeedy
источник
pointer-events- это восхитительно! Это именно то, что я искал, большое спасибо!
Саймон Ферндригер
1
@SimonFerndriger Ну, я надеюсь, что это будет полезно в будущем. Обязательно обратите внимание на то, что на сегодняшний день <a>ссылки могут быть недоступны при pointer-events:none. Если повезет, это изменится позже - или CSS 3.x или 4.0+ будут pointer-events:navigation-onlyили похожи.
SeldomNeedy
6

попробуй это:

@media (hover:<s>on-demand</s>) {
    button:hover {
        background-color: #color-when-NOT-touch-device;
    }
}

ОБНОВЛЕНИЕ: к сожалению, W3C удалил это свойство из спецификации ( https://github.com/w3c/csswg-drafts/commit/2078b46218f7462735bb0b5107c9a3e84fb4c4b1 ).

Маруэн Мхири
источник
Это действительно решило бы проблему. Я никогда не слышал об этом раньше. В какой версии браузера это должно работать?
Саймон Ферндригер
3
@SimonFerndriger caniuse.com/#feat=css-media-interaction и некоторая дополнительная информация: dev.opera.com/articles/media-features
Skeptic
Хорошо ... У него нет широкой поддержки браузера.
Джакомо Пайта
Это классно! Спасибо за такое удобное решение. Я надеюсь, что это будет добавлено к стандартам W3C.
GProst
рад, что смог помочь ^^
Маруен Мири
5

Вы можете использовать Modernizr JS (см. Также этот ответ StackOverflow ) или создать собственную функцию JS:

function is_touch_device() {
 return 'ontouchstart' in window        // works on most browsers 
  || navigator.maxTouchPoints;       // works on IE10/11 and Surface
};

if ( is_touch_device() ) {
  $('html').addClass('touch');
} else {
  $('html').addClass('no-touch');
} 

чтобы обнаружить поддержку сенсорного события в браузере, а затем присвоить регулярное CSSсвойство, пересекающий элемент с html.no-touchклассом, как это:

html.touch a {
    width: 480px;
}

/* FOR THE DESKTOP, SET THE HOVER STATE */
html.no-touch a:hover {
   width: auto;
   color:blue;
   border-color:green;
}
Джакомо Паита
источник
Это также было предложено @blade - однако, использование htmlтега вместо bodyтега может сделать его немного лучше для чтения. Это на самом деле решение, которое я сейчас использую. В любом случае, спасибо.
Саймон Ферндригер
1

Это было полезно для меня: ссылка

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
mineroot
источник
1

Это также возможный обходной путь, но вам нужно будет пройти через CSS и добавить .no-touch класс, прежде чем ваши стили наведения.

Javascript:

if (!("ontouchstart" in document.documentElement)) {
document.documentElement.className += " no-touch";
}

Пример CSS:

<style>
p span {
    display: none;
}

.no-touch p:hover span {
    display: inline;
}
</style>
<p><a href="/">Tap me</a><span>You tapped!</span></p>

Источник

PS Но мы должны помнить, что на рынке появляется все больше сенсорных устройств, которые одновременно поддерживают ввод с помощью мыши.

mr.mii
источник
0

Возможно, это еще не идеальное решение (и это с jQuery), но, возможно, это направление / концепция, над которой нужно работать: как насчет того, чтобы сделать это наоборот? Это означает, что по умолчанию необходимо деактивировать состояния: hover css и активировать их, если в любом месте документа обнаружено событие mousemove. Конечно, это не работает, если кто-то отключил JS. Что еще может говорить против этого?

Может быть так:

CSS:

/* will only work if html has class "mousedetected" */
html.mousedetected a:hover {
   color:blue;
   border-color:green;
}

JQuery:

/* adds "mousedetected" class to html element if mouse moves (which should never happen on touch-only devices shouldn’t it?) */
$("body").mousemove( function() {
    $("html").addClass("mousedetected");
});
Ларс в upstruct
источник
1
Одна проблема на самом деле в том, что это также .mousemove () при нажатии на что-то на сенсорных устройствах.
Ларс в upgrade
1
И вы, вероятно, будете запускать это событие без остановок, что окажет влияние на производительность. Если это сработает, то лучше использовать$('body').one.('mousemove', ...)
Саймон Ферндригер,
0

Попробуйте это (я использую background и background-color в этом примере):

var ClickEventType = ((document.ontouchstart !== null) ? 'click' : 'touchstart');

if (ClickEventType == 'touchstart') {
            $('a').each(function() { // save original..
                var back_color = $(this).css('background-color');
                var background = $(this).css('background');
                $(this).attr('data-back_color', back_color);
                $(this).attr('data-background', background);
            });

            $('a').on('touchend', function(e) { // overwrite with original style..
                var background = $(this).attr('data-background');
                var back_color = $(this).attr('data-back_color');
                if (back_color != undefined) {
                    $(this).css({'background-color': back_color});
                }
                if (background != undefined) {
                    $(this).css({'background': background});
                }
            }).on('touchstart', function(e) { // clear added stlye="" elements..
                $(this).css({'background': '', 'background-color': ''});
            });
}

CSS:

a {
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
HU TanKy
источник
0

Грязный путь ... Не элегантный, но самый простой способ, который может спасти вас.

Удалите все, что характеризует зависание.

.your-class:hover:before {
  color: blue;
  background: linear-gradient(to bottom, rgba(231,56,39,0) 0%, #aaaaaa 100%);
}

@media all and (min-width:320px) and (max-width: 960px) {
    .your-class:hover:before {
    color: black;
    background: transparent;
  }
}
Fellipe Sanches
источник
0

Если ваша проблема, когда вы касаетесь / нажимаете на Android и весь div покрыт синим прозрачным цветом! Тогда вам нужно просто изменить

КУРСОР: УКАЗАТЕЛЬ; КУРСОРУ: ПО УМОЛЧАНИЮ;

использовать mediaQuery, чтобы скрыть в мобильном телефоне / планшете.

Это работает для меня.

кунал шарма
источник
-1

Попробуйте это простое решение jquery 2019 года, хотя оно уже давно;

  1. добавить этот плагин в голову:

    SRC = "https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. добавить это к JS:

    $ ("*"). on ("touchend", function (e) {$ (this) .focus ();}); // применяется ко всем элементам

  3. некоторые предлагаемые варианты этого:

    $ (": input,: checkbox,"). on ("touchend", function (e) {(this) .focus);}); // указать элементы

    $ ("*"). on ("click, touchend", function (e) {$ (this) .focus ();}); // включить событие клика

    css: body {курсор: указатель; } // коснитесь где-нибудь, чтобы закончить фокус

Ноты

  • поместите плагин перед bootstrap.js, чтобы избежать влияния на всплывающие подсказки
  • протестировано только на iphone XR ios 12.1.12 и ipad 3 ios 9.3.5 с использованием Safari или Chrome.

Ссылки:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

Даррен
источник
2
В 2019 году вам не нужно будет использовать jQuery - WebAPI довольно мощный и поддерживает все основные функции.
акме
Я ... JQuery в 2019 году? Как насчет Flash? Hehehe.
drug.io