Jak zapobiegać efektom lepkiego najechania na przyciski na urządzeniach dotykowych

144

Utworzyłem karuzelę z zawsze widocznymi przyciskami poprzedni i następny. Te przyciski mają stan najechania, zmieniają kolor na niebieski. Na urządzeniach dotykowych, takich jak iPad, stan najechania kursorem jest lepki, więc przycisk pozostaje niebieski po dotknięciu. Nie chcę tego.

  • Mógłbym dodać no-hoverklasę ontouchenddla każdego przycisku i zrobić mój CSS w ten sposób: button:not(.no-hover):hover { background-color: blue; }ale prawdopodobnie jest to dość złe dla wydajności i nie obsługuje poprawnie urządzeń takich jak Chromebook Pixel (który ma zarówno ekran dotykowy, jak i mysz).

  • Mógłbym dodać touchklasę do documentElementi zrobić mój CSS w ten sposób: html:not(.touch) button:hover { background-color: blue; }Ale to też nie działa dobrze na urządzeniach z dotykiem i myszą.

Wolałbym usunąć stan najechania ontouchend. Ale wydaje się, że nie jest to możliwe. Skupienie na innym elemencie nie usuwa stanu najechania. Ręczne dotknięcie innego elementu działa, ale nie wydaje się, żebym to wywołał w JavaScript.

Wszystkie znalezione przeze mnie rozwiązania wydają się niedoskonałe. Czy istnieje idealne rozwiązanie?

Chris
źródło

Odpowiedzi:

55

Możesz usunąć stan najechania, tymczasowo usuwając link z DOM. Zobacz http://testbug.handcraft.com/ipad.html


W CSS masz:

:hover {background:red;}

W JS masz:

function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}

A następnie w swoim HTML masz:

<a href="#" ontouchend="this.onclick=fix">test</a>
Darren Cook
źródło
3
@Chris Słuszna uwaga, zmieniłem przykład, aby ustawić procedurę obsługi onclick w zdarzeniu ontouchend.
Sjoerd Visscher
4
Rozważ dodanie minimalnego kodu poglądowego do swojej odpowiedzi. Dzięki! stackoverflow.com/help/how-to-answer
2540625
1
@SjoerdVisscher Wkleiłem go. StackOverflow lubi, gdy kod jest w odpowiedzi, ponieważ linki mogą zniknąć. (W tym przypadku wymagało to nie tylko kliknięcia, ale także obejrzenia źródła i ustalenia, które bity są tą techniką.)
Darren Cook,
2
@KevinBorders tak, na niektórych urządzeniach opóźnienie czasowe między wyjęciem i ponownym włożeniem elementu może być bardzo zauważalne. Niestety na moim urządzeniu z Androidem 4.4 zauważyłem, że zrobienie tego bez setTimeout nie działa.
Rodney,
1
Pomysł jest interesujący, ale wydaje mi się nieco nierówny i nie jest szeroko obsługiwany na wszystkich urządzeniach dotykowych. Wolałbym mniej inwazyjne rozwiązanie oparte na wykrywaniu wsparcia dotykowego i czystym CSS, takim jak ten stackoverflow.com/a/39787268/885464
Lorenzo Polidori
83

Po zaimplementowaniu CSS Media Queries Level 4 będziesz mógł to zrobić:

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}

Lub po angielsku: „Jeśli przeglądarka obsługuje prawidłowe / prawdziwe / rzeczywiste / nieemulowane najechanie kursorem (np. Ma podstawowe urządzenie wejściowe przypominające mysz), zastosuj ten styl po najechaniu kursorem na buttons.”

Ponieważ ta część Media Queries Level 4 została do tej pory zaimplementowana tylko w najnowszej wersji Chrome, napisałem polyfill, aby sobie z tym poradzić. Używając go, możesz przekształcić powyższy futurystyczny CSS w:

html.my-true-hover button:hover {
    background-color: blue;
}

(Odmiana tej .no-touchtechniki) Następnie używając JavaScript po stronie klienta z tego samego polyfillu, który wykrywa obsługę zawisu, możesz odpowiednio przełączyć obecność my-true-hoverklasy:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
cvrebert
źródło
Dzięki! Dla moich celów wydaje się, że jest to obsługiwane w większości przeglądarek caniuse.com/#search=media%20queries i działa znakomicie, dzięki!
ragamufin
3
Zamiast tego musisz spojrzeć na caniuse.com/#feat=css-media-interaction, a zobaczysz, że nie jest obsługiwana w Firefoksie i IE11 :( więc potrzebujesz wypełnienia polyfill
CherryDT
Wygląda na to, że polyfill nie jest już obsługiwany (repozytorium jest zarchiwizowane) i wymaga jQuery ...
amoebe
Jest to teraz szeroko obsługiwane w przeglądarkach mobilnych i działa jak urok. Myślę, że powinna to być akceptowana odpowiedź.
Trevor Burnham
Jest to zdecydowanie najłatwiejsza do wdrożenia i najlepsza odpowiedź. Działa w Firefoksie na urządzeniach z Androidem i PC. Nie jestem pewien co do urządzeń dotykowych i myszy.
HalfMens
28

To częsty problem bez idealnego rozwiązania. Zachowanie najechania kursorem jest przydatne w przypadku myszy i najczęściej szkodliwe w przypadku dotyku. Dodatkowym problemem są urządzenia obsługujące dotyk i mysz (jednocześnie, nie mniej!), Takie jak Chromebook Pixel i Surface.

Najczystszym rozwiązaniem, jakie znalazłem, jest włączenie zachowania najechania kursorem tylko wtedy, gdy urządzenie nie obsługuje wprowadzania dotykowego.

var isTouch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

if( !isTouch ){
    // add class which defines hover behavior
}

To prawda, tracisz najechanie na urządzeniach, które mogą go obsługiwać. Czasami jednak najechanie kursorem ma większy wpływ niż sam link, np. Być może chcesz wyświetlić menu po najechaniu kursorem na element. Takie podejście pozwala przetestować istnienie dotyku i być może warunkowo dołączyć inne zdarzenie.

Przetestowałem to na iPhonie, iPadzie, Chromebooku Pixel, Surface i różnych urządzeniach z Androidem. Nie mogę zagwarantować, że zadziała, gdy do miksu zostanie dodane standardowe wejście dotykowe USB (takie jak rysik).

Tim Medora
źródło
1
Świetnie, to zadziałało dla mnie, w przeciwieństwie do odpowiedzi wiki społeczności / Darren Cook.
Jannik
1
Dobra odpowiedź. To jest podobne rozwiązanie: stackoverflow.com/a/39787268/885464
Lorenzo Polidori
11

Dzięki Modernizr możesz kierować najechania specjalnie dla urządzeń bezdotykowych:

(Uwaga: to nie działa w systemie fragmentów StackOverflow, zamiast tego sprawdź jsfiddle )

/* this one is sticky */
#regular:hover, #regular:active {
  opacity: 0.5;
}

/* this one isn't */
html.no-touch #no-touch:hover, #no-touch:active {
  opacity: 0.5;
}

Pamiętaj, że :activenie musi być celem kierowania, .no-touchponieważ działa zgodnie z oczekiwaniami zarówno na urządzeniach mobilnych, jak i na komputerach stacjonarnych.

rachel
źródło
To najlepsza odpowiedź IMO, ALE przykład jest niepoprawny. Pokazuje ten sam stan najechania na urządzenia dotykowe i bezdotykowe. Powinien zastosować stan aktywowania tylko wtedy, gdy .no-touchjest obecny na htmltagu. W przeciwnym razie ta odpowiedź otrzyma moją pieczęć aprobaty.
morrisbret
2
Problem polega na tym, że teraz, gdy urządzenia z obsługą myszy i ekranami dotykowymi są wszędzie, nie można już polegać na tej metodzie. Jednak nie widzę innego sposobu, aby to zrobić ... to jest spory dylemat
dudewad
Przypuszczam, że jednym ze sposobów byłoby użycie zarówno programu Modernizr, jak i biblioteki, takiej jak mobile-detection.js, aby upewnić się, że jest to telefon lub tablet.
Gavin
Jesteś zbawicielem, wielkie dzięki, że działało to idealnie na urządzeniach mobilnych
Shivam
8
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});
Verard Sloggett
źródło
Możesz poprawić tę odpowiedź, używając on () zamiast kliknięcia (). Usuwając element z DOM i ponownie go dołączając, straciłem zdarzenia kliknięcia. Kiedy przepisałem swoją funkcję z włączeniem, wiązanie się z elementem, a następnie usuwanie i dodawanie działało. Na przykład: `$ ('body'). On ('click', '# elementwithhover', function () {// clone, insertafter, remove}); Zagłosuję za tym, jeśli wprowadzisz tę zmianę.
Will Lanni
clone true zachowuje zdarzenie click na nowym elemenecie, zajmując miejsce elementu z zablokowanym kursorem. oryginalny element jest usuwany z domeny po jego sklonowaniu.
Verard Sloggett
niesamowity stary, 10x
Kaloyan Stamatov
Godziny poszukiwań rozwiązania, które w końcu dostarczyło. Stukrotne dzięki!
phil917
8

Od 4 sposoby radzenia sobie z lepkiej najechaniu na mobile : Oto sposób dynamicznie dodać lub usunąć „ can touch” klasy do dokumentu w oparciu o bieżący typ wejściowego użytkownika. Działa również z urządzeniami hybrydowymi, w których użytkownik może przełączać się między dotykiem a myszą / gładzikiem:

<script>

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")

    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }

    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }

    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

</script>
chrupki kokosowe
źródło
To najlepszy sposób, jaki znalazłem, a jeśli zwiększysz licznik czasu do 1000 ms, możesz również pokryć długie naciśnięcie, patrz tutaj . Świetne rzeczy!
lowtechsun
8

Możesz zastąpić efekt najechania na urządzenia, które nie obsługują wskaźnika. Lubić:

.my-thing {
    color: #BADA55;
}

.my-thing:hover {
    color: hotpink;
}

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}

Przetestowane i zweryfikowane na iOS 12

Wskazówka na temat https://stackoverflow.com/a/50285058/178959, aby to wskazać.

OrganicPanda
źródło
Jest to nowocześniejsze rozwiązanie, nie wymaga manipulacji javascript ani DOM, ma pełną obsługę przeglądarki (z wyjątkiem IE) i powinno być akceptowaną odpowiedzią.
funkju
3

Miałem zamieścić własne rozwiązanie, ale sprawdzając, czy ktoś już je opublikował, stwierdziłem, że @Rodney prawie to zrobił. Jednak brakowało mu tego ostatniego kluczowego elementu, który sprawił, że było to niesmaczne, przynajmniej w moim przypadku. To znaczy, ja też wziąłem ten sam .fakeHoverdodatek klasa / usuwania pośrednictwem mouseenteri mouseleavezdarzeń detekcji, ale że sam, per se , działa niemal identycznie jak „prawdziwy” :hover. Mam na myśli: kiedy stukasz w element w swojej tabeli, nie wykryje on, że go „opuściłeś” - zachowując w ten sposób stan „fałszywego”.

To, co zrobiłem, to po prostu nasłuchiwać click, więc kiedy „dotykam” przycisku, ręcznie uruchamiam plik mouseleave.

To jest mój ostateczny kod:

.fakeHover {
    background-color: blue;
}


$(document).on('mouseenter', 'button.myButton',function(){
    $(this).addClass('fakeHover');
});

$(document).on('mouseleave', 'button.myButton',function(){
    $(this).removeClass('fakeHover');
});

$(document).on('button.myButton, 'click', function(){
    $(this).mouseleave();
});

W ten sposób zachowujesz swoją zwykłą hoverfunkcjonalność podczas używania myszy po prostu „najeżdżając” na przyciski. Cóż, prawie wszystko: jedyną wadą jest to, że po kliknięciu myszką na przycisk nie będzie w hoverstanie. Podobnie jak w przypadku kliknięcia i szybkiego usunięcia wskaźnika z przycisku. Ale w moim przypadku mogę z tym żyć.

Pere
źródło
2

Oto, co wymyśliłem do tej pory po przestudiowaniu pozostałych odpowiedzi. Powinien być w stanie obsługiwać tylko użytkowników dotykowych, tylko myszy lub hybrydowych.

Utwórz osobną klasę najechania dla efektu najechania. Domyślnie dodaj tę klasę hover do naszego przycisku.

Nie chcemy wykrywać obecności obsługi dotyku i wyłączać od samego początku wszystkie efekty najechania kursorem. Jak wspominali inni, urządzenia hybrydowe zyskują na popularności; ludzie mogą mieć obsługę dotykową, ale chcą używać myszy i odwrotnie. Dlatego należy usuwać klasę aktywowania tylko wtedy, gdy użytkownik faktycznie dotknie przycisku.

Następnym problemem jest to, co jeśli użytkownik chce wrócić do korzystania z myszy po dotknięciu przycisku? Aby rozwiązać ten problem, musimy znaleźć odpowiedni moment, aby z powrotem dodać klasę dymienia, którą usunęliśmy.

Nie możemy jednak dodać go z powrotem natychmiast po jego usunięciu, ponieważ stan najechania jest nadal aktywny. Możemy też nie chcieć zniszczyć i odtworzyć całego przycisku.

Pomyślałem więc o użyciu algorytmu zajętości (za pomocą setInterval) do sprawdzenia stanu aktywowania. Po dezaktywacji stanu najechania możemy ponownie dodać klasę najechania i zatrzymać oczekiwanie zajętości, przywracając nas z powrotem do pierwotnego stanu, w którym użytkownik może używać myszy lub dotyku.

Wiem, że zajęty czekanie nie jest takie wspaniałe, ale nie jestem pewien, czy jest odpowiednie wydarzenie. Rozważałem dodanie go z powrotem podczas imprezy mouseleave, ale nie był on zbyt mocny. Na przykład, gdy alert pojawia się po naciśnięciu przycisku, pozycja myszy zmienia się, ale zdarzenie mouseleave nie jest wyzwalane.

var button = document.getElementById('myButton');

button.ontouchstart = function(e) {
  console.log('ontouchstart');
  $('.button').removeClass('button-hover');
  startIntervalToResetHover();
};

button.onclick = function(e) {
  console.log('onclick');
}

var intervalId;

function startIntervalToResetHover() {
  // Clear the previous one, if any.
  if (intervalId) {
    clearInterval(intervalId);
  }
  
  intervalId = setInterval(function() {
    // Stop if the hover class already exists.
    if ($('.button').hasClass('button-hover')) {
      clearInterval(intervalId);
      intervalId = null;
      return;
    }
    
    // Checking of hover state from 
    // http://stackoverflow.com/a/8981521/2669960.
    var isHovered = !!$('.button').filter(function() {
      return $(this).is(":hover");
    }).length;
    
    if (isHovered) {
      console.log('Hover state is active');
    } else {
      console.log('Hover state is inactive');
      $('.button').addClass('button-hover');
      console.log('Added back the button-hover class');
      
      clearInterval(intervalId);
      intervalId = null;
    }
  }, 1000);
}
.button {
  color: green;
  border: none;
}

.button-hover:hover {
  background: yellow;
  border: none;
}

.button:active {
  border: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='myButton' class='button button-hover'>Hello</button>

Edycja: Innym podejściem, które próbowałem, jest wywołanie e.preventDefault()w ramach ontouchstart lub ontouchend. Wydaje się, że zatrzymuje efekt najechania po dotknięciu przycisku, ale także zatrzymuje animację kliknięcia przycisku i zapobiega wywoływaniu funkcji onclick po dotknięciu przycisku, więc musisz wywoływać je ręcznie w obsłudze ontouchstart lub ontouchend. Niezbyt czyste rozwiązanie.

Kevin Lee
źródło
1

To było dla mnie pomocne: link

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
mineroot
źródło
Należy raz wywołać funkcję hoverTouchUnstick () z globalnej procedury obsługi zdarzeń ontouchstart. I to rozwiązanie sprawdziłoby się idealnie.
Jusid
1

Dodaj ten kod JS do swojej strony:

document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';

teraz w twoim CSS przed każdym najechaniem dodaj klasę hover w ten sposób:

.hover .foo:hover {}

Jeśli urządzenie jest dotykane, klasa ciała będzie pusta, w przeciwnym razie jego klasa zostanie najechana, a reguły zostaną zastosowane!

Ali
źródło
Nie działało dla mnie, ale to document.body.className = 'ontouchstart' in window ? '' : 'hover';
działało
1

Mógłbym dodać klasę ontouchend bez najechania kursorem dla każdego przycisku i sprawić, by mój CSS wyglądał następująco: button: not (.no-hover): hover {background-color: blue; }, ale jest to prawdopodobnie bardzo niekorzystne dla wydajności i nie obsługuje> urządzeń takich jak Chromebook Pixel (który ma zarówno ekran dotykowy, jak i mysz)> poprawnie.

To jest właściwy punkt wyjścia. Następny krok: zastosuj / usuń klasę nohover na kolejnych zdarzeniach (demo z jQuery)

buttonelement
 .on("touchend touchcancel",function(){$(this).addClass("nohover")})
 .on("touchstart mouseover",function({$(this).removeClass("nohover")});   

Uwaga: Jeśli chcesz zastosować inne klasy do elementu przycisku, polecenie: not (.nohover) w CSS nie będzie już działać zgodnie z oczekiwaniami. Zamiast tego musisz dodać oddzielną definicję z wartością domyślną i znacznikiem! Important, aby nadpisać styl najechania: .nohover {background-color: white! Important}

Powinno to nawet poprawnie obsługiwać urządzenia takie jak Chromebook Pixel (który ma zarówno ekran dotykowy, jak i mysz)! I nie sądzę, żeby to był wielki zabójca wydajności ...

Sascha Hendel
źródło
1

Rozwiązanie, które się sprawdziło:

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

Dodaj ten kod do swojego arkusza stylów.

Chciałem pozbyć się szarego tła, które pojawia się na iOS Safari po kliknięciu łącza. Ale wydaje się, że robi więcej. Teraz kliknięcie przycisku (z :hoverpseudoklasą!) Otwiera się od razu! Przetestowałem to tylko na iPadzie, nie wiem, czy zadziała na innych urządzeniach.

Leon Vogler
źródło
1

Myślę, że znalazłem eleganckie (minimum js) rozwiązanie podobnego problemu:

Korzystając z jQuery, możesz wyzwolić najechanie na ciało (lub dowolny inny element), używając .mouseover()

Więc po prostu dołączam this handler do ontouchendzdarzenia elementu w następujący sposób:

var unhover = function() {
  $("body").mousover();  
};
.hoverable {
  width: 100px;
  height: 100px;
  background: teal;
  cursor: pointer;
}

.hoverable:hover {
  background: pink;
}
<div class="hoverable" ontouchend={unhover}></div>

To jednak usuwa tylko: najedź na pseudoklasę z elementu po wywołaniu jakiegoś innego zdarzenia dotykowego, takiego jak przesunięcie lub inny dotyk

Ian Averno
źródło
1
W przypadku fragmentu kodu kwadrat po dotknięciu nadal pozostaje różowy. Myślę, że tak naprawdę nie rozwiązałeś problemu zadanego w tym pytaniu?
Kevin Lee
To rozwiązanie nie działa. Po pierwsze, użyłeś złej metody do wywołania zdarzenia, powinieneś użyć .trigger () . Po drugie, tak czy inaczej nie działa na mobilnym safari.
xHocquet
1

Mam fajne rozwiązanie, którym chciałbym się podzielić. Najpierw musisz wykryć, czy użytkownik korzysta z telefonu komórkowego w następujący sposób:

var touchDevice = /ipad|iphone|android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());

Następnie po prostu dodaj:

if (!touchDevice) {
    $(".navbar-ul").addClass("hoverable");
}

A w CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}
Michał Reszka
źródło
2
Nie działa na urządzeniach hybrydowych, np. Komputerach z ekranem dotykowym Windows.
cspolton
1

Przeszedłem przez podobny problem, moja aplikacja była kompatybilna ze wszystkimi rozmiarami ekranu, miała cholernie dużo efektów najechania kursorem na urządzeniach opartych na rozmiarze ekranu / myszy, a później zdałem sobie sprawę, że urządzenia dotykowe powodują stan znany jako lepki - najechanie kursorem i było to przeszkodą, aby aplikacja działała poprawnie dla użytkowników urządzeń dotykowych.

W naszej aplikacji korzystaliśmy z SCSS . i zdefiniowałem mixin, aby zająć się urządzeniem dotykowym.

@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}

a następnie umieściłem wszystkie moje klasy css pod poniższym fragmentem.

   @include hover-support() {
    // Your css-classes or css that you want to apply on those devices that support hover.
   }

Na przykład mieliśmy klasę do animowania ikony, która wyzwalała się po najechaniu kursorem na ikonę, jak widać z css, ale na urządzeniu dotykowym wpływał na nią efekt lepkiego najechania kursorem, a następnie umieściłem go wewnątrz @ Uwzględnij hover-support () , aby upewnić się, że hover dotyczy tylko tych urządzeń, które obsługują hover.

@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}
Divyanshu Rawat
źródło
1

Oto prosty kod JavaScript, który nie wymaga od programisty edycji CSS ani pisania nowych reguł CSS. Napisałem to dla przycisków Bootstrap z class="btn", ale będzie działać z każdym przyciskiem, który ma określoną nazwę klasy.

Kroki są następujące:

  1. określić, czy jest to urządzenie dotykowe
  2. jeśli tak, iteruj po każdej regule CSS w document.styleSheets
  3. usuń dowolną regułę zawierającą zarówno .btni:hover

Wyeliminowanie wszystkich .btn :hoverreguł CSS gwarantuje, że na przycisku nie będzie wizualnego efektu najechania kursorem.

Krok 1: Wykryj urządzenie dotykowe

Sprawdź zapytanie o media pod kątem obecności (hover: none):

    const hasMatchMedia = typeof window.matchMedia !== 'undefined';
    /**
     * determine if device is touch-capable
     * true - device is touch-capable
     * false - device is not touch-capable
     * null - unable to determine touch capability
     * @return {null|boolean}
     */
    const hasTouch = () => {
      if (hasMatchMedia) {
        return window.matchMedia('(hover: none)').matches;
      }
      return null;
    };

Krok 2: Usuń reguły CSS zawierające „btn” i „: hover”

    /**
     * remove all CSS rules contaning both '.btn' and ':hover'
     * @return {number} count of rules deleted
     */
    function removeBtnHovers () {

      let rulesDeleted = 0;

      // recursively delete '.btn:hover' rules
      function recursiveDelete (rules, styleSheet) {

        if (typeof rules === 'undefined' ||
          typeof rules.length === 'undefined' ||
          rules.length <= 0) {
          return;
        }

        // iterate in reverse order,
        // deleting any rule containing both '.btn' and ':hover'
        const ruleLen = rules.length;
        for (let i = ruleLen - 1; i >= 0; i--) {
          const rule = rules[i];
          if (typeof rule.cssRules === 'undefined') {
            // a standard rule, evaluate it
            const cssText = rule.cssText;
            if (typeof cssText === 'string' &&
              cssText.includes('.btn') &&
              cssText.includes(':hover')) {
              styleSheet.deleteRule(i);
              rulesDeleted++;
            }
          } else {
            // rule contains cssRules, iterate over them
            recursiveDelete(rule.cssRules, rule);
          }
        }
      }

      // iterate over all style sheets in document
      for (const styleSheet of document.styleSheets) {
        let rules = styleSheet.cssRules;
        if (!rules) { continue; }
        recursiveDelete(rules, styleSheet);
      }
      return rulesDeleted;
    }

Kompletny kod znajduje się na GitHub i npm .

Demo na żywo na terrymorse.com .

terrymorse
źródło
Czy nie usuwa to również efektu najechania na urządzenia z ekranem dotykowym z myszą / gładzikiem?
Jensei
@Jensei Ewentualnie. Reguły najechania są usuwane, jeśli urządzenie pasuje @media (hover:none)lub gdy użytkownik po raz pierwszy dotknie ekranu. Możesz to wypróbować na stronie demonstracyjnej na żywo, aby mieć pewność.
terrymorse
0

Możesz ustawić kolor tła na :activestan i nadać :focus niewyraźne tło.

jeśli ustawisz kolor tła za pomocą onfocus/ontouch, styl koloru pozostanie po zniknięciu :focusstanu.
Potrzebujesz również zresetowania, onbluraby przywrócić defaut bg po utracie ostrości.

G-Cyrillus
źródło
Ale chciałbym zachować efekt najechania kursorem dla użytkowników myszy.
Chris
: hover i: active mogą otrzymać ten sam CSS, jest na: focus masz problem. W rzeczywistości, jeśli ustawisz kolor tła za pomocą funkcji onfocus, styl koloru pozostanie po zniknięciu ostrości. potrzebujesz również resetu na onlur, aby przywrócić defaut bg
G-Cyrillus
0

To zadziałało dla mnie: umieść stylizację na hover w nowej klasie

.fakehover {background: red}

Następnie dodaj / usuń klasę w razie potrzeby

$(".someclass > li").on("mouseenter", function(e) {
  $(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
  $(this).removeClass("fakehover");
});

Powtórz dla zdarzeń Touchstart i Touchstart. Lub jakiekolwiek zdarzenia, które lubisz, aby uzyskać pożądany rezultat, na przykład chciałem, aby efekt najechania był przełączany na ekranie dotykowym.

Rodney
źródło
0

Na podstawie odpowiedzi Darrena Cooksa, która działa również, jeśli przesuniesz palcem po innym elemencie.

Zobacz Znajdź palec elementu jest włączony podczas zdarzenia dotknięcia

jQuery(function() {
    FastClick.attach(document.body);
});
// Prevent sticky hover effects for buttons on touch devices
// From https://stackoverflow.com/a/17234319
//
//
// Usage:
// <a href="..." touch-focus-fix>..</a>
//
// Refactored from a directive for better performance and compability
jQuery(document.documentElement).on('touchend', function(event) {
  'use strict';

  function fix(sourceElement) {
    var el = $(sourceElement).closest('[touch-focus-fix]')[0];
    if (!el) {
      return;
    }
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    par.insertBefore(el, next);
  }

  fix(event.target);
  var changedTouch = event.originalEvent.changedTouches[0];
  // http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchend-event
  if (!changedTouch) {
    return;
  }
  var touchTarget = document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
  if (touchTarget && touchTarget !== event.target) {
    fix(touchTarget);
  }
});

Codepen Demo

jantimon
źródło
0

Możesz spróbować w ten sposób.

javascript:

var isEventSupported = function (eventName, elementName) {
    var el = elementName ? document.createElement(elementName) : window;
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported && el.setAttribute) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
    }
    el = null;
    return isSupported;
};

if (!isEventSupported('touchstart')) {
    $('a').addClass('with-hover');
}

css:

a.with-hover:hover {
  color: #fafafa;
}
Lorenzo Polidori
źródło
0

Do tej pory w moich projektach cofałem :hoverzmiany na urządzeniach dotykowych:

.myhoveredclass {
    background-color:green;
}
.myhoveredclass:hover {
    background-color:red;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
    .myhoveredclass:hover, .myhoveredclass:active, .myhoveredclass:focus {
        background-color:green;
    }
}

Wszystkie nazwy klas i nazwane kolory tylko w celach demonstracyjnych ;-)

z00l
źródło
0

Działa to idealnie w 2 krokach.

  1. Ustaw swój tag body tak, aby był taki <body ontouchstart="">. Nie jestem fanem tego „hackowania”, ale pozwala on Safari na iOS natychmiast reagować na dotyk. Nie wiem jak, ale to działa.

  2. Skonfiguruj swoją dotykalną klasę w następujący sposób:

    // I did this in SASS, but this should work with normal CSS as well
    
    // Touchable class
    .example {
    
        // Default styles
        background: green;
    
        // Default hover styles 
        // (Think of this as Desktop and larger)
        &:hover {
            background: yellow;
        }
    
        // Default active styles
        &:active {
            background: red;
        }
    
        // Setup breakpoint for smaller device widths
        @media only screen and (max-width: 1048px) {
    
            // Important!
            // Reset touchable hover styles
            // You may want to use the same exact styles as the Default styles
            &:hover {
                background: green;
            }
    
            // Important!
            // Touchable active styles
            &:active {
                background: red;
            }
        }
    }

Możesz również chcieć usunąć jakąkolwiek animację z klasy, którą można dotykać. Android Chrome wydaje się być nieco wolniejszy niż iOS.

Spowoduje to również zastosowanie stanu aktywnego, jeśli użytkownik przewinie stronę, dotykając zajęć.

Michael
źródło
0

Niektóre z lepkich lub blokowanych :hover :focus :activeproblemów na urządzeniach mobilnych mogą być spowodowane brakiem, <meta name="viewport" content="width=device-width">gdy przeglądarki próbują manipulować ekranem.

GEkk
źródło
0

Rozwiązaniem dla mnie po touchend było sklonowanie i zastąpienie węzła ... nienawidzę tego robić, ale nawet próba przemalowania elementu za pomocą offsetHeight nie działała

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );
Banowanie
źródło
W końcu to nie zadziałało ... w moim przypadku musiałbym sklonować cały ES6, który jest rozszerzony i kilka słuchaczy wydarzeń, a rozwiązanie tak małej rzeczy zaczęło się komplikować.
Zakaz
0

Można to osiągnąć poprzez zamianę klasy HTML. Powinien być mniej podatny na usterki niż usuwanie całego elementu, szczególnie w przypadku dużych, graficznych linków itp.

Możemy również zdecydować, czy chcemy, aby stany najechania były wyzwalane podczas przewijania za pomocą dotyku (touchmove), czy nawet dodać limit czasu, aby je opóźnić.

Jedyną znaczącą zmianą w naszym kodzie będzie użycie dodatkowej klasy HTML, takiej jak <a class='hover'></a>na elementach implementujących nowe zachowanie.

HTML

<a class='my-link hover' href='#'>
    Test
</a>

CSS

.my-link:active, // :active can be turned off to disable hover state on 'touchmove'
.my-link.hover:hover {

    border: 2px dotted grey;
}

JS (z jQuery)

$('.hover').bind('touchstart', function () {

   var $el;
   $el = $(this);
   $el.removeClass('hover'); 

   $el.hover(null, function () {
      $el.addClass('hover');
   });
});

Przykład

https://codepen.io/mattrcouk/pen/VweajZv

-

Nie mam jednak żadnego urządzenia z myszą i dotykiem, aby poprawnie je przetestować.

Maciek Rek
źródło