【问题标题】:Hover state is maintained during a transition even if the element has gone即使元素已经消失,在转换期间也会保持悬停状态
【发布时间】:2014-06-20 03:51:35
【问题描述】:

考虑一个简单的元素及其关联的 CSS:

<div id="content">Hover me !</div>
#content {
    width: 100px;
    height: 100px;
}

#content:hover {
    transform: translateY(500px);
    transition: transform 1s 500ms;
}

JSFiddle

原理很简单:当元素悬停时,它必须向下。问题是,当鼠标不移动时,即使元素不再位于鼠标下方(由于翻译),:hover 状态也会保持不变。状态似乎只有在鼠标移动后才会更新。


注意光标(指针)及其与元素的相对位置!

只有当鼠标在元素上时才必须执行 JavaScript 函数,这是一个真正的问题,在 timeout 之后:

// The mouseleave event will not be called during the transition,
// unless the mouse move !

element.on('mouseenter', executeAfterTimeout);
element.on('mouseleave', cancelTimeout);

所以这是我的问题:

  1. 这种行为是否正常(符合规范)?
  2. 有哪些解决方案可以避免这个问题?

编辑:为了给你一个上下文,这是我想要做的具体事情:使用 JavaScript,当鼠标在一个元素上时我会显示一个工具提示(并且当鼠标离开它时隐藏它)。但是当用户点击它时,相同的元素可以是transform-ed。如果用户只是单击而不移动鼠标,则工具提示将保持显示,这是一个真正的问题。如何检测元素已消失?

【问题讨论】:

  • 这种行为在某种程度上是正常的,元素仍在使用您指向的房间,但通过翻译将其拉低。您可以用相对 nd 坐标来尝试相同的有趣行为,而不是 translate。
  • @GCyrillus 你有规范文件的链接吗?
  • 来自这样的在线编辑器:jsfiddle.net 或 codepen.io/pen
  • 嗯,我发现的唯一规范文件是:w3.org/TR/CSS2/selector.html#dynamic-pseudo-classes。它只说明了悬停的激活:“当用户指定一个元素(使用一些指针设备)时应用 :hover 伪类”,因此很明显悬停只能通过鼠标移动而不是通过鼠标移动激活翻译。可能停用也是这样实现的
  • 根据标准,该行为似乎是正常的。你到底需要完成什么?

标签: javascript css hover css-transitions css-transforms


【解决方案1】:

这种行为是正常的,以防止元素在光标下弹跳。想象一下,一旦元素离开光标,过渡就会恢复。一旦光标离开元素,它就会返回,因此光标再次位于元素上方并向下移动。这样它就会在光标边缘上下弹跳。

一种解决方案是使用 JavaScript 而不是 CSS 实现过渡,然后元素将“反弹”。但这真的是理想的行为吗?你到底想做什么?

【讨论】:

    【解决方案2】:

    此行为是正常的,无法更改。根据the specification@Stasik链接到正确实现。

    如果你必须改变这种行为,你可以使用带有 jquery 的 javascript 而不是 css 伪类。我创建了一个jsfiddle 来演示使用@Ivan Castellanos 提供的here 提供的.ismouseover() jQuery 扩展的可能方法。

    【讨论】:

      【解决方案3】:

      这是一种使用 JavaScript 和类来指示状态的解决方案。在您的情况下,您可以使用 mouseover 事件来切换这样的类:

      $('#content').on('mouseover', function() {
          $(this).toggleClass('down');
      });
      

      CSS

      #content.down  {
          background-color: deepskyblue;
          transform:translateY(300px);
          -webkit-transform: translateY(300px);
      }
      

      jsFiddle

      另一种解决方案是使用包装器作为悬停块

      <div id="container">
          <div id="wrapper">
              <div id="content">Hover me !</div>
          </div>
      </div>
      

      CSS

      #wrapper:hover #content  {
          background-color: deepskyblue;
          transform:translateY(300px);
          -webkit-transform: translateY(300px);
      }
      

      jsFiddle

      请注意,这两种解决方案针对不同的需求有不同的行为。

      【讨论】:

        【解决方案4】:

        检查这是否是您想要完成的行为。有些是示例样式,请随意调整。

        http://jsfiddle.net/U44Zf/9/

        .tooltip {
            background-color: white;
            border: 1px solid black;
            padding: 10px;
            opacity: 0;
            transition: 1s 500ms;
            transition-property: transform, opacity;
            position: absolute;
            right: 0;
            top: 0;
        }
        
        #content:hover .tooltip {
            display: block;
            opacity: 1;
            transform:translateX(100px);
            -webkit-transform: translateX(100px);
        }
        #content {
            transition: 1s 500ms;
            transition-property: background-color, color;
            cursor: pointer;
            position: relative;
        }
        #content.active {
            background-color: blue;
            color: white;
        }
        #content.active .tooltip {
            opacity: 0;
            transform: none;
            -webkit-transform: none;
        }
        

        我添加了这个 javascript sn-p 来控制点击状态

        $('#content').click(function () {
            $(this).toggleClass('active');
        });
        

        【讨论】:

          【解决方案5】:

          我的建议是以另一种方式看待这个问题:当你click 时,如果一个元素将被转换。为什么不在click 而不是mouseleave 上执行您的回调?

          我假设工具提示与 mouseenter 的元素有某种联系,在这种情况下,mouseleave 和 click 实际上是相同的 - 它们都导致鼠标指针不再位于元素上方(无论如何浏览器行为)。

          PS:请注意,在您的示例中,mouseenter 和 mouseleave 的触发方式还取决于您将transition 设置为默认属性还是:hover 状态属性,因为这看起来像是浏览器所在的区域供应商可以随心所欲地进行优化,您应该首先避免使用它们。

          【讨论】:

            【解决方案6】:

            您问题的第 1 部分:

            原理很简单:当元素悬停时,它 必须下去。问题是,当鼠标不动时, :hover 状态保持即使元素不在物理下方 鼠标了(由于翻译)。状态好像 仅在鼠标移动后更新。

            所以这是我的问题:

            1. 这种行为是否正常(符合规范)?

            是的。这种行为是正常的。标准中虽然没有一字不差,但在此详细提及:http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105

            以此小提琴为参考:http://jsfiddle.net/Blackhole/h7tb9/3/

            上面的div 直接绑定了鼠标事件。较低的div 具有绑定到其父级的鼠标事件。捡起下面的那个。在一侧缓慢移动鼠标并观察控制台,看看会发生什么。

            1. 您触摸边缘,mouseover 和 mouseenter 被快速连续触发(悬停)。
            2. 因此,内部div 进行了翻译。
            3. 什么都不做。没有事件被触发,所以什么也没有发生。
            4. 将鼠标移到外部div 内。 mousemove 触发,内部 div 仍在翻译中。
            5. 慢慢将鼠标移出。 mouseout 和 mouseleave 快速连续触发,内部 div 转换回其原始位置。

            此处对此进行了描述:鼠标事件顺序部分下的http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-mouseevents。

            上面的第 3 步很重要。因为你什么都不做,所以不会触发任何事件,因此什么也不会发生。如果内部div在这一步反弹回原来的位置,那就意味着激活发生了,没有任何事件!

            这符合 event 的定义,如本节中的文档:http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#glossary-event 说:

            事件是某些事件的表示(例如鼠标 点击一个元素的呈现,子节点的移除 从一个元素或任何数量的其他可能性)这是 与其事件目标相关联。每个事件都是一个实例化 一种特定的事件类型。

            现在看看这里的文档:http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#event-flow,就在第 3.2 节开始之前,它说:

            在一个事件完成其传播路径的所有阶段后,它的 Event.currentTarget 必须设置为 null 并且 Event.eventPhase 必须 设置为 0(无)。事件(或接口)的所有其他属性 派生自 Event)不变(包括 Event.target 属性,必须继续引用事件目标)。

            最后一行(括号内)很重要。即使在事件完成后,event.target 也会继续引用事件目标。

            现在选择小提琴中上部的div 以供参考。在mouseenter 上,div 本身被翻译。 它是否离开鼠标指针下方无关紧要。 event.target 仍然在引用它,如果没有其他鼠标事件发生,则什么也不会发生,它会保持翻译状态。在您移动鼠标的那一刻(任何地方移入或移出),激活发生在 event.target(仍然是 div)上,现在用户代理发现鼠标指针不再在元素上方并立即触发mouseout 和mouseleave 事件(当然是在触发mousemove 之后)导致div 翻译回来。

            您问题的第 2 部分:

            2.有什么办法可以避免这个问题?

            编辑:为了给你一个背景,这是我想要做的具体事情: 使用 JavaScript,当鼠标位于元素上时,我会显示一个工具提示 (并在鼠标离开时隐藏它)。但同样的元素可以 当用户点击它时进行转换。如果用户只是点击 在不移动鼠标的情况下,工具提示将保持显示,即 一个真正的问题。如何检测元素已消失?

            如果您查看此小提琴中较低 div 中的实现:http://jsfiddle.net/abhitalks/h7tb9/2/ ;与上层 div 相比,鼠标悬停时没有抖动/抖动。这是因为事件不是在 div 本身上处理的,而是在父级上处理的。

            所以,这可能是您的用例的一种解决方案。

            查看此演示:http://jsfiddle.net/Blackhole/nR8t9/9/

            这解决了您的编辑问题。工具提示显示在 mouseover 上。工具提示在 mouseleave 上隐藏。当您click 时,可以转换相同的元素。如果您只是 click 而不移动鼠标,则工具提示会隐藏。

            在这里,如果您click,则该元素正在被翻译,然后不会发生进一步的hover 操作。工具提示本身是使用:before 伪元素实现的。这将工具提示和要在click 之后更改的元素分开。您仍然可以处理元素本身的事件。不需要超时,因为它由 css 本身处理。如果你mouseout,工具提示会在延迟后隐藏。

            希望对您有所帮助。

            【讨论】:

              猜你喜欢
              • 2018-03-31
              • 1970-01-01
              • 1970-01-01
              • 2013-03-28
              • 2017-03-15
              • 1970-01-01
              • 2016-05-08
              • 2016-12-27
              • 2013-01-14
              相关资源
              最近更新 更多