ChatGPT解决这个技术问题 Extra ChatGPT

如何防止触摸设备上按钮的粘滞悬停效果

我创建了一个带有始终可见的上一个和下一个按钮的轮播。这些按钮有一个悬停状态,它们变成蓝色。在 iPad 等触控设备上,悬停状态是粘性的,因此在点击后按钮会保持蓝色。我不想要那个。

我可以为每个按钮添加一个 no-hover 类 ontouchend,并使我的 CSS 像这样: button:not(.no-hover):hover { background-color: blue;但这可能对性能很不利,并且不能正确处理 Chromebook Pixel(同时具有触摸屏和鼠标)之类的设备。

我可以向 documentElement 添加一个触摸类,并使我的 CSS 像这样: html:not(.touch) button:hover { background-color: blue;但这也不适用于同时具有触摸和鼠标的设备。

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

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

这是一个非常好的解决方案,@dasfdsa!但是,它不是同时支持触摸屏和鼠标的设备的解决方案。

P
Phoenix

由于 CSS Media Queries Level 4 的这一部分现在是 widely implemented since 2018,您可以使用它:

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}

或者用英语:“如果浏览器支持正确/真实/真实/非模拟悬停(例如具有类似鼠标的主要输入设备),则在 button 悬停时应用此样式。”

对于未实现此功能(或在此原始答案时尚未实现)的浏览器,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);
});

谢谢!就我的目的而言,这似乎在大多数浏览器 caniuse.com/#search=media%20queries 中都受支持并且运行良好,谢谢!
您需要查看 caniuse.com/#feat=css-media-interaction ,您会发现 Firefox 和 IE11 不支持它 :( 所以您需要 polyfill
似乎不再支持 polyfill(repo 已存档),它需要 jQuery ......
这现在在移动浏览器中得到了广泛的支持,并且就像一个魅力。我认为这应该是公认的答案。
这实际上并不能解决双输入设备的问题。 (我是从 Surface Book 2 写的。)您可以在通过触摸按下按钮后移动鼠标/触摸板,但这是一个粗制滥造的修复。我们真的需要一个仅适用于鼠标悬停的伪类。
3
3 revs, 2 users 88%

您可以通过暂时从 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>

@Chris 好点,我更改了示例以在 ontouchend 事件中设置 onclick 处理程序。
请考虑在您的答案中添加最少的演示代码。谢谢! stackoverflow.com/help/how-to-answer
@SjoerdVisscher 我已将其粘贴进去。StackOverflow 喜欢将代码放在答案中,因为链接可能会消失。 (在这种情况下,它不仅需要点击,还需要查看源代码,并确定哪些位是有问题的技术。)
@KevinBorders 是的,在某些设备上,移除和重新插入元素之间的时间延迟可能非常明显。不幸的是,我在我的 android 4.4 设备上发现没有 setTimeout 这样做是行不通的。
@DarrenCook 但是删除元素并重新添加它是个好主意吗?我想这会导致“janking”并与应用程序的 60fps 黄油流畅需求发生冲突。
T
Tim M.

这是一个没有完美解决方案的常见问题。悬停行为对鼠标很有用,但对触摸大多不利。使问题更加复杂的是支持触摸和鼠标的设备(同时,不少于!),例如 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 触摸输入(例如手写笔)添加到混合中时它会起作用。


太棒了,这对我有用,不像社区维基/达伦库克的回答。
好答案。这是一个类似的解决方案:stackoverflow.com/a/39787268/885464
不错的解决方案!但不适用于同时支持触摸和鼠标的设备。
O
OrganicPanda

您可以覆盖不支持悬停的设备的悬停效果。喜欢:

.my-thing {
    color: #BADA55;
}

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

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}

在 iOS 12 上测试和验证

https://stackoverflow.com/a/50285058/178959 致敬以指出这一点。


这是更现代的解决方案,不需要 javascript 或 DOM 操作,具有完整的浏览器支持(IE 除外),应该是公认的答案。
还要检查:css-tricks.com/…
这也不适用于双模设备(触摸屏笔记本电脑等)。如果浏览器同时具有触摸输入和指针输入,hover: none 将不成立。
D
Dawid Świtoń-Maniakowski

从 2020 年起,您可以在媒体查询中添加悬停样式

@media (hover: hover) and (pointer: fine) {
    /* css hover class/style */
}

此媒体查询表明样式将适用于不模拟 :hover 的浏览器,因此它不适用于触摸浏览器。


这适用于仅触摸浏览器,即没有可用常规指针的触摸屏。它不能解决例如触摸屏笔记本电脑的问题。
A
Aleksander Azizi

使用 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;
}

请注意,不需要使用 .no-touch 定位 :active,因为它在移动设备和桌面设备上都可以正常工作。


这是 IMO 的最佳答案,但示例不正确。它为触摸和非触摸设备显示相同的悬停状态。如果 .no-touch 出现在 html 标记上,它应该只应用悬停状态。否则,这个答案会得到我的认可。
问题是现在有触摸屏的鼠标设备到处都是,你不能再依赖这种方法了。但是我看不到很多其他的方法......这是一个两难的选择
我想一种方法是同时使用 Modernizr 以及诸如 mobile-detect.js 之类的库,以确保它是手机或平板电脑。
你是救世主,非常感谢这对移动设备非常有效
这并不能解决多输入设备的问题。 no-touch 类应用于我的 Surface Book 2(触控板 + 触摸屏),但 :hover 规则保留在您的小提琴链接中。
G
Graham P Heath
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});

您可以使用 on() 而不是 click() 来改进这个答案。通过从 DOM 中删除元素并重新附加它,我丢失了点击事件。当我用 on 重写我的函数时,绑定到元素,然后删除和添加工作。例如: `$('body').on('click', '#elementwithhover',function() { // clone, insertafter, remove });如果你做出改变,我会投票赞成。
克隆 true 保留新元素上的单击事件,以代替带有卡住悬停的元素。原始元素在克隆后从 dom 中删除。
厉害了兄弟,10x
数小时寻找修复程序,这终于提供了一个。太感谢了!
c
coco puffs

来自 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>

这是我发现的最佳方式,另外,如果您将计时器增加到 1000 毫秒,您还可以覆盖长按,请参阅 here。好东西!
P
Pere

我打算发布我自己的解决方案,但检查是否有人已经发布它,我发现@Rodney 几乎做到了。然而,他错过了最后一个关键,这使它变得不协调,至少在我的情况下。我的意思是,我也通过 mouseentermouseleave 事件检测采用了相同的 .fakeHover 类添加/删除,但仅此一项,本身,几乎与“真正的”:hover .我的意思是:当你点击表格中的一个元素时,它不会检测到你已经“离开”了它——从而保持了“fakehover”状态。

我所做的也只是在 click 上收听,所以当我“点击”按钮时,我手动触发了 mouseleave

Si 这是我的最终代码:

.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 功能。好吧,几乎全部:唯一的缺点是,用鼠标单击按钮后,它不会处于 hover 状态。就像您单击并快速将指针移出按钮一样。但就我而言,我可以忍受。


K
Kevin Lee

这是我在研究了其余答案后得出的结论。它应该能够支持仅触摸、仅鼠标或混合用户。

为悬停效果创建一个单独的悬停类。默认情况下,将此悬停类添加到我们的按钮。

我们不想从一开始就检测是否存在触摸支持并禁用所有悬停效果。正如其他人所提到的,混合设备越来越受欢迎。人们可能有触摸支持,但想使用鼠标,反之亦然。因此,仅在用户实际触摸按钮时才删除悬停类。

下一个问题是,如果用户在触摸按钮后想要返回使用鼠标怎么办?为了解决这个问题,我们需要找到一个合适的时机来添加我们已经删除的悬停类。

但是,我们不能在删除它后立即将其添加回来,因为悬停状态仍然处于活动状态。我们可能也不想销毁并重新创建整个按钮。

所以,我想到了使用忙等待算法(使用 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'); } 变量间隔ID; function startIntervalToResetHover() { // 清除前一个,如果有的话。 if (intervalId) { clearInterval(intervalId); } intervalId = setInterval(function() { // 如果悬停类已经存在则停止 if ($('.button').hasClass('button-hover')) { clearInterval(intervalId); intervalId = null; return; } // 检查悬停状态 // 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('添加回button-hover类'); clearInterval(intervalId); intervalId = null; } }, 1000); } .button { 颜色:绿色;边框:无; } .button-hover:hover { 背景:黄色;边框:无; } .button:active { 边框:无; }

编辑:我尝试的另一种方法是在 ontouchstart 或 ontouchend 中调用 e.preventDefault()。当按钮被触摸时,它似乎停止了悬停效果,但它也停止了按钮单击动画,并防止在触摸按钮时调用 onclick 函数,因此您必须在 ontouchstart 或 ontouchend 处理程序中手动调用它们。不是一个非常干净的解决方案。


谢谢,我没有使用基于间隔的方法,但您最后关于 preventDefault 的信息非常有用——我在其他任何地方都没有看到过这个帖子!
m
mineroot

这对我有帮助: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");
                    }
                }
            }
        }
    }
}

您需要从全局 ontouchstart 事件处理程序调用 hoverTouchUnstick() 一次。这个解决方案将完美运行。
A
Ali

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

document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';

现在在每次悬停之前的 CSS 中添加悬停类,如下所示:

.hover .foo:hover {}

如果设备是触摸的,body 类将为空,否则它的类将为悬停并应用规则!


对我不起作用,但这确实有效:document.body.className = 'ontouchstart' in window ? '' : 'hover';
S
Sascha Hendel

我可以为每个按钮添加一个无悬停类 ontouchend,并使我的 CSS 像 >this: 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")});   

注意:如果您希望将其他类应用于按钮元素,CSS 中的 :not(.nohover) 将不再按预期工作。比您必须添加一个带有默认值和 !important 标记的单独定义来覆盖悬停样式: .nohover{ background-color: white !important}

这甚至应该可以正确处理 Chromebook Pixel(同时具有触摸屏和鼠标)之类的设备!而且我不认为,这是一个主要的性能杀手......


L
Leon Vogler

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

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

将此代码添加到您的样式表中。

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


M
Michał Reszka

我有很好的解决方案,我想分享。首先,您需要检测用户是否在移动设备上,如下所示:

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

不适用于混合设备,例如 Windows 触摸屏 PC。
D
Divyanshu Rawat

我遇到了类似的问题,我的应用程序兼容所有屏幕尺寸在基于桌面屏幕尺寸/鼠标的设备中有很多悬停效果,后来我意识到基于触摸的设备导致了一种称为粘滞的情况-悬停,这是应用程序对于基于触摸的设备用户正常工作的障碍。

我们在我们的应用程序中使用了 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 中看到的那样,但在基于触摸的设备中,它受到粘性悬停效果的影响,然后我将它放在 @包括 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;
    }
  }
}

t
terrymorse

这里有一些简单的 JavaScript 代码,不需要开发人员编辑 CSS 或编写任何新的 CSS 规则。我用 class="btn" 为 Bootstrap 按钮编写了这个,但它适用于任何具有特定类名的按钮。

步骤是:

确定这是否是触摸设备,如果是,遍历 document.styleSheets 中的每个 CSS 规则删除任何包含 .btn 和 :hover 的规则

消除所有 .btn :hover CSS 规则可确保按钮上没有视觉悬停效果。

第 1 步:检测触控设备

检查媒体查询是否存在 (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;
    };

第 2 步:删除包含 `btn` 和 `:hover` 的 CSS 规则

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

完整的代码在 GitHubnpm

terrymorse.com 上的现场演示。


这是否也消除了带有鼠标/触控板的触摸屏设备的悬停效果?
@Jensei 可能。如果设备匹配 @media (hover:none),或者当用户第一次触摸屏幕时,悬停规则将被删除。您可以在现场演示页面上试一试以确定。
G
G-Cyrillus

您可以在 :active 状态下设置背景颜色并为 :focus 提供默认背景。

如果您通过 onfocus/ontouch 设置背景颜色,一旦 :focus 状态消失,颜色样式将保持不变。
您还需要重置 onblur 以在失去焦点时恢复默认背景。


但我想为鼠标用户保持悬停效果。
:hover 和 :active 可以接收相同的 CSS,它在 :focus 你有问题。实际上,如果您通过 onfocus 设置背景颜色,那么一旦焦点消失,颜色样式就会保持不变。您还需要重置 onlur 以恢复默认 bg
R
Rodney

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

.fakehover {background: red}

然后在需要时添加/删除类

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

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


I
Ian Averno

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

使用 jQuery,您可以使用 .mouseover() 在正文(或任何其他元素)上触发悬停

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

var unhover = function() { $("body").mousover(); }; .hoverable { 宽度:100px;高度:100px;背景:蓝绿色;光标:指针; } .hoverable:hover { 背景:粉红色; }

但是,这只会在触发其他一些触摸事件(例如滑动或其他触摸)后从元素中删除 :hover 伪类


对于您的代码片段,在我触摸它之后,正方形仍然保持粉红色。我猜你并没有真正解决这个问题中提出的问题?
此解决方案不起作用。首先,您使用了错误的方法来调用事件,您应该使用 .trigger()。其次,无论哪种方式都不适用于移动野生动物园。
C
Community

基于 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);
  }
});

Codepen Demo


L
Lorenzo Polidori

你可以试试这个方法。

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

z
z00l

到目前为止,我在项目中所做的是恢复触摸设备上的 :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;
    }
}

所有类名和命名颜色仅用于演示目的;-)


M
Michael

这分两步完美运行。

将您的身体标签设置为像这样的 。我不是这种“黑客”的粉丝,但它允许 iOS 上的 Safari 立即对触摸做出反应。不知道如何,但它的工作原理。像这样设置你的 touchable 类: // 我在 SASS 中做了这个,但这也适用于普通 CSS // Touchable class .example { // 默认样式 background: green; // 默认悬停样式 // (将其视为桌面或更大) &:hover { background: yellow; } // 默认活动样式 &:active { background: red; } // 为较小的设备宽度设置断点 @media only screen and (max-width: 1048px) { // 重要! // 重置可触摸悬停样式 // 您可能希望使用与默认样式完全相同的样式 &:hover { background: green; } // 重要的! // 可触摸的活动样式 &:active { background: red; } } }

您可能还想删除可触摸类上的任何动画。 Android Chrome 似乎比 iOS 慢一点。

如果用户在触摸您的班级时滚动页面,这也将导致应用活动状态。


G
GEkk

移动设备上的一些粘滞或卡住的 :hover :focus :active 问题可能是由于浏览器试图操纵屏幕时缺少 <meta name="viewport" content="width=device-width"> 造成的。


M
Maciek Rek

它可以通过交换 HTML 类来完成。与删除整个元素相比,它应该更不容易出现故障,尤其是对于大型图像链接等。

我们还可以决定是否希望在触摸滚动时触发悬停状态(touchmove),甚至添加超时来延迟它们。

我们代码中唯一的重大变化是在实现新行为的元素上使用额外的 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

-

不过,我没有任何同时具有鼠标和触摸功能的设备来正确测试它。


K
Kng

那太容易使用javascrpt了。那不是悬停问题,那是焦点问题。使用 css 聚焦时将轮廓设置为无。

.button:focus {
outline: none;
}    

P
Pavindu

如果您是 CSS-in-JS 专家并正在寻找解决此问题的方法,那就是这里。
您可以使用 JS media queries 在 CSS-in-JS 中实现媒体查询。

例如,以下代码段仅在屏幕尺寸大于 768 像素时为按钮添加悬停效果。

tag: {
  cursor: "pointer",
  "&:hover, &:active": window.matchMedia('(min-width: 768px)').matches ? {
    transform: "scale(1.3)"
  } : null
}

B
Banning

我的解决方案是在 touchend 之后克隆和替换节点......我讨厌这样做,但即使尝试用 offsetHeight 重新绘制元素也不起作用

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );

最后,这对我不起作用……我的情况是,我必须克隆一个扩展的整个 ES6 和几个事件侦听器,而且解决这么小的事情变得越来越复杂。
C
Coderer

Kevin Lee's answer 在结尾处包含一些我在其他任何地方都没有见过的内容,它帮助我解决了这个多输入系统(如触摸屏笔记本电脑)的问题,而且工作量很少。

函数 f() { console.log("Hi"); } 按钮:悬停 { 边框:2px 纯蓝色; }

在多输入设备上运行此程序,您应该会看到鼠标指针悬停会创建一个蓝色边框,但按下触摸屏上的按钮不会。

唯一的缺点是您的 UI 框架中的任何其他点击功能(波纹动画等)可能不会触发。您也许可以自己手动触发它们-在我的情况下,这首先不是问题。