İPhone / iPad kullanıcıları için: hover sözde sınıfını görmezden gelmeye zorlamak mümkün mü?


95

Sitemde :hoverjs olmadan genişleyen bazı css menülerim var

Bu, iDevices üzerinde yarı kırık bir şekilde çalışır, örneğin bir dokunma :hoverkuralı etkinleştirir ve menüyü genişletir, ancak daha sonra başka bir yere dokunmak :hover. Ayrıca, öğenin içinde bir bağlantı varsa, bağlantıyı :hoveretkinleştirmek için iki kez dokunmanız gerekir (ilk dokunma tetikleri :hover, ikinci dokunma tetikleme bağlantısı).

touchstartEtkinliği bağlayarak iphone'da işlerin güzel çalışmasını sağladım .

Sorun bazen mobil safari hala tetiklemek için seçtiği olmasıdır :hovercss gelen kuralı yerine benim ait touchstartolaylar!

Sorunun bu olduğunu biliyorum, çünkü css'de tüm :hoverkuralları manuel olarak devre dışı bıraktığımda , mobil safari harika çalışıyor (ancak normal tarayıcılar artık açıkça değil).

Kullanıcı :hovermobil safarideyken belirli öğeler için kuralları dinamik olarak "iptal etmenin" bir yolu var mı ?

İOS davranışını burada görün ve karşılaştırın: http://jsfiddle.net/74s35/3/ Not: Yalnızca bazı css özellikleri iki tıklama davranışını tetikler, örneğin display: none; ancak arka plan değil: kırmızı; veya metin süsleme: altı çizili;


7
LÜTFEN, yalnızca 'dokunma' olaylarının varlığı nedeniyle gezinmeyi devre dışı bırakmayın. Bu, dokunmatik ve fare giriş cihazlarına sahip dizüstü bilgisayar kullanıcılarını olumsuz etkileyecektir. Daha fazla ayrıntı için cevabımı görün
Simon_Weaver

Yanıtlar:


77

İPhone / iPad Safari'de ": hover" ifadesinin tahmin edilemez olduğunu buldum. Bazen öğeye hafifçe vurmak o öğeyi ": hover" yapar, bazen de diğer öğelere sürüklenir.

Şimdilik, bedenimde sadece "dokunmadan" dersim var.

<body class="yui3-skin-sam no-touch">
   ...
</body>

Ve ".no-touch" altında ": hover" olan tüm CSS kurallarına sahip olun:

.no-touch my:hover{
   color: red;
}

Sayfanın bir yerinde, dokunmasız sınıfı vücuttan kaldırmak için javascript'im var .

if ('ontouchstart' in document) {
    Y.one('body').removeClass('no-touch');
}

Bu mükemmel görünmüyor, ama yine de çalışıyor.


5
Bunu yapmanın tek yolu bu. Beni rahatsız eden şey, "normal" siteyi oraya ait olmayan ve alakasız şeylerle kirletmesi. Oh iyi. Teşekkürler.
Christopher Camps

Ayrıca, IE için bir yedek içeren medya sorgularını da kullanabilirsiniz
Lime

2
@Shackrock: "Fareyle üzerine gelmek için bir kez hafifçe vurmak ve iki tıklamak için iki kez tıklamak" yaklaşımının iyi bir çözüm olduğunu düşünmüyorum. Aslında dokunmatik bir cihazda gerçek bir fareyle üzerine gelme olmadığından (parmağınızın üzerinde gezindiğini algılayan ekranlarla gelene kadar), gezinmeyi hiç taklit etmemenin daha iyi olacağını düşünüyorum. Düğmelerde ve bağlantılarda yaygın olanlar gibi efektler için efekti atlayın. Fareyle üzerine gelindiğinde genişleyen menüler için, bunun yerine dokunma / tıklama ile genişletmelerini sağlayın. 2c.
Adrian Schmidt

18
Dokunmatik ve fare girişi içeren yeni Windows 8 sistemleri nedeniyle son zamanlarda bu tür bir yaklaşımda sorunlar buldum
Tom

4
Tom'un yorumuna +1 - ontouchstart'ın kontrol edilmesi, harici bir monitöre takılı olsa bile dokunmatik özellikli dizüstü bilgisayarlarda gerçek değerine dönecektir (fareyle üzerine gelme durumları olan fare dostu bir sitenin daha çok tercih edildiği yerlerde).
gregdev

45

:hoverburadaki sorun değil. İOS için Safari, çok garip bir kuralı takip ediyor. Ateşler mouseoverve mousemoveönce; bu olaylar sırasında herhangi bir değişiklik olursa, 'tıklama' ve ilgili olaylar tetiklenmez:

İOS'ta dokunma olayının şeması

mouseenterve mouseleavegrafikte belirtilmemiş olsalar da dahil edilmiş görünüyorlar.

Bu olayların sonucu olarak herhangi bir değişiklik yaparsanız, tıklama etkinlikleri tetiklenmez. Bu, DOM ağacında daha yukarıda olan bir şeyi içerir. Örneğin, bu, jQuery ile web sitenizde tek tıklamaların çalışmasını engeller:

$(window).on('mousemove', function() {
    $('body').attr('rel', Math.random());
});

Düzenleme: Açıklama için jQuery'nin hoveretkinliği mouseenterve içerir mouseleave. Bunların ikisi de clickiçeriğin değiştirilmesini önleyecektir .


5
tabii ki: vurgulu sorun :-) veya daha doğrusu Safari'nin buggy uygulaması. bu, konuyla ilgili ilginç bir arka plan, ancak Apple, bu korkunç davranışı düzeltebilecek tek taraf. ya öğelerin dışındaki bir şey tıklandığında "unhover" yapması veya ilk etapta asla "üzerine gelmemesi" gerekir. şu anki davranış temelde şunu kullanan herhangi bir web sitesini bozuyor: fare için üzerine gelin
Simon_Weaver

bu, jquery hoverişleyicisinin ayrı bir clickişleyiciye vurulmasını engellediğini anlamama yardımcı oldu - ne şaka!
Simon_Weaver

1
Mükemmel yanıt ve karşılaştığım sorunun en iyi açıklaması. "Çift tıklama" sorununa neden olan sadece CSS gezinmeleri değil, fareyle üzerine gelme / mouseenter ve diğerleri olaylarından sonra gerçek anlamda herhangi bir DOM değişikliği.
Oliver Joseph Ash


@Oliver Joseph Ash Doğru, bu nedenle cevaptaki JS örneği. ;)
Zenexer

18

Tarayıcı özelliği algılama kitaplığı Modernizer , dokunma olayları için bir kontrol içerir.

Varsayılan davranış, algılanan her özellik için html öğenize sınıfları uygulamaktır. Daha sonra bu sınıfları belgenize stil uygulamak için kullanabilirsiniz.

Dokunma olayları etkinleştirilmezse, Modernizr bir sınıf ekleyebilir no-touch:

<html class="no-touch">

Ve sonra bu sınıfla üzerine gelme stillerinizin kapsamını belirleyin:

.no-touch a:hover { /* hover styles here */ }

Sen olabilir özel bir Modernizr yapımını indirerek İhtiyacınız kadar az ya da çok sayıda özellik, algılamalar olarak eklenecek.

Aşağıda, uygulanabilecek bazı sınıfların bir örneği verilmiştir:

<html class="js no-touch postmessage history multiplebgs
             boxshadow opacity cssanimations csscolumns cssgradients
             csstransforms csstransitions fontface localstorage sessionstorage
             svg inlinesvg no-blobbuilder blob bloburls download formdata">

Modernizr'in "dokunma" olarak bildirdiği masaüstü bilgisayarlardaki son Chrome sürümlerinde olduğunu unutmayın. Görünüşe göre bu, sürüm 3'te dokunmatik olaylarla düzeltildi.
Craig Jacobs

18

Bazı cihazlarda (diğerlerinin söylediği gibi) hem dokunma hem de fare etkinlikleri vardır. Örneğin Microsoft Surface, bir dokunmatik ekrana, bir izleme paneline VE ekranın üzerine getirildiğinde hover olaylarını gerçekten yükselten bir ekrana sahiptir.

:hover'Dokunma' olaylarının varlığına bağlı olarak devre dışı bırakan herhangi bir çözüm, Surface kullanıcılarını (ve diğer birçok benzer cihazı) da etkileyecektir. Birçok yeni dizüstü bilgisayar dokunma özelliğine sahiptir ve dokunma olaylarına yanıt verir - bu nedenle gezinmeyi devre dışı bırakmak gerçekten kötü bir uygulamadır.

Bu Safari'deki bir hatadır, bu korkunç davranışın kesinlikle hiçbir gerekçesi yoktur. Yıllardır var olduğu anlaşılan iOS Safari'deki bir hata nedeniyle iOS olmayan tarayıcıları sabote etmeyi reddediyorum. Umarım önümüzdeki hafta iOS8 için bunu düzeltirler ama bu arada ...

Benim çözümüm :

Bazıları zaten Modernizr'i kullanmayı önerdi, Modernizr kendi testlerinizi oluşturmanıza izin veriyor. Burada temelde yaptığım :hoverşey, kodum boyunca kod yazmadan kullanabileceğim bir Modernizr testini destekleyen bir tarayıcı fikrini 'soyutlamak' if (iOS).

 Modernizr.addTest('workinghover', function ()
 {
      // Safari doesn't 'announce' to the world that it behaves badly with :hover
      // so we have to check the userAgent  
      return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true;
 });

Sonra css böyle bir şeye dönüşür

html.workinghover .rollover:hover 
{
    // rollover css
}

Yalnızca iOS'ta bu test başarısız olur ve rollover'ı devre dışı bırakır.

Bu tür bir soyutlamanın en iyi yanı, belirli bir android üzerinde kırıldığını ya da iOS9'da düzeltildiğini fark edersem, testi değiştirebilirim.


Bu çözüm hem çirkin hem de en iyisidir. Yalnızca üzerine gelme ile mücadele eden bir tarayıcı hem dokunma hem de tıklama yaparsa bozulur, ancak ipad / iphone'daki yalnızca dokunma özellikli tarayıcılar için durum böyle değildir. Benim önerim, bunu yalnızca bir optimizasyon düzeltmesi olarak uygulamak (fastclick.js'yi zaten kullanırken vurgulu titremeyi kaldırmak için) ve her şeyin onsuz da çalıştığından emin olmaktır.
Gersom

Teşekkürler. Katılıyorum. İOS 9'un bu sorun için ne yaptığını merak ediyorum - eğer varsa.
Simon_Weaver

Ters yöne gittim:html:not(.no-hover) .category:hover { ...
Chris Marisic

"Safari, kötü bir şekilde davrandığını dünyaya 'duyurmuyor': üzerine gelindiğinde" Bu sorun, bence
Spencer O'Reilly

17

JS, css sınıfı ve görüntü alanı kontrolü olmadan daha iyi bir çözüm: Etkileşim Medya Özelliklerini kullanabilirsiniz (Medya Sorguları Seviye 4)

Bunun gibi:

@media (hover) {
  // properties
  my:hover {
    color: red;
  }
}

iOS Safari bunu destekliyor

Daha fazla bilgi için: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/


Yine de Firefox tarafından desteklenmiyor (elbette bu yorumun yapıldığı sırada)
Frank

Bu artık Firefox tarafından da destekleniyor (Aralık 2018'de yayınlanan FF 64+).
2019

16

FastClick kitaplığını sayfanıza eklemek, bir mobil cihazdaki tüm dokunmaların tıklama olaylarına dönüştürülmesine neden olur (kullanıcının nerede tıkladığına bakılmaksızın), bu nedenle mobil cihazlarda fareyle üzerine gelme sorununu da düzeltmesi gerekir. Kemanınızı örnek olarak düzenledim: http://jsfiddle.net/FvACN/8/ .

Fastclick.min.js lib dosyasını sayfanıza eklemeniz ve şu yolla etkinleştirmeniz yeterlidir:

FastClick.attach(document.body);

Bir yan fayda olarak, mobil cihazların maruz kaldığı can sıkıcı 300 ms onClick gecikmesini de ortadan kaldıracaktır.


FastClick'i kullanmanın siteniz için önemli olabilecek veya olmayabilecek birkaç küçük sonucu vardır:

  1. Sayfada herhangi bir yere dokunursanız, yukarı kaydırırsanız, aşağı kaydırırsanız ve ardından parmağınızı başlangıçta yerleştirdiğiniz aynı konumda bırakırsanız, FastClick bunu bir "tıklama" olarak yorumlayacaktır, ancak açıkça görülmemesine rağmen. En azından şu anda kullandığım FastClick sürümünde (1.0.0) böyle çalışıyor. Birisi bu sürümden sonra sorunu çözmüş olabilir.
  2. FastClick, birinin "çift tıklama" yeteneğini kaldırır.

1
Bunu web sitem için nasıl yapabileceğime dair başka bir somut örnek paylaşmak ister misiniz? Javascript hakkında hiçbir şey bilmiyorum, bu yüzden bunun nasıl çalışacağı konusunda biraz kafam karıştı. Web sitemde, kullanıcıların genellikle tıklamadan önce üzerine geldikleri tüm bu bağlantılar var, ancak ipad / mobil için iki kez tıklamak zorunda kalmayacakları şekilde yapmak istiyorum.
Andy

@Andy - Neye ihtiyacınız olduğu ve neyi kaçırdığınız tam olarak belli değil ... Şimdiye kadar neyi denediniz ve varsa hangi hataları görüyorsunuz? Henüz yapmadıysanız, ne yapmaya çalıştığınızın bir örneğiyle (?) Yeni bir Stackoverflow sorusu oluşturmak belki de en iyisidir veya yukarıda ne olduğunu netleştirmeye çalışın, jsfiddle örneği ' anlamak.
Troy

bu tek sayfalı uygulamalarda kullanılabilir mi? DOM içeriği her
seferinde

Evet, tek sayfalı uygulamalarla kullanıyorum.
Troy

4

Temel olarak üç senaryo vardır:

  1. Kullanıcı yalnızca bir fare / işaret cihazına sahiptir ve etkinleştirebilir:hover
  2. Kullanıcı yalnızca dokunmatik ekrana sahiptir ve :hoveröğeleri etkinleştiremez
  3. Kullanıcı hem dokunmatik ekrana hem de işaretçi cihazına sahiptir

Başlangıçta kabul edilen cevabı sadece ilk iki senaryo kullanıcı sahip olduğu, mümkünse eğer inşaat büyük ya işaretçi veya dokunmatik ekran. Bu, OP 4 yıl önce soruyu sorduğunda yaygındı. Birkaç kullanıcı, Windows 8 ve Surface cihazlarının üçüncü senaryoyu daha olası hale getirdiğine dikkat çekti.

Dokunmatik ekranlı cihazlarda fareyle üzerine gelememe sorununa yönelik iOS çözümü (@ Zenexer tarafından detaylandırıldığı gibi) akıllıca olsa da, basit kodun yanlış davranmasına neden olabilir (OP tarafından belirtildiği gibi). Fareyle üzerine gelmeyi yalnızca dokunmatik ekranlı cihazlar için devre dışı bırakmak, dokunmatik ekran dostu bir alternatifi kodlamanız gerektiği anlamına gelir. Bir kullanıcının hem işaretçiye hem de dokunmatik ekrana sahip olduğunu tespit etmek suları daha da bulanıklaştırır (@Simon_Weaver tarafından açıklandığı gibi).

Bu noktada, en güvenli çözüm, :hoverbir kullanıcının web sitenizle etkileşime girmesinin tek yolu olarak kullanmaktan kaçınmaktır . Fareyle üzerine gelme efektleri, bir bağlantının veya düğmenin işlem yapılabilir olduğunu belirtmenin iyi bir yoludur, ancak kullanıcının web sitenizde bir eylem gerçekleştirmek için bir öğenin üzerine gelmesine gerek olmamalıdır.

Dokunmatik ekranları göz önünde bulundurarak "üzerine gelme" işlevselliğini yeniden düşünmek , alternatif UX yaklaşımları hakkında iyi bir tartışmaya sahiptir. Buradaki cevabın sağladığı çözümler şunları içerir:

  • Fareyle üzerine gelme menülerini doğrudan eylemlerle değiştirme (her zaman görünür bağlantılar)
  • Fareyle üzerine gelindiğinde açılan menüleri dokunarak menülerle değiştirme
  • Fareyle üzerine gelindiğinde büyük miktarda içeriği ayrı bir sayfaya taşıma

İlerlerken, bu muhtemelen tüm yeni projeler için en iyi çözüm olacaktır. Kabul edilen cevap muhtemelen ikinci en iyi çözümdür, ancak işaretçi cihazlara sahip cihazları da dikkate aldığınızdan emin olun. Bir cihazda yalnızca iOS :hoverhack'ini aşmak için dokunmatik ekran varken işlevselliği ortadan kaldırmamaya dikkat edin .


1

.Cs'lerinizdeki JQuery sürümü .no-touch .my-element kullanır: fareyle üzerine gelme kurallarınız için JQuery ve aşağıdaki komut dosyası bulunur

function removeHoverState(){
    $("body").removeClass("no-touch");
}

Ardından gövde etiketine class = "no-touch" ontouchstart = "removeHoverState ()" ekleyin

ontouchstart ateşlediği anda tüm hover durumları için sınıf kaldırılır


0

Yalnızca dokunma olmadığında gezinme efektlerine sahip olmak yerine, dokunma olaylarını işlemek için bir sistem oluşturdum ve bu benim için sorunu çözdü. İlk olarak, "dokunma" ("tıklama" ile eşdeğer) olaylarını test etmek için bir nesne tanımladım.

touchTester = 
{
    touchStarted: false
   ,moveLimit:    5
   ,moveCount:    null
   ,isSupported:  'ontouchend' in document

   ,isTap: function(event)
   {
      if (!this.isSupported) {
         return true;
      }

      switch (event.originalEvent.type) {
         case 'touchstart':
            this.touchStarted = true;
            this.moveCount    = 0;
            return false;
         case 'touchmove':
            this.moveCount++;
            this.touchStarted = (this.moveCount <= this.moveLimit);
            return false;
         case 'touchend':
            var isTap         = this.touchStarted;
            this.touchStarted = false;
            return isTap;
         default:
            return true;
      }
   }
};

Ardından, olay işleyicimde aşağıdakine benzer bir şey yapıyorum:

$('#nav').on('click touchstart touchmove touchend', 'ul > li > a'
            ,function handleClick(event) {
               if (!touchTester.isTap(event)) {
                  return true;
               }

               // touch was click or touch equivalent
               // nromal handling goes here.
            });

0

Yanıt için teşekkürler @Morgan Cheng, ancak " touchstart " ı elde etmek için JS işlevini biraz değiştirdim (kod @Timothy Perez cevabından alınmıştır ), bunun için jQuery 1.7+ gerekir

  $(document).on({ 'touchstart' : function(){
      //do whatever you want here
    } });

0

Zenexer tarafından sağlanan yanıt göz önüne alındığında, ek HTML etiketi gerektirmeyen bir kalıp:

jQuery('a').on('mouseover', function(event) {
    event.preventDefault();
    // Show and hide your drop down nav or other elem
});
jQuery('a').on('click', function(event) {
    if (jQuery(event.target).children('.dropdown').is(':visible') {
        // Hide your dropdown nav here to unstick
    }
});

Bu yöntem önce fareyle üzerine gelmeyi, sonra tıklamayı tetikler.


0

Dokunma için fareyle üzerine gelmeyi devre dışı bırakmanın en iyi yol olduğuna katılıyorum.

Ancak, kendinizi css'nizi yeniden yazma zahmetinden kurtarmak için, herhangi bir :hoveröğeyi @supports not (-webkit-overflow-scrolling: touch) {}

.hover, .hover-iOS {
  display:inline-block;
  font-family:arial;
  background:red;
  color:white;
  padding:5px;
}
.hover:hover {
  cursor:pointer;
  background:green;
}

.hover-iOS {
  background:grey;
}

@supports not (-webkit-overflow-scrolling: touch) {
  .hover-iOS:hover {
    cursor:pointer;
    background:blue;
  }

}
<input type="text" class="hover" placeholder="Hover over me" />

<input type="text" class="hover-iOS" placeholder="Hover over me (iOS)" />


0

:hoverİOS Safari'de olayları devre dışı bırakmanın yaygın kullanım durumu olanlar için en basit yol, :hoveretkinlikleriniz için kaçınmakta olduğunuz cihazların ekran genişliğinin üzerinde kalan minimum genişlikte bir medya sorgusu kullanmaktır. Misal:

@media only screen and (min-width: 1024px) {
  .my-div:hover { // will only work on devices larger than iOS touch-enabled devices. Will still work on touch-enabled PCs etc.
    background-color: red;
  }
}

-6

Sadece ekran boyutuna bakın ...

@media (min-width: 550px) {
    .menu ul li:hover > ul {
    display: block;
}
}

-12

yerleştirmek isteyeceğiniz kod burada

// a function to parse the user agent string; useful for 
// detecting lots of browsers, not just the iPad.
function checkUserAgent(vs) {
    var pattern = new RegExp(vs, 'i');
    return !!pattern.test(navigator.userAgent);
}
if ( checkUserAgent('iPad') ) {
    // iPad specific stuff here
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.