Piszę witrynę sieci Web, która ma być używana zarówno z komputerów stacjonarnych, jak i tabletów. Kiedy jest odwiedzany z pulpitu, chcę, aby klikalne obszary ekranu były podświetlane z :hover
efektami (inny kolor tła itp.). Na tablecie nie ma myszy, więc nie chcę żadnych efektów najechania kursorem.
Problem polega na tym, że kiedy dotykam czegoś na tablecie, przeglądarka ewidentnie ma jakiś „niewidoczny kursor myszy”, który przesuwa się do miejsca, w które stuknąłem, a następnie zostawia go tam - więc to, co właśnie stuknąłem, zapala się efekt najechania, dopóki nie stuknę czegoś innego.
Jak mogę uzyskać efekty najechania kursorem, gdy używam myszy, ale je wyłączyć, gdy używam ekranu dotykowego?
Na wypadek, gdyby ktoś myślał o zasugerowaniu tego, nie chcę korzystać z węszenia klienta użytkownika. To samo urządzenie może mieć zarówno ekran dotykowy, jak i mysz (może nie tak powszechne obecnie, ale znacznie bardziej w przyszłości). Nie interesuje mnie urządzenie, interesuje mnie jak jest aktualnie używane: mysz czy ekran dotykowy.
Próbowałem już podpinania się touchstart
, touchmove
oraz touchend
wydarzenia i powołanie preventDefault()
na wszystkie z nich, które nie tłumią „niewidzialny kursor myszy” na jakiś czas; ale jeśli szybko stuknę tam iz powrotem między dwoma różnymi elementami, po kilku stuknięciach zacznie przesuwać „kursor myszy” i tak czy inaczej podświetla efekty najechania - to tak, jakby mój preventDefault
nie zawsze był honorowany. Nie będę Cię zanudzać szczegółami, chyba że będzie to konieczne - nie jestem nawet pewien, czy jest to właściwe podejście; jeśli ktoś ma prostsze rozwiązanie, mam wszystkie uszy.
Edycja: Można to odtworzyć za pomocą standardowego CSS bog :hover
, ale oto krótka reprodukcja w celach informacyjnych.
<style>
.box { border: 1px solid black; width: 150px; height: 150px; }
.box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>
Jeśli najedziesz kursorem myszy na jedno z pól, pojawi się niebieskie tło, które chcę. Ale jeśli dotkniesz któregokolwiek z pól, również pojawi się niebieskie tło, czemu staram się zapobiec.
Opublikowałem tutaj również próbkę , która wykonuje powyższe, a także przechwytuje zdarzenia myszy jQuery. Możesz go użyć, aby zobaczyć, że zdarzenia dotknięcia również będą uruchamiane mouseenter
, mousemove
i mouseleave
.
źródło
Odpowiedzi:
Z twojego pytania wynika, że efekt najechania kursorem zmienia zawartość twojej strony. W takim przypadku radzę:
touchstart
imouseenter
.mouseleave
,touchmove
iclick
.Alternatywnie możesz edytować swoją stronę, aby nie zmieniała treści.
tło
Aby zasymulować mysz, przeglądarki, takie jak Webkit mobile, uruchamiają następujące zdarzenia, jeśli użytkownik dotknie i puści palec na ekranie dotykowym (takim jak iPad) (źródło: Touch And Mouse na html5rocks.com):
touchstart
touchmove
touchend
mouseover
mouseenter
mouseover
,mouseenter
czymousemove
zdarzenie zmienia zawartość strony, następujące zdarzenia nie są wypalane.mousemove
mousedown
mouseup
click
Wydaje się, że nie jest możliwe po prostu nakazanie przeglądarce pominięcia zdarzeń myszy.
Co gorsza, jeśli zdarzenie najechania kursorem myszy zmieni zawartość strony, zdarzenie kliknięcia nigdy nie zostanie uruchomione, jak wyjaśniono w Przewodniku po treściach internetowych Safari - Obsługa zdarzeń , w szczególności na rysunku 6.4 w Zdarzeniach jednym palcem . Czym dokładnie jest „zmiana treści”, zależy od przeglądarki i wersji. Odkryłem, że w iOS 7.0 zmiana koloru tła nie jest (lub już nie?) Zmianą treści.
Wyjaśnienie rozwiązania
Przypomnę:
touchstart
imouseenter
.mouseleave
,touchmove
iclick
.Zauważ, że nie ma żadnej akcji
touchend
!To oczywiście działa w przypadku zdarzeń myszy:
mouseenter
imouseleave
(nieco ulepszone wersjemouseover
imouseout
) są uruchamiane i dodają i usuwają dymek.Jeśli użytkownik faktycznie jest
click
linkiem, efekt najechania kursorem jest również usuwany. Zapewnia to, że zostanie usunięty, jeśli użytkownik naciśnie przycisk Wstecz w przeglądarce internetowej.Działa to również w przypadku zdarzeń dotykowych: przy Touchstart dodawany jest efekt najechania. To jest '' 'nie' '' usunięte po dotknięciu. Jest on ponownie dodawany
mouseenter
, a ponieważ nie powoduje to żadnych zmian treści (zostało już dodane),click
zdarzenie jest również uruchamiane, a łącze jest śledzone bez konieczności ponownego klikania przez użytkownika!300 ms opóźnienia, które przeglądarka ma między
touchstart
zdarzeniem iclick
jest faktycznie dobrze wykorzystywane, ponieważ efekt najechania kursorem będzie wyświetlany w tym krótkim czasie.Jeśli użytkownik zdecyduje się anulować kliknięcie, ruch palcem zrobi to normalnie. Zwykle jest to problem, ponieważ żadne
mouseleave
zdarzenie nie jest uruchamiane, a efekt zawisu pozostaje na miejscu. Na szczęście można to łatwo naprawić, usuwając efekt najechania natouchmove
.Otóż to!
Zwróć uwagę, że możliwe jest usunięcie opóźnienia 300 ms, na przykład przy użyciu biblioteki FastClick , ale jest to poza zakresem tego pytania.
Alternatywne rozwiązania
Znalazłem następujące problemy z następującymi alternatywami:
touchend
: Spowoduje to niepoprawne podążanie za linkiem, nawet jeśli użytkownik chciał tylko przewijać lub powiększać, bez zamiaru klikania łącza.touchend
która jest używana jako warunek jeśli w kolejnych zdarzeniach myszy, aby zapobiec zmianom stanu w tym momencie. Zmienna jest resetowana w przypadku kliknięcia. Zobacz odpowiedź Waltera Romana na tej stronie. To przyzwoite rozwiązanie, jeśli naprawdę nie chcesz efektu najechania na interfejsy dotykowe. Niestety, to nie działa, jeśli atouchend
jest uruchamiane z innego powodu i nie jest uruchamiane żadne zdarzenie kliknięcia (np. Użytkownik przewinął lub powiększył), a następnie próbuje podążać za linkiem za pomocą myszy (tj. Na urządzeniu z myszą i interfejsem dotykowym ).Dalsze czytanie
mouseover
lubmousemove
.źródło
touchend
zamiast stanowitouchstart
w większości przypadków uniknąć natychmiastowego działania wyzwalające, gdy użytkownik próbuje trzepnąć-przewijanie w górę lub w dół strony. Nadal będzie się zdarzać, ale jest mniej prawdopodobne, że rozproszy lub zmyli (zakładając, że jest to coś nieszkodliwego, jak wyświetlenie etykiety, a nie coś, o czym użytkownik musi wiedzieć)Może nie myśl o tym tak bardzo, jak o wyłączaniu efektów najechania na ekrany dotykowe, ale jako o dodaniu efektów najechania na zdarzenia myszy?
Jeśli chcesz zachować
:hover
efekty w swoim CSS, możesz określić różne style dla różnych mediów:Tyle że niestety istnieje wiele urządzeń mobilnych, które to ignorują i po prostu korzystają z reguł ekranu. Na szczęście wiele nowszych przeglądarek na telefony komórkowe / tablety obsługuje bardziej wyszukane zapytania o media:
Więc nawet jeśli część „ekranowa” lub „podręczna” zostanie zignorowana, „maksymalna szerokość” załatwi sprawę za Ciebie. Możesz po prostu założyć, że wszystko, co ma ekran mniejszy niż 800 pikseli, musi być tabletem lub telefonem i nie może używać efektów najechania kursorem. Dla rzadkich użytkowników, którzy używają myszy na urządzeniu o niskiej rozdzielczości, nie zobaczyliby efektów najechania kursorem, ale w przeciwnym razie Twoja witryna byłaby w porządku.
Chcesz dowiedzieć się więcej na temat zapytań medialnych? W Internecie jest mnóstwo artykułów na ten temat - oto jeden: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet
Jeśli przesuniesz efekty najechania poza CSS i zastosujesz je w JavaScript, możesz powiązać się specjalnie ze zdarzeniami myszy i / lub znowu możesz po prostu przyjąć pewne założenia na podstawie rozmiaru ekranu, z najgorszym "problemem" użytkownik korzystający z myszy traci efekty najechania kursorem.
źródło
preventDefault()
, czasami tłumi to zdarzenia myszy, ale jak powiedziałem w moim pytaniu, nie jest to wiarygodne.Napisałem następujący JS dla niedawnego projektu, który był stroną na komputery / urządzenia mobilne / tablety, które mają efekty najechania kursorem, które nie powinny pojawiać się po dotknięciu.
Poniższy
mobileNoHoverState
moduł ma zmiennąpreventMouseover
(początkowo zadeklarowaną jakofalse
), która jest ustawiana,true
gdy użytkownik uruchomitouchstart
zdarzenie na elemencie,$target
.preventMouseover
jest następnie ustawiany z powrotem nafalse
moment uruchomieniamouseover
zdarzenia, co pozwala witrynie działać zgodnie z przeznaczeniem, jeśli użytkownik używa zarówno ekranu dotykowego, jak i myszy.Wiemy, że
mouseover
jest uruchamiany później ztouchstart
powodu kolejności, w której są deklarowaneinit
.Moduł jest następnie tworzony w dalszej części linii:
źródło
Naprawdę chciałem mieć czyste
css
rozwiązanie tego problemu, ponieważ rozsypanie ciężkiego rozwiązania javascript wokół wszystkich moich poglądów wydawało się nieprzyjemną opcją. Wreszcie znalazłem zapytanie @ media.hover , które może wykryć „czy podstawowy mechanizm wprowadzania danych pozwala użytkownikowi na najechanie kursorem na elementy”. Pozwala to uniknąć urządzeń dotykowych, w przypadku których „zawisanie” jest bardziej emulowaną czynnością niż bezpośrednią funkcją urządzenia wejściowego.Czyli na przykład, jeśli mam link:
Wtedy mogę bezpiecznie stylizować go tylko
:hover
wtedy, gdy urządzenie z łatwością go obsługuje w ten sposóbcss
:Podczas gdy większość nowoczesnych przeglądarek obsługuje zapytania o funkcje multimediów, niektóre popularne przeglądarki, takie jak IE i Firefox , nie obsługują . W moim przypadku działa to dobrze, ponieważ zamierzałem obsługiwać tylko Chrome na komputerze stacjonarnym oraz Chrome i Safari na urządzeniach mobilnych.
źródło
Moim rozwiązaniem jest dodanie klasy css hover-active do tagu HTML i użycie jej na początku wszystkich selektorów CSS za pomocą: hover i usuń tę klasę przy pierwszym zdarzeniu touchstart.
http://codepen.io/Bnaya/pen/EoJlb
JS:
HTML:
CSS:
źródło
'ontouchstart' in window
. np.if ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
To, co zrobiłem, aby rozwiązać ten sam problem, to wykrywanie funkcji (używam czegoś w rodzaju ten kod ), sprawdzanie, czy zdefiniowano onTouchMove, a jeśli tak, dodaję do treści klasę css "touchMode", w przeciwnym razie dodaję " desktopMode ”.
Następnie za każdym razem, gdy jakiś efekt stylu dotyczy tylko urządzenia dotykowego lub tylko pulpitu, reguła css jest poprzedzona odpowiednią klasą:
Edycja : ta strategia oczywiście dodaje kilka dodatkowych znaków do twojego css, więc jeśli martwisz się o rozmiar css, możesz wyszukać definicje touchMode i desktopMode i umieścić je w różnych plikach, abyś mógł obsługiwać zoptymalizowany css dla każdego urządzenia rodzaj; albo możesz zmienić nazwy klas na coś znacznie krótszego przed przystąpieniem do produkcji.
źródło
Racja, ja jst miałem podobny problem, ale udało mi się go naprawić za pomocą zapytań o media i prostego CSS. Jestem pewien, że łamię tutaj pewne zasady, ale to działa na mnie.
Po prostu musiałem wziąć ogromną aplikację, którą ktoś stworzył, i sprawić, by była responsywna. Użyli jQueryUI i poprosili mnie, abym nie manipulował żadnym z ich jQuery, więc byłem ograniczony do używania samego CSS.
Kiedy nacisnąłem jeden z ich przycisków w trybie ekranu dotykowego, efekt najechania aktywowałby się na sekundę, zanim zadziałał przycisk. Oto jak to naprawiłem.
źródło
W moim projekcie rozwiązaliśmy ten problem za pomocą https://www.npmjs.com/package/postcss-hover-prefix i https://modernizr.com/ Najpierw przetwarzamy wyjściowe pliki css za pomocą
postcss-hover-prefix
. Dodaje.no-touch
do wszystkichhover
reguł CSS .css
staje się
W czasie wykonywania
Modernizr
automatycznie dodaje klasy css dohtml
oznaczania w ten sposóbTakie przetwarzanie końcowe css plus Modernizr wyłącza kursor dla urządzeń dotykowych i włącza go dla innych. W rzeczywistości to podejście zostało zainspirowane Bootstrap 4, w jaki sposób rozwiązują ten sam problem: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile
źródło
mouseLeave
Zdarzenie można wywołać za każdym razem, gdy dotkniesz elementu na ekranie dotykowym. Oto rozwiązanie dla wszystkich<a>
tagów:źródło
Znalazłem 2 rozwiązania tego problemu, co sugeruje, że wykrywasz kontakt z moderr lub czymś innym i ustawiasz klasę dotyku w elemencie html.
To jest dobre, ale niezbyt dobrze obsługiwane :
Ale to ma bardzo dobre wsparcie :
Działa dla mnie bezbłędnie, sprawia, że wszystkie efekty najechania na mysz będą wyglądać tak, jakbyś dotknął przycisku, który zaświeci się, ale nie zakończy się błędem, jak początkowy efekt najechania kursorem dla zdarzeń myszy.
Wykrywanie dotyku z urządzeń bezdotykowych Myślę, że modernizr wykonał najlepszą pracę:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.jsEDYTOWAĆ
Znalazłem lepsze i prostsze rozwiązanie tego problemu
Jak ustalić, czy klient jest urządzeniem dotykowym
źródło
Pomocne może być zobaczenie CSS, ponieważ brzmi to raczej dziwnie. Ale w każdym razie, jeśli tak się dzieje i wszystko inne jest w porządku, możesz spróbować przenieść efekt najechania na javascript (możesz również użyć jquery). Po prostu połącz się ze zdarzeniem mouseover lub jeszcze lepiej mouseenter i zapal swój element, gdy zdarzenie zostanie uruchomione.
Sprawdź ostatni przykład tutaj: http://api.jquery.com/mouseover/ , możesz użyć czegoś podobnego do rejestrowania, gdy zdarzenie się uruchamia i stamtąd je zabrać!
źródło
mouseenter
; nie ma kości. Stuknięcie przesuwa „niewidzialny kursor myszy”, więc uruchamiamouseenter
imousemove
(imouseleave
kiedy stukniesz w inne miejsce).Jeśli jesteś zadowolony z używania JavaScript, możesz użyć Modernizr na swojej stronie. Po załadowaniu strony przeglądarka bez ekranu dotykowego będzie miała klasę „.no-touch” dodaną do tagu HTML, ale w przypadku przeglądarki z ekranem dotykowym tag HTML będzie miał klasę „.touch” dodaną do tagu HTML .
Następnie wystarczy sprawdzić, czy znacznik html ma klasę no-touch przed podjęciem decyzji o dodaniu mouseenter i mouseleave nasłuchujących.
W przypadku urządzenia z ekranem dotykowym zdarzenia nie będą miały słuchaczy, więc po dotknięciu nie pojawi się efekt najechania kursorem.
źródło
.touch
i.no-touch
. Przepisanie odpowiedzi w CSS razem z Modernizeremhtml.no-touch .box:hover {background-color: "#0000ff"}
i brak definiowania czegokolwiekhtml.touch .box:hover
powinno załatwić sprawę, ponieważ OP stara się tylko unikać telefonów komórkowych:hover
.W projekcie, który robiłem niedawno, rozwiązałem ten problem za pomocą funkcji zdarzeń delegowanych w jQuery. Wyszukuje określone elementy za pomocą selektora jQuery i dodaje / usuwa klasę CSS do tych elementów, gdy wskaźnik myszy znajduje się nad elementem. Wydaje się, że działa dobrze, o ile mogłem to przetestować, w tym IE10 na notebooku obsługującym dotyk z systemem Windows 8.
edycja: to rozwiązanie wymaga oczywiście zmiany CSS w celu usunięcia selektorów „: hover” i przemyślenia z wyprzedzeniem, które elementy mają być „hoverable”.
Jeśli masz na stronie bardzo dużo elementów (np. Kilka tysięcy), może się to trochę spowolnić, ponieważ to rozwiązanie wyłapuje zdarzenia trzech typów na wszystkich elementach na stronie, a następnie robi swoje, jeśli selektor pasuje. Nazwałem klasę CSS „mouseover” zamiast „hover”, ponieważ nie chciałem, aby czytający CSS czytali „: hover”, gdzie napisałem „.hover”.
źródło
Oto moje rozwiązanie: http://jsfiddle.net/agamemnus/g56aw709/ - kod poniżej.
Wszystko, co trzeba zrobić, to przekonwertować ich ": hover" na ".hover" ... to wszystko! Duża różnica między tym a resztą polega na tym, że będzie to działać również w przypadku selektorów elementów innych niż pojedyncze, takich jak
.my_class > *:hover {
.źródło
Uwzględnij Modernizr na swojej stronie i zamiast tego ustaw stany najechania w następujący sposób:
źródło
Witaj osobie z przyszłości, prawdopodobnie chcesz skorzystać z zapytania
pointer
i / lubhover
media query.handheld
Zapytania mediów została zaniechana.źródło
Wypróbuj to proste rozwiązanie jquery 2019, chociaż było ono już od jakiegoś czasu;
dodaj tę wtyczkę do głowy:
src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"
dodaj to do js:
$("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements
niektóre sugerowane warianty tego to:
Uwagi
Bibliografia:
https://code.jquery.com/ui/
https://api.jquery.com/category/selectors/jquery-selector-extensions/
źródło