即使元素已经消失,在转换期间也会保持悬停状态

时间:2014-05-03 14:06:13

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

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

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

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

JSFiddle

原则是直截了当的:当元素悬停时,它必须下降。问题是,当鼠标移动时,即使元素不再在物理上低于鼠标(由于翻译),也会保持:hover状态。只有在鼠标移动后,状态似乎才会更新。

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

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

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

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

所以这是我的问题:

  1. 此行为正常(符合规范)?
  2. 有哪些解决方案可以避免此问题?
  3. 编辑: 为了给你一个上下文,这是我想要具体做的事情:使用JavaScript,当鼠标位于元素上时,我会显示工具提示(和当鼠标离开时隐藏它)。但是当用户点击它时,相同的元素可以是transform。如果用户只是在不移动鼠标的情况下单击,则工具提示将保持显示,这是一个真正的问题。如何检测元素消失?

6 个答案:

答案 0 :(得分:7)

问题的第1部分:

  

原则是直截了当的:当元素悬停时,它   必须下去。问题是,当鼠标不移动时,即   :即使元素实际上不在下面,也会保持悬停状态   鼠标了(由于翻译)。国家似乎是   只有在鼠标移动后才会更新。

     

所以这是我的问题:

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

是。这种行为很正常。虽然标准中没有逐字逐句指出,但在此处详细说明: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105

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

上部div直接绑定了鼠标事件。较低的div将鼠标事件绑定到其父级。拿起下面一个。在一个边缘缓慢移动鼠标并观察控制台以查看会发生什么。

  1. 您触摸边缘,mouseovermouseenter会快速连续发起(悬停)。
  2. 因此内部div翻译。
  3. 什么都不做。没有事件被触发,所以没有任何反应。
  4. 将鼠标移到外部div内。 mousemove点火,内部div仍然翻译。
  5. 慢慢移开鼠标。 mouseoutmouseleave会快速连续发起,内部div会转换回原来的位置。
  6. 此处描述了鼠标事件订单部分下的 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.target   属性,必须继续引用事件目标)。

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

    现在选择小提琴中的上div作为参考。在mouseenter div本身已翻译。 如果它远离鼠标指针下方并不重要。 event.target仍然引用它 ,如果没有其他鼠标事件发生,则没有任何反应,它仍然会被翻译。移动鼠标的时刻(无论进出),激活都发生在event.target(仍然是div)和 上,现在用户代理发现鼠标指针是不再超过元素 并立即触发mouseoutmouseleave事件(当然在触发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,工具提示会在延迟后隐藏。

    希望有所帮助。

答案 1 :(得分:2)

这是一个使用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

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

答案 2 :(得分:2)

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

我假设工具提示与您mouseenter的元素有一些连接,在这种情况下mouseleaveclick实际上是相同的 - 它们都会导致鼠标指针不在元素不再(无论浏览器的行为如何)。

PS:请注意,在您的示例中,mouseentermouseleave如何触发还取决于您是将transition设置为默认属性还是:hover状态属性,因为这看起来像浏览器供应商可以随意优化的区域,所以你应该首先避开它们。

答案 3 :(得分:1)

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

一种解决方案是使用JavaScript而不是CSS实现转换,然后该元素将反弹&#34;。但这真的是理想的行为吗?你究竟想做什么?

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

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

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代码段来控制点击状态

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