Состояние наведения сохраняется во время перехода, даже если элемент

Рассмотрим простой элемент и связанный с ним 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
Обратите внимание на курсор (указатель) и его относительное положение с элементом!

Это реальная проблема, когда функция JavaScript должна выполняться, только если мышь находится на элементе, после timeout:

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

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

Итак, вот мои вопросы:

  • Является ли это поведение нормальным (соответствует нормам)?
  • Каковы решения, чтобы избежать этой проблемы?

Изменить: Чтобы дать вам контекст, вот что я хочу сделать конкретно: с помощью JavaScript я показываю всплывающую подсказку, когда мышь находится на элементе (и спрячьте ее, когда мышь покинет ее). Но тот же элемент может быть transform -ed, когда пользователь нажимает на него. Если пользователь просто нажимает без перемещения мыши, всплывающая подсказка останется отображаемой, что является реальной проблемой. Как я могу обнаружить, что элемент ушел?

Ответ 1

Часть 1 вашего вопроса:

Принцип прост: пока элемент завис, он должен спуститься. Проблема заключается в том, что когда мышь не перемещается,: состояние зависания поддерживается, даже если элемент физически ниже мышь больше (из-за перевода). Кажется, что государство обновляется только после перемещения мыши.

Итак, вот мои вопросы:

  • Является ли это поведение нормальным (соответствует нормам)?

Да. Это нормально. Хотя это не указано в стенограмме в стандартах, здесь подробно сказано: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105

Возьмите эту скрипту как ссылку: http://jsfiddle.net/Blackhole/h7tb9/3/

В верхнем div есть привязанные к нему события мыши. В нижнем div есть событие mouse-event, связанное с его родителем. Возьмите нижнюю. Медленно перемещайте мышь по одному краю и смотрите консоль, чтобы увидеть, что произойдет.

  • Вы касаетесь края, а mouseover и mouseenter запускаются быстро (наведите курсор мыши).
  • В результате преобразуется внутренний div.
  • Ничего не делай. Никакое событие не запускается, и поэтому ничего не происходит.
  • Переместите мышь внутри внешнего div. mousemove огонь и внутренний div все еще переведен.
  • Медленно выведите мышь. mouseout и mouseleave запускаются быстро, а внутренний div возвращается в исходное положение.

Это описано здесь: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-mouseevents в разделе "Заказ события мыши".

Этап 3 выше важен. Поскольку вы ничего не делаете, ни одно событие не запускается, и, следовательно, ничего не происходит. Если внутренний div должен был вернуться к исходному положению на этом шаге, это означало бы, что активация произошла без какого-либо события!

Это соответствует определению события как документа в этом разделе: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#glossary-event говорит:

Событие - это представление некоторого события (например, мыши нажмите на презентацию элемента, удаление дочернего nodeот элемента или любого количества других возможностей), который связанные с его целью. Каждое событие представляет собой один конкретный тип события.

Теперь взгляните на документ здесь: 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 переводится. Не важно, удаляется ли он из-под указателя мыши. Событие .target все еще ссылается на него, и если никаких других событий мыши не происходит, ничего не происходит, и он остается переведенным. В тот момент, когда вы перемещаете мышь (в любом месте или снаружи), активация происходит на event.target(который все еще находится в этом div) и , теперь пользовательский агент обнаруживает, что указатель мыши больше не находится над элементом и сразу mouseout и mouseleave события загораются (после стрельбы mousemove, конечно), заставляя div переводить назад.

Часть 2 вашего вопроса:

2. Каковы решения, чтобы избежать этой проблемы?

Изменить: Чтобы дать вам контекст, вот что я хочу сделать конкретно: с JavaScript, я показываю всплывающую подсказку, когда мышь находится на элементе (и спрячьте его, когда мышь покинет его). Но тот же самый элемент может быть преобразуется, когда пользователь нажимает на него. Если пользователь просто нажимает без перемещения мыши, всплывающая подсказка останется отображаемой, что реальная проблема. Как я могу обнаружить, что элемент ушел?

Если вы посмотрите на реализацию в нижнем div в этой скрипте: http://jsfiddle.net/abhitalks/h7tb9/2/; по сравнению с верхним диваном, при затухании нет трещин/джиттера. Это связано с тем, что вместо того, чтобы div сам, события обрабатываются родительским.

Итак, это может быть одно решение для вашего случая использования.

Смотрите эту демонстрацию: http://jsfiddle.net/Blackhole/nR8t9/9/

Это касается вашего редактирования. Всплывающая подсказка отображается на mouseover. Подсказка скрывается на mouseleave. Один и тот же элемент можно преобразовать, если вы click. Если вы просто click не перемещаете мышь, всплывающая подсказка скрывается.

Здесь, если вы click, этот элемент переводится, и тогда не будет действий hover. Сама подсказка реализована с использованием псевдоэлемента :before. Это отделяет всплывающую подсказку и элемент, который вы хотите изменить после click. Вы по-прежнему обрабатываете события на самом элементе. Нет необходимости в тайм-ауте, так как он обрабатывается самим css. Если вы mouseout, всплывающая подсказка будет скрываться после задержки.

Надеюсь, что это поможет.

Ответ 2

Это решение использовать JavaScript и класс для указания статуса. В вашем случае вы можете использовать событие mouseover для переключения класса следующим образом:

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

CSS

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

jsFiddle

Другим решением является использование обертки в качестве блока hover

<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

Обратите внимание, что эти два решения имеют разные типы поведения для разных требований.

Ответ 3

Мое предложение - посмотреть на эту проблему другим способом: если элемент будет переходить, когда вы click на нем. Почему бы просто не выполнить обратный вызов на click вместо mouseleave?

Я предполагаю, что подсказка имеет некоторую связь с элементом you mouseenter, и в этом случае mouseleave и click фактически одинаковы - оба они заставляют указатель мыши больше не быть над элементом (независимо от того, как браузер ведет себя).

PS: обратите внимание, что в вашем примере, как mouseenter и mouseleave огонь также зависит от того, установлено ли значение transition как свойство по умолчанию или как свойство состояния :hover, так как это выглядит как область, в которой браузер поставщики могут свободно оптимизировать, как им заблагорассудится, вы, вероятно, должны избегать их в первую очередь.

Ответ 4

Это поведение является нормальным для предотвращения подмены элемента под курсором. Представьте, что переход будет возвращен, как только элемент будет удален от курсора. Как только курсор покинет элемент, он вернется назад, поэтому курсор снова окажется над элементом, и он движется вниз. Таким образом, он будет отскакивать вверх и вниз по краю курсора.

Одним из решений было бы реализовать переход с JavaScript вместо CSS, тогда элемент будет "отскакивать". Но действительно ли это желаемое поведение? Что именно вы пытаетесь сделать?

Ответ 5

Это поведение является нормальным и не может быть изменено. Он правильно реализован в соответствии с спецификацией @Stasik, связанной с.

Если вам нужно изменить это поведение, вы можете использовать javascript с jquery вместо псевдо-классов css. Я создал jsfiddle, чтобы продемонстрировать возможный подход с использованием расширения .ismouseover() jQuery на @Иван Кастельянос предоставил здесь.

Ответ 6

Проверьте, является ли это поведение, которое вы хотите выполнить. Некоторые из них являются примерами, настраиваются, как вам угодно.

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