我创建了一个带有前一个和下一个按钮的轮播,这些按钮始终可见。这些按钮具有悬停状态,它们变为蓝色。在触控设备(如iPad)上,悬停状态是粘性的,因此按下按钮后按钮会保持蓝色。我不希望这样。
我可以为每个按钮添加no-hover
班ontouchend
,然后制作
我的CSS是这样的:button:not(.no-hover):hover { background-color:
blue; }
但这可能对性能非常不利,但事实并非如此
处理像Chromebook Pixel这样的设备
触摸屏和鼠标)正确。
我可以将touch
类添加到documentElement
并制作我的CSS
像这样:html:not(.touch) button:hover { background-color: blue;
}
但是这也无法在具有touch和a的设备上正常工作
鼠标。
我更喜欢删除悬停状态ontouchend
。但这似乎不太可能。聚焦另一个元素不会消除悬停状态。手动点击另一个元素,但我似乎无法在JavaScript中触发它。
我发现的所有解决方案似乎都不完美。有完美的解决方案吗?
答案 0 :(得分:51)
您可以通过暂时从DOM中删除链接来删除悬停状态。见http://testbug.handcraft.com/ipad.html
在CSS中你有:
:hover {background:red;}
在JS中你有:
function fix()
{
var el = this;
var par = el.parentNode;
var next = el.nextSibling;
par.removeChild(el);
setTimeout(function() {par.insertBefore(el, next);}, 0)
}
然后在你的HTML中你有:
<a href="#" ontouchend="this.onclick=fix">test</a>
答案 1 :(得分:51)
实施CSS Media Queries Level 4后,您就可以执行此操作:
@media (hover: hover) {
button:hover {
background-color: blue;
}
}
或者用英语:&#34;如果浏览器支持正确/真实/真实/非模拟悬停(例如,具有类似鼠标的主要输入设备),则在button
悬停时应用此样式在&#34;
由于Media Queries Level 4的这一部分到目前为止只在最前沿的Chrome中实现,I wrote a polyfill才能解决这个问题。使用它,您可以将上面的未来派CSS转换为:
html.my-true-hover button:hover {
background-color: blue;
}
(.no-touch
技术的变体)然后使用来自检测支持悬停的相同polyfill的一些客户端JavaScript,您可以相应地切换my-true-hover
类的存在:
$(document).on('mq4hsChange', function (e) {
$(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
答案 2 :(得分:25)
这是一个常见问题,没有完美的解决方案。悬停行为对鼠标很有用,而且对触摸大多不利。使问题更加复杂的是支持触摸和鼠标的设备(同时,不低于!),如Chromebook Pixel和Surface。
我发现最干净的解决方案是,如果设备不被视为支持触摸输入,则仅启用悬停行为。
var isTouch = !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;
if( !isTouch ){
// add class which defines hover behavior
}
当然,你会丢失悬停在可能支持它的设备上。但是,有时候悬停的影响比链接本身更多,例如也许你想在元素悬停时显示一个菜单。这种方法允许您测试触摸的存在,并可能有条件地附加不同的事件。
我在iPhone,iPad,Chromebook Pixel,Surface和各种Android设备上进行了测试。我不能保证当混合使用通用USB触摸输入(例如手写笔)时它会起作用。
答案 3 :(得分:10)
使用Modernizr,您可以专门针对无触摸设备定位您的悬停:
(注意:这不会在StackOverflow的代码段系统上运行,请检查jsfiddle)
/* this one is sticky */
#regular:hover, #regular:active {
opacity: 0.5;
}
/* this one isn't */
html.no-touch #no-touch:hover, #no-touch:active {
opacity: 0.5;
}
请注意,:active
不需要定位.no-touch
,因为它在移动设备和桌面设备上都能正常运行。
答案 4 :(得分:6)
来自4 ways to deal with sticky hover on mobile:这是根据用户的当前输入类型动态添加或删除文档的“can touch
”类的方法。它适用于混合设备,用户可以在触摸和鼠标/触控板之间切换:
<script>
;(function(){
var isTouch = false //var to indicate current input type (is touch versus no touch)
var isTouchTimer
var curRootClass = '' //var indicating current document root class ("can-touch" or "")
function addtouchclass(e){
clearTimeout(isTouchTimer)
isTouch = true
if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
curRootClass = 'can-touch'
document.documentElement.classList.add(curRootClass)
}
isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
}
function removetouchclass(e){
if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
isTouch = false
curRootClass = ''
document.documentElement.classList.remove('can-touch')
}
}
document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();
</script>
答案 5 :(得分:5)
$("#elementwithhover").click(function() {
// code that makes element or parent slide or otherwise move out from under mouse.
$(this).clone(true).insertAfter($(this));
$(this).remove();
});
答案 6 :(得分:2)
对于不支持悬停的设备,您可以覆盖悬停效果。喜欢:
.my-thing {
color: #BADA55;
}
.my-thing:hover {
color: hotpink;
}
@media (hover: none) {
.my-thing {
color: #BADA55;
}
}
在iOS 12上经过测试和验证
答案 7 :(得分:2)
我打算发布我自己的解决方案,但是检查是否有人发布了它,我发现@Rodney差点做到了。然而,至少在我的情况下,他错过了最后一个让它变得不明智的关键。我的意思是,我也通过.fakeHover
和mouseenter
事件检测添加/删除相同的mouseleave
类,但仅此一项本身,几乎就像&#34;真正&#34; :hover
。我的意思是:当你点击表格中的元素时,它不会发现你已经离开了#34;它 - 从而保持&#34; fakehover&#34;状态。
我所做的只是听click
,所以当我&#34;点击&#34;按钮,我手动触发mouseleave
。
这是我的最终代码:
.fakeHover {
background-color: blue;
}
$(document).on('mouseenter', 'button.myButton',function(){
$(this).addClass('fakeHover');
});
$(document).on('mouseleave', 'button.myButton',function(){
$(this).removeClass('fakeHover');
});
$(document).on('button.myButton, 'click', function(){
$(this).mouseleave();
});
这样,当您使用鼠标时,只需&#34;悬停&#34;在你的按钮上。嗯,差不多全部:唯一的缺点是,用鼠标点击按钮后,它不会处于hover
状态。就像你点击并快速将指针从按钮中取出一样。但在我的情况下,我可以忍受。
答案 8 :(得分:2)
从2020年开始,您可以在媒体查询中添加悬停样式
@media (hover: hover) and (pointer: fine) {
/* css hover class/style */
}
此媒体查询表明,样式将在未模拟:hover的浏览器上工作,因此在触摸浏览器上将无法工作。
答案 9 :(得分:1)
将此JS代码添加到您的页面:
document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';
现在在你的CSS之前每个悬停添加像这样的悬停类:
.hover .foo:hover {}
如果设备是触摸的,则body类将为空,否则其类将悬停并应用规则!
答案 10 :(得分:1)
我可以为每个按钮添加一个无悬停类ontouchend,并使我的CSS像&gt; this:button:not(.no-hover):hover {background-color: 蓝色;但这可能对性能非常不利,并且不能正确处理Chromebook Pixel(同时具有触摸屏和鼠标)等设备&gt;
这是正确的起点。下一步: 在以下事件上应用/删除nohover类(使用jQuery演示)
buttonelement
.on("touchend touchcancel",function(){$(this).addClass("nohover")})
.on("touchstart mouseover",function({$(this).removeClass("nohover")});
注意:如果您希望将其他类应用于buttonelement,则CSS中的not(.nohover)将不再按预期工作。比你必须用默认值和!important标签添加一个单独的定义来覆盖悬停样式: .nohover {background-color:white!important}
这甚至可以正确处理Chromebook Pixel(同时具有触摸屏和鼠标)等设备!我不认为,这是一个主要的性能杀手......
答案 11 :(得分:1)
对我有用的解决方案:
html {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
将此代码添加到样式表中。
我希望摆脱点击链接时出现在iOS Safari上的灰色背景。但它似乎做得更多。现在点击一个按钮(带有:hover
伪类!)立即打开!我只是在iPad上测试过,我不知道它是否适用于其他设备。
答案 12 :(得分:1)
我认为我找到了一个针对类似问题的优雅(最小js)解决方案:
使用jQuery,您可以使用.mouseover()
所以我只是将这个处理程序附加到元素的ontouchend
事件中,如下所示:
var unhover = function() {
$("body").mousover();
};
.hoverable {
width: 100px;
height: 100px;
background: teal;
cursor: pointer;
}
.hoverable:hover {
background: pink;
}
<div class="hoverable" ontouchend={unhover}></div>
但是,这只会删除:在触发其他触摸事件后将光标悬停在该元素上,例如滑动或其他触摸
答案 13 :(得分:1)
这是我在研究其余答案后到目前为止所提出的。它应该能够支持仅限触摸,仅限鼠标或混合用户。
为悬停效果创建单独的悬停类。默认情况下,将此悬停类添加到我们的按钮。
我们不希望从一开始就检测到触摸支持的存在并禁用所有悬停效果。正如其他人所提到的,混合设备越来越受欢迎;人们可能有触摸支持,但想要使用鼠标,反之亦然。因此,仅在用户实际触摸按钮时删除悬停类。
接下来的问题是,如果用户想要在触摸按钮后返回使用鼠标怎么办?要解决这个问题,我们需要找到一个合适的时机来添加我们已删除的悬停类。
但是,我们无法在删除它后立即将其添加回来,因为悬停状态仍处于活动状态。我们可能也不想破坏和重新创建整个按钮。
所以,我想过使用忙等待算法(使用setInterval)来检查悬停状态。一旦停用悬停状态,我们就可以添加回悬停类并停止忙等待,使我们回到用户可以使用鼠标或触摸的原始状态。
我知道忙碌的等待不是很好,但我不确定是否有适当的事件。我考虑过将它添加回mouseleave事件,但它不是很强大。例如,触摸按钮后弹出警报时,鼠标位置会发生变化,但不会触发mouseleave事件。
var button = document.getElementById('myButton');
button.ontouchstart = function(e) {
console.log('ontouchstart');
$('.button').removeClass('button-hover');
startIntervalToResetHover();
};
button.onclick = function(e) {
console.log('onclick');
}
var intervalId;
function startIntervalToResetHover() {
// Clear the previous one, if any.
if (intervalId) {
clearInterval(intervalId);
}
intervalId = setInterval(function() {
// Stop if the hover class already exists.
if ($('.button').hasClass('button-hover')) {
clearInterval(intervalId);
intervalId = null;
return;
}
// Checking of hover state from
// http://stackoverflow.com/a/8981521/2669960.
var isHovered = !!$('.button').filter(function() {
return $(this).is(":hover");
}).length;
if (isHovered) {
console.log('Hover state is active');
} else {
console.log('Hover state is inactive');
$('.button').addClass('button-hover');
console.log('Added back the button-hover class');
clearInterval(intervalId);
intervalId = null;
}
}, 1000);
}
.button {
color: green;
border: none;
}
.button-hover:hover {
background: yellow;
border: none;
}
.button:active {
border: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='myButton' class='button button-hover'>Hello</button>
编辑:我尝试的另一种方法是在ontouchstart或ontouchend中调用e.preventDefault()
。触摸按钮时似乎会停止悬停效果,但它也会停止按钮单击动画并阻止触摸按钮时调用onclick功能,因此您必须在ontouchstart或ontouchend处理程序中手动调用它们。不是一个非常干净的解决方案。
答案 14 :(得分:1)
这里有一些简单的JavaScript代码,不需要开发人员编辑CSS或编写任何新的CSS规则。我使用class="btn"
为Bootstrap按钮编写了此代码,但是它可以与具有特定类名的任何按钮一起使用。
步骤是:
document.styleSheets
中的每条CSS规则.btn
和:hover
的规则消除所有.btn :hover
CSS规则可确保按钮上没有视觉上的悬停效果。
检查媒体查询中是否存在(hover: none)
:
const hasMatchMedia = typeof window.matchMedia !== 'undefined';
/**
* determine if device is touch-capable
* true - device is touch-capable
* false - device is not touch-capable
* null - unable to determine touch capability
* @return {null|boolean}
*/
const hasTouch = () => {
if (hasMatchMedia) {
return window.matchMedia('(hover: none)').matches;
}
return null;
};
/**
* remove all CSS rules contaning both '.btn' and ':hover'
* @return {number} count of rules deleted
*/
function removeBtnHovers () {
let rulesDeleted = 0;
// recursively delete '.btn:hover' rules
function recursiveDelete (rules, styleSheet) {
if (typeof rules === 'undefined' ||
typeof rules.length === 'undefined' ||
rules.length <= 0) {
return;
}
// iterate in reverse order,
// deleting any rule containing both '.btn' and ':hover'
const ruleLen = rules.length;
for (let i = ruleLen - 1; i >= 0; i--) {
const rule = rules[i];
if (typeof rule.cssRules === 'undefined') {
// a standard rule, evaluate it
const cssText = rule.cssText;
if (typeof cssText === 'string' &&
cssText.includes('.btn') &&
cssText.includes(':hover')) {
styleSheet.deleteRule(i);
rulesDeleted++;
}
} else {
// rule contains cssRules, iterate over them
recursiveDelete(rule.cssRules, rule);
}
}
}
// iterate over all style sheets in document
for (const styleSheet of document.styleSheets) {
let rules = styleSheet.cssRules;
if (!rules) { continue; }
recursiveDelete(rules, styleSheet);
}
return rulesDeleted;
}
terrymorse.com上的实时演示。
答案 15 :(得分:1)
对我有帮助:link
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");
}
}
}
}
}
}
答案 16 :(得分:0)
我遇到了类似的问题,我的应用程序与所有屏幕尺寸兼容,在基于 desktop-screen-size /鼠标的设备中产生了很多悬停效果,后来我意识到基于触摸的设备导致了一种状况,称为“粘滞悬停”,这对于使基于触摸的设备用户正常运行该应用程序是一个障碍。
我们在应用中使用了 SCSS 。并且我定义了 mixin 来照顾基于触摸的设备。
@mixin hover-support {
@media not all and (pointer: coarse) {
&:hover {
@content;
}
}
}
然后将我所有的CSS类放在以下代码段下。
@include hover-support() {
// Your css-classes or css that you want to apply on those devices that support hover.
}
例如,我们有一个用于使图标动画化的类,当您将鼠标悬停在图标上时,该类便会触发,就像您从CSS中看到的那样,但是在基于触摸的设备中,它受到粘滞悬停效果的影响,然后我将其放置在 @include hover-support()中以确保悬浮仅适用于支持悬浮的设备。
@include hover-support() {
.animate-icon {
-webkit-transition: all 0.2s;
transition: all 0.2s;
&:hover {
transform: scale(1.3);
filter: brightness(85%);
cursor: pointer;
}
}
}
答案 17 :(得分:0)
到目前为止,我在项目中所做的是恢复触摸设备上的Mockito.reset(mockAppender);
Mockito.when(mockAppender.getName()).thenReturn("MockAppender");
Mockito.when(mockAppender.isStarted()).thenReturn(true);
Mockito.when(mockAppender.isStopped()).thenReturn(false);
更改:
:hover
所有类名和命名颜色仅用于演示目的; - )
答案 18 :(得分:0)
对我来说,解决方案是在touchend之后克隆并替换节点...我讨厌这样做,但是即使尝试使用offsetHeight重新绘制元素也无法正常工作
const express = require('express');
const secure = require('express-force-https');
const app = express();
app.use(secure);
答案 19 :(得分:0)
可以通过交换HTML类来完成。它应该比删除整个元素更不容易出现毛刺,尤其是对于较大的图像链接等。
我们还可以决定在触摸(滚动)滚动时是否要触发悬停状态,甚至添加超时来延迟它们。
我们代码中唯一的重大变化将是在实现新行为的元素上使用其他HTML类,例如<a class='hover'></a>
。
HTML
<a class='my-link hover' href='#'>
Test
</a>
CSS
.my-link:active, // :active can be turned off to disable hover state on 'touchmove'
.my-link.hover:hover {
border: 2px dotted grey;
}
JS (使用jQuery)
$('.hover').bind('touchstart', function () {
var $el;
$el = $(this);
$el.removeClass('hover');
$el.hover(null, function () {
$el.addClass('hover');
});
});
示例
https://codepen.io/mattrcouk/pen/VweajZv
-
尽管我没有任何设备可以同时使用鼠标和触摸进行测试。
答案 20 :(得分:0)
javascrpt 太容易用了。那不是悬停问题,那是焦点问题。使用 css 聚焦时将大纲设置为无。
.button:focus {
outline: none;
}
答案 21 :(得分:0)
对我来说最好的方法是使用 @media
只需使用默认样式覆盖 :hover
效果:
@media screen and (max-width:700px){
.element:hover{ /* add the same styles of non hover */ }
}
答案 22 :(得分:0)
在移动设备上出现一些发粘或卡滞的:hover
:focus
:active
问题可能是由于浏览器试图操纵屏幕而缺少<meta name="viewport" content="width=device-width">
造成的。
答案 23 :(得分:0)
我有一个很好的解决方案,我想分享。 首先,您需要像这样检测用户是否在移动设备上:
var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());
然后只需添加:
if (!touchDevice) {
$(".navbar-ul").addClass("hoverable");
}
在CSS中:
.navbar-ul.hoverable li a:hover {
color: #fff;
}
答案 24 :(得分:0)
这完美地分两步完成。
将您的正文标记设置为此<body ontouchstart="">
。我不是这个“黑客”的粉丝,但它允许iOS上的Safari立即对触摸作出反应。不确定如何,但它确实有效。
设置这样的可触摸类:
// I did this in SASS, but this should work with normal CSS as well
// Touchable class
.example {
// Default styles
background: green;
// Default hover styles
// (Think of this as Desktop and larger)
&:hover {
background: yellow;
}
// Default active styles
&:active {
background: red;
}
// Setup breakpoint for smaller device widths
@media only screen and (max-width: 1048px) {
// Important!
// Reset touchable hover styles
// You may want to use the same exact styles as the Default styles
&:hover {
background: green;
}
// Important!
// Touchable active styles
&:active {
background: red;
}
}
}
您可能还想删除可触摸类上的任何动画。 Android Chrome似乎比iOS慢一点。
如果用户在触摸您的课程时滚动页面,这也会导致应用活动状态。
答案 25 :(得分:0)
你可以这样试试。
的javascript:
var isEventSupported = function (eventName, elementName) {
var el = elementName ? document.createElement(elementName) : window;
eventName = 'on' + eventName;
var isSupported = (eventName in el);
if (!isSupported && el.setAttribute) {
el.setAttribute(eventName, 'return;');
isSupported = typeof el[eventName] == 'function';
}
el = null;
return isSupported;
};
if (!isEventSupported('touchstart')) {
$('a').addClass('with-hover');
}
的CSS:
a.with-hover:hover {
color: #fafafa;
}
答案 26 :(得分:0)
您可以在:active
州设置背景颜色,并为:focus
提供defaut背景。
如果您通过onfocus/ontouch
设置背景颜色,则:focus
状态消失后颜色样式仍然存在。
您需要重置onblur
以便在焦点丢失时恢复defaut bg。
答案 27 :(得分:0)
根据Darren Cooks的答案,如果你将手指放在另一个元素上,这个答案也有效。
请参阅Find element finger is on during a touchend event
jQuery(function() {
FastClick.attach(document.body);
});
// Prevent sticky hover effects for buttons on touch devices
// From https://stackoverflow.com/a/17234319
//
//
// Usage:
// <a href="..." touch-focus-fix>..</a>
//
// Refactored from a directive for better performance and compability
jQuery(document.documentElement).on('touchend', function(event) {
'use strict';
function fix(sourceElement) {
var el = $(sourceElement).closest('[touch-focus-fix]')[0];
if (!el) {
return;
}
var par = el.parentNode;
var next = el.nextSibling;
par.removeChild(el);
par.insertBefore(el, next);
}
fix(event.target);
var changedTouch = event.originalEvent.changedTouches[0];
// http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchend-event
if (!changedTouch) {
return;
}
var touchTarget = document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
if (touchTarget && touchTarget !== event.target) {
fix(touchTarget);
}
});
答案 28 :(得分:0)
这对我有用:将悬停样式放在一个新类
中$(".someclass > li").on("mouseenter", function(e) {
$(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
$(this).removeClass("fakehover");
});
然后在需要时添加/删除课程
{{1}}
重复touchstart和touchend事件。或者您喜欢的任何事件以获得所需的结果,例如我希望在触摸屏上切换悬停效果。