如何防止触摸设备上的button粘滞hover效果
我创build了一个旋转木马,上一个和下一个button始终可见。 这些button有一个hover状态,他们变成蓝色。 在触摸设备上,如iPad,hover状态是粘滞的,所以点击后button保持蓝色。 我不要那个。
-
我可以为每个button添加一个
no-hover
类,让我的CSS像这样:button:not(.no-hover):hover { background-color: blue; }
button:not(.no-hover):hover { background-color: blue; }
但是这可能对性能非常不利,并且无法正确处理像Chromebook Pixel(同时包含触摸屏和鼠标)的设备。 -
我可以添加一个
touch
类到documentElement
并使我的CSS如下所示:html:not(.touch) button:hover { background-color: blue; }
html:not(.touch) button:hover { background-color: blue; }
但是,这也不适用于具有触摸和鼠标的设备。
我更喜欢去掉hover状态ontouchend
。 但似乎并不是这样。 聚焦另一个元素不会消除hover状态。 手动点击另一个元素,但我似乎无法触发在JavaScript中。
我find的所有解决scheme似乎都不完善。 有没有完美的解决scheme?
您可以通过暂时删除DOM中的链接来删除hover状态。 请参阅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>
一旦实现了CSS Media Queries Level 4 ,你就可以做到这一点:
@media (hover: hover) { button:hover { background-color: blue; } }
或者用英文表示:“如果浏览器支持正确/真实/真实/非仿真hover(例如,有一个类似于鼠标的主input设备),则在button
shover时应用此样式。
由于第4层媒体查询的这一部分到目前为止只是在stream血的Chrome中实现, 所以我写了一个polyfill来处理这个问题。 使用它,你可以把上面的未来派的CSS变成:
html.my-true-hover button:hover { background-color: blue; }
( .no-touch
技术的一个变种)然后使用来自相同的polyfill的一些客户端JavaScript来检测对hover的支持,可以相应地切换my-true-hover
类的存在:
$(document).on('mq4hsChange', function (e) { $(document.documentElement).toggleClass('my-true-hover', e.trueHover); });
这是没有完美解决scheme的常见问题。 hover行为对于鼠标来说是有用的,并且大部分是有害的。 更复杂的问题是支持触摸和鼠标的设备(同时,不会less于!),就像Chromebook Pixel和Surface一样。
我发现最干净的解决scheme是只启用hover行为,如果设备不被视为支持触摸input。
var isTouch = !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0; if( !isTouch ){ // add class which defines hover behavior }
当然,你会失去hover在可能支持它的设备上。 然而,有时hover的影响比链接本身更多,例如,也许你想在一个元素被徘徊的时候显示一个菜单。 这种方法允许您testing触摸的存在,也许有条件地附加一个不同的事件。
我已经在iPhone,iPad,Chromebook Pixel,Surface以及各种Android设备上进行了testing。 当通用的USB触摸input(如触控笔)被添加到混音中时,我不能保证它可以工作。
使用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; }
从4种方式来处理移动粘滞hover :这是一种基于用户的当前inputtypesdynamic添加或删除“ 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>
$("#elementwithhover").click(function() { // code that makes element or parent slide or otherwise move out from under mouse. $(this).clone(true).insertAfter($(this)); $(this).remove(); });
我打算发布自己的解决scheme,但是如果有人已经发布了它,我发现@罗德尼差不多就这么做了。 不过,他错过了最后一个至关重要的因素,至less在我看来是无足轻重的。 我的意思是,我也采取了相同的.fakeHover
类加法/删除通过.fakeHover
和mouseleave
事件检测,但单独, 本身 ,行为几乎完全一样的“真正的” :hover
。 我的意思是:当你点击你桌子上的一个元素时,它不会检测到你已经“离开”它 – 从而保持“退色”状态。
我所做的只是简单地听click
,所以当我“点击”button时,我手动发射一个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(); });
这样,当您只是简单地将鼠标hover在button上时,就可以保持惯用的hover
function。 好吧,几乎所有的东西:唯一的缺点是,用鼠标点击button后,它不会处于hover
状态。 就像如果你点击并迅速把指针从button之外。 但在我的情况下,我可以忍受。
添加这个JS代码到你的页面:
document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';
现在在每个hover之前在你的CSS添加像这样的hover类:
.hover .foo:hover {}
如果设备触摸,主体类将是空的,否则它的类将hover和规则应用!
我可以为每个button添加一个无hover的类,让我的CSS像这样:button:not(.no-hover):hover {background-color:blue; }但是这可能对性能非常不利,并且不能像Chromebook Pixel(同时包含触摸屏和鼠标)>正确地处理设备。
这是正确的出发点。 下一步:在下列事件上应用/删除nohover类(使用jQuery进行演示)
buttonelement .on("touchend touchcancel",function(){$(this).addClass("nohover")}) .on("touchstart mouseover",function({$(this).removeClass("nohover")});
注意:如果您希望将其他类应用于buttonelement,CSS中的not(.nohover)将不再按预期工作。 比你必须添加一个单独的定义与默认值和!重要标签覆盖hover样式:.nohover {background-color:white!important}
这甚至应该正确处理像Chromebook Pixel(同时具有触摸屏和鼠标)的设备! 我不认为,这是一个主要的性能杀手…
这是我研究了其余的答案之后到目前为止所提出的。 它应该能够支持只触摸,仅鼠标或混合用户。
为hover效果创build单独的hover类。 默认情况下,将此hover类添加到我们的button。
我们不想检测触摸支持的存在,并从一开始就禁用所有的hover效果。 正如其他人所说,混合设备越来越受欢迎; 人们可能有触摸支持,但想要使用鼠标,反之亦然。 因此,只有在用户实际触摸button时才能移除hover类。
接下来的问题是,如果用户在触摸button后想要回到使用鼠标呢? 为了解决这个问题,我们需要find一个合适的时机来添加我们删除的hover类。
但是,由于hover状态仍处于活动状态,因此我们无法在删除后立即将其添加回去。 我们可能不想销毁并重新创build整个button。
所以,我想使用忙等待algorithm(使用setInterval)来检查hover状态。 一旦hover状态被停用,我们可以添加hover类并停止忙等待,使我们回到用户可以使用鼠标或触摸的原始状态。
我知道忙等待不是很好,但我不确定是否有适当的事件。 我已经考虑将它添加回mouseleave事件,但它不是很健壮。 例如,当触摸button后popup警报,鼠标位置移动,但不触发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>
你可以设置背景颜色:active
状态,并给:focus
的背景。
如果通过onfocus/ontouch
设置背景颜色,颜色样式将保持一次:focus
状态已经消失。
你需要在onblur
重置,以便在重点丢失时恢复默认的bg。
这对我有帮助: 链接
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"); } } } } } }
这为我工作:把hover式样在一个新的类
.fakehover {background: red}
然后根据需要添加/删除类
$(".someclass > li").on("mouseenter", function(e) { $(this).addClass("fakehover"); }); $(".someclass > li").on("mouseleave", function(e) { $(this).removeClass("fakehover"); });
重复touchstart和touchend事件。 或者任何喜欢得到想要的结果的事件,例如我想让hover效果在触摸屏上切换。
一个为我工作的解决scheme:
html { -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
将此代码添加到您的样式表。
我想摆脱点击链接时出现在iOS Safari上的灰色背景。 但似乎做得更多。 现在点击一个button(带有:hover
伪类!)马上被打开! 我只在iPad上testing过,我不知道它是否能在其他设备上工作。
我想我已经find了一个类似问题的优雅(最小的JS)解决scheme:
使用jQuery,你可以使用.mouseover()
来触发在body(或任何其他元素)上的hover,
所以我简单地把这个处理程序附加到元素的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>
根据Darren Cooks的回答,如果你将手指放在另一个元素上,这也是有效的。
在触发事件期间,请参阅查找元素手指处于打开状态
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); } });
Codepen演示
你可以试试这个方法
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; }
我到目前为止在我的项目中做的是恢复:hover
触摸设备上的:hover
更改:
.myhoveredclass { background-color:green; } .myhoveredclass:hover { background-color:red; } @media screen and (-webkit-min-device-pixel-ratio:0) { .myhoveredclass:hover, .myhoveredclass:active, .myhoveredclass:focus { background-color:green; } }
所有类名称和命名颜色仅用于演示目的;-)
这完美分两步完成。
-
设置你的身体标签是这样
<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; } } }
您也可以删除触摸式课程中的所有animation。 Android Chrome似乎比iOS慢一点。
如果用户在触摸课程的同时滚动页面,这也会导致应用活动状态。