: aktywna pseudoklasa nie działa w mobilnym safari

109

W Webkit na iPhonie / iPadzie / iPodzie określenie stylu dla pseudoklasy: active dla <a>tagu nie jest wyzwalane po dotknięciu elementu. Jak mogę to spowodować? Przykładowy kod:

<style> 
a:active { 
    background-color: red;
}
</style>
<!-- snip -->
<a href="#">Click me</a>
Jesse Rusak
źródło

Odpowiedzi:

238
<body ontouchstart="">
    ...
</body>

Zastosowany tylko raz, w przeciwieństwie do każdego elementu przycisku, wydawał się naprawiać wszystkie przyciski na stronie. Alternatywnie możesz użyć tej małej biblioteki JS o nazwie „ Fastclick ”. Przyspiesza zdarzenia kliknięć na urządzeniach dotykowych i rozwiązuje również ten problem.

wilsonpage
źródło
19
Czy nie wystarczy po prostu dodać ontouchstartbez =""? (HTML5)
feklee
2
Dla przyszłych czytelników opublikowałem tutaj demo: http://jsbin.com/EjiWILe/3/ . Sprawdź funkcjonalność na swoim urządzeniu iOS.
mhulse
6
Czy możesz wyjaśnić, dlaczego zastosowałeś do ciała pustego słuchacza? Jak to działa?
Maurizio Battaghini
2
Używałem: focus, i to też działa. Dzięki za magię.
TecBrat
Otrzymuję zawieszanie się strony w iOS 9.1 i 9.3 przy użyciu tej metody ... te wersje miały błąd js, ale nadal mają 0,5% użytkowników w tych systemach
Ruskin
55

Jak stwierdziły inne odpowiedzi, iOS Safari nie wyzwala :activepseudoklasy, chyba że zdarzenie dotykowe jest dołączone do elementu, ale jak dotąd to zachowanie było „magiczne”. Natknąłem się na tę małą notkę w bibliotece programistów Safari, która to wyjaśnia (moje wyróżnienie):

Możesz również użyć -webkit-tap-highlight-colorwłaściwości CSS w połączeniu z ustawieniem zdarzenia dotyku, aby skonfigurować przyciski tak, aby zachowywały się podobnie do pulpitu. W systemie iOS zdarzenia myszy są wysyłane tak szybko, że stan nieaktywny lub nieaktywny nigdy nie jest odbierany. Dlatego :activepseudo stan jest wyzwalany tylko wtedy, gdy istnieje zdarzenie dotykowe ustawione w elemencie HTML - na przykład, gdy ontouchstart jest ustawiony na elemencie w następujący sposób:

<button class="action" ontouchstart=""
        style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
    Testing Touch on iOS
</button>

Teraz po dotknięciu i przytrzymaniu przycisku w systemie iOS przycisk zmienia się na określony kolor bez pojawienia się otaczającego przezroczystego szarego koloru.

Innymi słowy, ustawienie ontouchstartzdarzenia (nawet jeśli jest ono puste) wyraźnie mówi przeglądarce, aby reagowała na zdarzenia dotykowe.

Moim zdaniem jest to błędne zachowanie i prawdopodobnie sięga czasów, gdy „mobilna” sieć praktycznie nie istniała (spójrz na te zrzuty ekranu na połączonej stronie, aby zobaczyć, co mam na myśli), a wszystko było zorientowane na mysz. Warto zauważyć, że inne, nowsze przeglądarki mobilne, takie jak Android, wyświetlają `: active 'pseudo-stan po dotknięciu, bez żadnych hacków, takich jak to, co jest potrzebne w iOS.

(Uwaga boczna: jeśli chcesz używać własnych niestandardowych stylów na iOS, możesz również wyłączyć domyślne szare półprzezroczyste pole, którego system iOS używa zamiast :activepseudo-stanu, używając -webkit-tap-highlight-colorwłaściwości CSS, jak wyjaśniono na tej samej połączonej stronie powyżej .)


Po pewnych eksperymentach oczekiwane rozwiązanie polegające na ustawieniu ontouchstartzdarzenia na <body>elemencie, do którego wszystkie zdarzenia dotykają się, nie działa w pełni. Jeśli element jest widoczny w rzutni podczas ładowania strony, to działa dobrze, ale przewijanie w dół i stukanie w element, który był poza rzutnią, nie wywołuje :activepseudo-stanu, jak powinien. Więc zamiast

<!DOCTYPE html>
<html><body ontouchstart></body></html>

dołącz zdarzenie do wszystkich elementów zamiast polegać na zdarzeniu bulgotanym do ciała (używając jQuery):

$('body *').on('touchstart', function (){});

Nie jestem jednak świadomy konsekwencji tego dla wydajności, więc uważaj.


EDYCJA: Jest jedna poważna wada tego rozwiązania: nawet dotknięcie elementu podczas przewijania strony aktywuje :activepseudo stan. Wrażliwość jest zbyt silna. Android rozwiązuje ten problem, wprowadzając bardzo małe opóźnienie przed wyświetleniem stanu, które jest anulowane, jeśli strona jest przewijana. W związku z tym proponuję używać tego tylko na wybranych elementach. W moim przypadku tworzę aplikację internetową do użytku w terenie, która jest w zasadzie listą przycisków do nawigacji po stronach i przesyłania działań. Ponieważ w niektórych przypadkach cała strona składa się z przycisków, to nie zadziała. Możesz jednak ustawić :hoverpseudo-stan, aby zamiast tego wypełniał. Po wyłączeniu domyślnego szarego pola działa to idealnie.

user128216
źródło
6
Świetne wyjaśnienie, dlaczego, a nie tylko jak ! Dzięki!
coderfin
6
Głosowany za daniem programistom zrozumienia, a nie tylko „magicznym” przepisem. To jest nieskończenie bardziej pouczające niż inne; dziękuję za napisanie tego dla nas.
user508633
Głosowano za szczegółowymi wyjaśnieniami + zastrzeżeniami. To powinna być prawidłowa odpowiedź.
Master of Ducks
39

Dodaj procedurę obsługi zdarzeń dla ontouchstart w tagu <a>. To powoduje, że CSS magicznie działa.

<a ontouchstart="">Click me</a>
Jesse Rusak
źródło
3
Przepraszam, to jest stara odpowiedź, ale dlaczego to działa? Nie mam nic przeciwko jako powód „magicznie”, ale gdybyś mógł wyjaśnić, dlaczego to działa, chciałbym przeczytać więcej szczegółów.
mhulse
1
@mhulse Chciałbym też wiedzieć, dlaczego.
Jesse Rusak
Ha! Jesteśmy na tej samej łodzi. Spróbuję poszukać informacji i zamieścić tutaj link do (pół) oficjalnych dokumentów w tej sprawie. Podoba mi się, że ta technika działa, zastanawiam się tylko, dlaczego?
mhulse
7

To działa dla mnie:

document.addEventListener("touchstart", function() {},false);

Uwaga: jeśli wykonasz tę sztuczkę, warto również usunąć domyślny kolor dotknięcia i podświetlenia, który stosuje Mobile Safari, używając następującej reguły CSS.

html {
    -webkit-tap-highlight-color: rgba(0,0,0,0);
}
dhqvinh
źródło
5

Od 8 grudnia 2016 r. Zaakceptowana odpowiedź ( <body ontouchstart="">...</body>) nie działa dla mnie na Safari 10 (iPhone 5s): Ten hack działa tylko w przypadku tych elementów, które były widoczne podczas ładowania strony.

Jednak dodając:

<script type='application/javascript'>
  document.addEventListener("touchstart", function() {}, false);
</script>

do headnie działa tak, jak chcesz, z drugiej jednak strony, że teraz wszystkie zdarzenia dotykowe podczas przewijania również wywołać :activepseudo-stan na dotykanych elementów. (Jeśli jest to dla Ciebie problem, możesz rozważyć obejście rozwiązania FighterJet :hover ).

Ali
źródło
4
//hover for ios
-webkit-tap-highlight-color: #ccc;

To działa dla mnie, dodaj do swojego CSS na elemencie, który chcesz wyróżnić

Czerwone oko
źródło
3

Czy używasz wszystkich pseudoklas, czy tylko jednej? Jeśli używasz co najmniej dwóch, upewnij się, że są we właściwej kolejności lub wszystkie się zepsują:

a:link
a:visited
a:hover
a:active

..w tej kolejności. Ponadto, jeśli używasz tylko: active, dodaj: link, nawet jeśli go nie stylizujesz.

tahdhaze09
źródło
świetna wskazówka, jak ważna jest kolejność podczas stylizowania pseudoklas.
brianarpie
1

Opublikowałem narzędzie, które powinno rozwiązać ten problem za Ciebie.

Z pozoru problem wygląda na prosty, ale w rzeczywistości zachowanie dotknięcia i kliknięcia wymaga dość szerokiego dostosowania, w tym funkcji limitu czasu i rzeczy typu „co się dzieje, gdy przewijasz listę linków” lub „co się dzieje, gdy klikasz link, a następnie odsuń mysz / palec od obszaru aktywnego "

To powinno rozwiązać wszystko naraz: https://www.npmjs.com/package/active-touch

Musisz albo przypisać swoje: active style do klasy .active, albo wybrać własną nazwę klasy. Domyślnie skrypt będzie działał ze wszystkimi elementami linków, ale możesz nadpisać go własną tablicą selektorów.

Szczere, pomocne opinie i wkłady bardzo doceniane!

dmitrizzle
źródło
2
Ta biblioteka dodaje 9 (nie pasywnych) detektorów zdarzeń do każdego elementu łącza, ale nie wywołuje metody removeEventListener - myślę, że byłaby to duża wada dla aplikacji jednostronicowych
Drenai
1
Dzięki Ryan. Nie obsługuję ani nie używam tego kodu od ponad roku; Zdejmę to. Po kilku przemyśleniach i eksperymentach zmieniłem projekt aplikacji, zamiast próbować wymusić interakcje, które nie są uwzględniane lub przemyślane przez przeglądarki.
dmitrizzle
1

Dla tych, którzy nie chcą korzystać z ontouchstart, możesz użyć tego kodu

<script>
 document.addEventListener("touchstart", function(){}, true);
</script>
Noob Dev
źródło
1

Wypróbowałem tę odpowiedź i jej warianty, ale żadna nie wydawała się działać niezawodnie (i nie lubię polegać na „magii” w takich sprawach). Więc zamiast tego wykonałem następujące czynności, które działają doskonale na wszystkich platformach, nie tylko na Apple:

  1. Przemianowany deklaracje CSS wykorzystywane :activedo .active.
  2. Utworzono listę wszystkich elementów, których to dotyczy, i dodano pointerdown/mousedown/touchstartprogramy obsługi zdarzeń, aby zastosować .activeklasę i pointerup/mouseup/touchendprogramy obsługi zdarzeń, aby je usunąć. Korzystanie z jQuery:

    let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
    let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
    
    let clickableThings = '<comma separated list of selectors>';
    $(clickableThings).on(controlActivationEvents,function (e) {
        $(this).addClass('active');
    }).on(controlDeactivationEvents, function (e) {
        $(this).removeClass('active');
    });

To było trochę uciążliwe, ale teraz mam rozwiązanie, które jest mniej podatne na awarie między wersjami Apple OS. (A kto potrzebuje czegoś takiego zerwania?)

daffinm
źródło
Myślę, że daje odpowiedź na to pytanie. Wydaje się, że nie ma niezawodnego sposobu, aby pseudoklasa: active działała w mobilnym Safari. Ale można to niezawodnie emulować za pomocą podanego przeze mnie rozwiązania. Zrobiłem to w mojej aplikacji i działa idealnie na wszystkich platformach. Dla wyjaśnienia dodałem kod.
daffinm
0

Rozwiązaniem jest poleganie :targetzamiast :active:

<style> 
a:target { 
    background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>

Styl zostanie wywołany, gdy zakotwiczenie zostanie skierowane przez aktualny adres URL, który działa nawet na urządzeniach mobilnych. Wadą jest to, że potrzebujesz innego linku, aby wyczyścić kotwicę w adresie URL. Kompletny przykład:

a:target { 
    background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>

rgmt
źródło
-3

Nie ma 100% związku z tym pytaniem, ale możesz też użyć hacka rodzeństwa CSS, aby to osiągnąć

HTML

<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>

SCSS

input {
    &:checked + label {
      background-color: red;
    }
  }

Jeśli chcesz używać czystej podpowiedzi html / css

span {
  display: none;
}
input {
    &:checked ~ span {
      display: block;
    }
  }
Seeliang
źródło
-6
<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="utf-8">

<title></title>

<style>
        a{color: red;}
        a:hover{color: blue;}
</style>
</head>

<body>

        <div class="main" role="main">
                <a href="#">Hover</a>
        </div>

</body>
</html>
TroyM
źródło
1
Zgodnie z FAQ, podpisy i autopromocja są niedozwolone.
LittleBobbyTables - Au Revoir