Javascript 如何防止触摸设备上的按钮出现粘性悬停效果

Javascript 如何防止触摸设备上的按钮出现粘性悬停效果,javascript,css,hover,touch,Javascript,Css,Hover,Touch,我创建了一个旋转木马,上面有一个始终可见的“上一个”和“下一个”按钮。这些按钮处于悬停状态,它们变为蓝色。在像iPad这样的触摸设备上,悬停状态是粘性的,所以点击按钮后按钮保持蓝色。我不想那样 我可以为每个按钮添加一个no hoverclassontouchend,然后 我的CSS是这样的:按钮:不(.no hover):hover{背景色: 蓝色;}但这可能对性能非常不利,而且不会 处理像Chromebook Pixel这样的设备(它具有 触摸屏和鼠标)正确 我可以在documentElem

我创建了一个旋转木马,上面有一个始终可见的“上一个”和“下一个”按钮。这些按钮处于悬停状态,它们变为蓝色。在像iPad这样的触摸设备上,悬停状态是粘性的,所以点击按钮后按钮保持蓝色。我不想那样

  • 我可以为每个按钮添加一个
    no hover
    class
    ontouchend
    ,然后 我的CSS是这样的:
    按钮:不(.no hover):hover{背景色:
    蓝色;}
    但这可能对性能非常不利,而且不会 处理像Chromebook Pixel这样的设备(它具有 触摸屏和鼠标)正确

  • 我可以在
    documentElement
    中添加
    touch
    类,并制作CSS 如下:
    html:not(.touch)按钮:悬停{背景色:蓝色;
    }
    但这在既有触摸屏又有触摸屏的设备上也不起作用 老鼠

我更喜欢的是删除鼠标悬停状态
ontouchend
。但这似乎是不可能的。聚焦另一个元素不会移除悬停状态。手动点击另一个元素可以,但我似乎无法在JavaScript中触发它


我找到的所有解决方案似乎都不完美。有完美的解决方案吗?

您可以将背景色设置为
:active
状态,并将背景设置为
:focus

如果通过
onfocus/ontouch
设置背景色,颜色样式将保持一次
:focus
状态已消失。

当焦点丢失时,您还需要重置
onblur
以恢复defaut bg。

您可以通过临时从DOM中删除链接来删除悬停状态。看


在CSS中,您有:

:hover {background:red;}
function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}
<a href="#" ontouchend="this.onclick=fix">test</a>
在JS中,您有:

:hover {background:red;}
function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}
<a href="#" ontouchend="this.onclick=fix">test</a>
然后在HTML中,您有:

:hover {background:red;}
function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}
<a href="#" ontouchend="this.onclick=fix">test</a>

这是一个常见的问题,没有完美的解决方案。鼠标的悬停行为是有用的,而触摸则是有害的。使问题更加复杂的是支持触摸和鼠标的设备(同时,同样如此!),比如Chromebook像素和表面

我找到的最干净的解决方案是,只有当设备不支持触摸输入时,才启用悬停行为

var isTouch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

if( !isTouch ){
    // add class which defines hover behavior
}
当然,您在可能支持它的设备上失去了悬停。但是,有时悬停的影响比链接本身更大,例如,当元素悬停时,您可能希望显示菜单。这种方法允许您测试触摸是否存在,并可能有条件地附加不同的事件

我已经在iPhone、iPad、Chromebook Pixel、Surface和各种Android设备上进行了测试。我不能保证在混音中添加通用USB触控输入(如触控笔)时,它会起作用。

您可以专门针对非触控设备进行悬停:

.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;
    }
}
(注意:这不会在StackOverflow的代码段系统上运行,请检查)

请注意,
:active
不需要以
为目标。无需触摸
,因为它在移动设备和桌面上都能正常工作。

一旦实现,您将能够执行以下操作:

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}
或英文:“如果浏览器支持正确/真实/真实/非模拟悬停(例如,有一个类似鼠标的主输入设备),则在悬停
按钮时应用此样式。”

由于媒体查询级别4的这一部分到目前为止只在最前沿的Chrome中实现,因此需要解决这个问题。使用它,您可以将上述未来主义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);
});
这对我很有帮助:


这对我很有用:将悬停样式放在一个新类中

.fakehover {background: red}
然后根据需要添加/删除该类

$(".someclass > li").on("mouseenter", function(e) {
  $(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
  $(this).removeClass("fakehover");
});

对touchstart和touchend事件重复上述步骤。或者任何您希望获得所需结果的事件,例如,我希望在触摸屏上切换悬停效果。

将此JS代码添加到您的页面:

$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});
document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';
现在在CSS中,在每次悬停之前添加如下悬停类:

.hover .foo:hover {}
// 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;
        }
    }
}
var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());
如果设备为touch,body类将为空,否则其类将为hover,并应用规则

我可以为每个按钮在touchend上添加一个无悬停类,并使我的CSS类似于>this:button:not(.no hover):hover{background color: 蓝色;}但这可能对性能非常不利,并且不能正确处理>像Chromebook Pixel(它有触摸屏和鼠标)>这样的设备

这是正确的起点。下一步: 在以下事件上应用/删除nohover类(使用jQuery演示)

注意:如果您希望将其他类应用于ButtoneElement,CSS中的:not(.nohover)将不再像预期的那样工作。然后,您必须添加一个带有默认值和的单独定义!覆盖悬停样式的重要标记: .nohover{背景色:白色!重要}


这甚至可以正确处理Chromebook Pixel(它同时具有触摸屏和鼠标)等设备!我不认为这是一个主要的性能杀手…

一个对我有效的解决方案:

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
将此代码添加到样式表中


我想摆脱点击链接时iOS Safari上出现的灰色背景。但它似乎做得更多。现在,单击一个按钮(带有
:hover
伪类!)立即打开!我只在iPad上测试过,不知道它是否能在其他设备上使用

我想我已经为类似的问题找到了一个优雅的(最小js)解决方案:

使用jQuery,您可以使用
.mouseover()

因此,我只需将this处理程序附加到元素的
ontouchend
事件,如下所示:

var unhover=function(){
$(“body”).mousover();
};
。可悬停{
宽度:100px;
高度:100px;
背景:茶
.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;
    }
}
// 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;
        }
    }
}
var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());
if (!touchDevice) {
    $(".navbar-ul").addClass("hoverable");
}
.navbar-ul.hoverable li a:hover {
    color: #fff;
}
.my-thing {
    color: #BADA55;
}

.my-thing:hover {
    color: hotpink;
}

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}
@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}
   @include hover-support() {
    // Your css-classes or css that you want to apply on those devices that support hover.
   }
@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}
<a class='my-link hover' href='#'>
    Test
</a>
.my-link:active, // :active can be turned off to disable hover state on 'touchmove'
.my-link.hover:hover {

    border: 2px dotted grey;
}
$('.hover').bind('touchstart', function () {

   var $el;
   $el = $(this);
   $el.removeClass('hover'); 

   $el.hover(null, function () {
      $el.addClass('hover');
   });
});
@media (hover: hover) and (pointer: fine) {
    /* css hover class/style */
}
.button:focus {
outline: none;
}