Apakah mungkin untuk mengabaikan paksa pseudoclass: hover untuk pengguna iPhone / iPad?

94

Saya memiliki beberapa menu css di situs saya yang berkembang dengan :hover(tanpa js)

Ini berfungsi dengan cara semi-rusak di iDevices, misalnya ketukan akan mengaktifkan :hoveraturan dan memperluas menu, tetapi kemudian mengetuk di tempat lain tidak menghapus file :hover. Juga jika ada tautan di dalam elemen yang :hover'ed, Anda harus mengetuk dua kali untuk mengaktifkan tautan (ketuk pemicu pertama :hover, tautan pemicu ketuk kedua).

Saya dapat membuat semuanya bekerja dengan baik di iphone dengan mengikat touchstartacara tersebut.

Masalahnya adalah terkadang safari seluler masih memilih untuk memicu :hoveraturan dari css daripadatouchstart acara saya !

Saya tahu ini masalahnya karena ketika saya menonaktifkan semua :hoveraturan secara manual di css, safari seluler berfungsi dengan baik (tetapi browser biasa jelas tidak lagi).

Adakah cara untuk "membatalkan" :hoveraturan secara dinamis untuk elemen tertentu saat pengguna menggunakan safari seluler?

Lihat dan bandingkan perilaku iOS di sini: http://jsfiddle.net/74s35/3/ Catatan: hanya beberapa properti css yang memicu perilaku dua-klik, misalnya display: none; tapi bukan background: merah; atau dekorasi teks: garis bawah;

Christopher Camps
sumber
7
TOLONG JANGAN nonaktifkan hovering hanya karena adanya peristiwa 'sentuh'. Ini akan berdampak buruk bagi pengguna laptop yang memiliki perangkat input sentuh dan mouse. Lihat jawaban saya untuk lebih jelasnya
Simon_Weaver

Jawaban:

77

Saya menemukan bahwa ": hover" tidak dapat diprediksi di iPhone / iPad Safari. Terkadang mengetuk elemen membuat elemen itu ": hover", sementara terkadang elemen itu melayang ke elemen lain.

Untuk saat ini, saya hanya memiliki kelas "tanpa sentuhan" di tubuh.

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

Dan memiliki semua aturan CSS dengan ": hover" di bawah ".no-touch":

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

Di suatu tempat di halaman, saya memiliki javascript untuk menghapus kelas no-touch dari body.

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

Ini tidak terlihat sempurna, tapi tetap berhasil.

Morgan Cheng
sumber
5
Ini satu-satunya cara untuk melakukannya. Yang mengganggu saya adalah hal itu mencemari situs "normal" dengan hal-hal yang tidak semestinya dan tidak relevan. Baiklah. Terima kasih.
Kamp Christopher
Anda juga dapat menggunakan kueri media dengan fallback untuk IE
Lime
2
@Shackrock: Menurut saya pendekatan "satu ketukan untuk mengarahkan kursor dan dua untuk mengeklik" adalah solusi yang baik. Karena sebenarnya tidak ada hover yang sebenarnya pada perangkat sentuh (sampai mereka hadir dengan layar yang merasakan jari Anda melayang di atasnya), saya pikir lebih baik tidak mensimulasikan hover sama sekali. Untuk efek, seperti yang umum pada tombol dan tautan, lewati saja efeknya. Untuk menu yang meluas saat melayang, buat menu diperluas saat ketuk / klik. 2c saya.
Adrian Schmidt
18
Saya baru-baru ini menemukan masalah dalam pendekatan semacam ini karena sistem Windows 8 baru yang menampilkan input sentuh dan mouse
Tom
4
+1 untuk komentar Tom - memeriksa ontouchstart akan mengembalikan true pada laptop berkemampuan sentuh, bahkan ketika dicolokkan ke monitor eksternal (di mana situs yang ramah mouse dengan status hover lebih diinginkan).
gregdev
45

:hoverbukan masalahnya di sini. Safari untuk iOS mengikuti aturan yang sangat aneh. Ini menyala mouseoverdan mousemovepertama; jika ada yang berubah selama acara ini, 'klik' dan acara terkait jangan diaktifkan:

Diagram acara sentuh di iOS

mouseenterdan mouseleavetampaknya disertakan, meskipun tidak ditentukan dalam bagan.

Jika Anda mengubah apa pun sebagai akibat dari peristiwa ini, peristiwa klik tidak akan diaktifkan. Itu termasuk sesuatu yang lebih tinggi di pohon DOM. Misalnya, ini akan mencegah satu klik berfungsi di situs web Anda dengan jQuery:

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

Edit: Untuk klarifikasi, hoveracara jQuery termasuk mouseenterdan mouseleave. Keduanya akan mencegah clickjika konten diubah.

Zenexer
sumber
5
tentu saja: hover masalahnya :-) atau lebih tepatnya implementasi buggy Safari. Ini adalah latar belakang yang menarik tentang masalah ini, tetapi Apple adalah satu-satunya pihak yang dapat memperbaiki perilaku mengerikan ini. baik itu perlu 'menampilkan' ketika sesuatu di luar elemen diklik, atau tidak pernah 'mengarahkan' di tempat pertama. perilaku saat ini pada dasarnya merusak situs web apa pun yang menggunakan: arahkan kursor ke mouse
Simon_Weaver
ini benar-benar membantu saya menyadari bahwa hoverpawang clicklelucon mencegah pawang terpisah dipukul - sungguh lelucon!
Simon_Weaver
1
Jawaban yang brilian, dan penjelasan terbaik dari masalah yang saya temui. Bukan hanya kursor CSS yang menyebabkan masalah "klik dua kali", tetapi secara harfiah semua modifikasi DOM setelah kejadian mouseover / mouseenter et al.
Oliver Joseph Ash
Berikut adalah contoh yang menunjukkan peristiwa klik tidak mouseenter aktif
Oliver Joseph Ash
@Oliver Joseph Ash Right, maka contoh JS di jawabannya. ;)
Zenexer
18

Perpustakaan deteksi fitur browser Modernizer menyertakan pemeriksaan untuk peristiwa sentuh.

Perilaku defaultnya adalah menerapkan kelas ke elemen html Anda untuk setiap fitur yang terdeteksi. Anda kemudian dapat menggunakan kelas-kelas ini untuk mengatur gaya dokumen Anda.

Jika acara sentuh tidak diaktifkan, Modernizr dapat menambahkan kelas no-touch:

<html class="no-touch">

Dan kemudian lingkup gaya hover Anda dengan kelas ini:

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

Anda dapat mengunduh build Modernizr khusus untuk menyertakan deteksi fitur sesedikit atau sebanyak yang Anda butuhkan.

Berikut contoh beberapa kelas yang dapat diterapkan:

<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">
Beau Smith
sumber
Ketahuilah bahwa pada versi terbaru Chrome di desktop yang menurut laporan Modernizr "menyentuh". Ini tampaknya diperbaiki di versi 3 dengan acara sentuh.
Craig Jacobs
18

Beberapa perangkat (seperti yang dikatakan orang lain) memiliki peristiwa sentuh dan mouse. Microsoft Surface misalnya memiliki layar sentuh, trackpad, DAN stylus yang benar-benar memunculkan peristiwa hover ketika di-hover di atas layar.

Solusi apa pun yang menonaktifkan :hoverberdasarkan adanya peristiwa 'sentuh' juga akan memengaruhi pengguna Surface (dan banyak perangkat serupa lainnya). Banyak laptop baru yang disentuh dan akan merespons peristiwa sentuh - jadi menonaktifkan hovering adalah praktik yang sangat buruk.

Ini adalah bug di Safari, sama sekali tidak ada pembenaran untuk perilaku buruk ini. Saya menolak untuk menyabotase browser non iOS karena bug di Safari iOS yang tampaknya telah ada selama bertahun-tahun. Saya sangat berharap mereka memperbaiki ini untuk iOS8 minggu depan tetapi sementara itu ....

Solusi saya :

Beberapa telah menyarankan untuk menggunakan Modernizr, baik Modernizr memungkinkan Anda membuat pengujian Anda sendiri. Apa yang pada dasarnya saya lakukan di sini adalah 'mengabstraksi' ide tentang browser yang mendukung :hoverpengujian Modernizr yang dapat saya gunakan di seluruh kode saya tanpa hardcode if (iOS)seluruhnya.

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

Kemudian css menjadi seperti ini

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

Hanya di iOS pengujian ini akan gagal dan menonaktifkan rollover.

Bagian terbaik dari abstraksi tersebut adalah jika saya menemukannya rusak pada android tertentu atau jika diperbaiki di iOS9 maka saya dapat memodifikasi tesnya.

Simon_Weaver
sumber
Solusi ini buruk dan terbaik di luar sana. Ini hanya rusak jika browser yang bermasalah dengan hover memiliki sentuhan dan klik, tetapi untuk browser hanya-sentuh di ipad / iphone ini tidak terjadi. Saran saya adalah menerapkan ini hanya sebagai perbaikan pengoptimalan (untuk menghapus hover berkedip ketika sudah menggunakan fastclick.js) dan pastikan semuanya juga berfungsi tanpa itu.
Gersom
Terima kasih. Saya setuju. Penasaran untuk melihat apa yang dilakukan iOS 9 untuk masalah ini - jika ada.
Simon_Weaver
Saya pergi ke arah sebaliknya:html:not(.no-hover) .category:hover { ...
Chris Marisic
+1 untuk "Safari tidak 'mengumumkan' kepada dunia bahwa ia berperilaku buruk dengan: hover" Masalah ini membuat iOS jauh lebih buruk daripada versi IE mana pun menurut pendapat saya ...
Spencer O'Reilly
16

Menambahkan perpustakaan FastClick ke halaman Anda akan menyebabkan semua ketukan di perangkat seluler diubah menjadi peristiwa klik (di mana pun pengguna mengklik), jadi itu juga harus memperbaiki masalah hover di perangkat seluler. Saya mengedit biola Anda sebagai contoh: http://jsfiddle.net/FvACN/8/ .

Cukup sertakan lib fastclick.min.js di halaman Anda, dan aktifkan melalui:

FastClick.attach(document.body);

Sebagai keuntungan tambahan, ini juga akan menghilangkan penundaan 300ms onClick yang mengganggu yang diderita perangkat seluler.


Ada beberapa konsekuensi kecil untuk menggunakan FastClick yang mungkin menjadi masalah atau tidak untuk situs Anda:

  1. Jika Anda mengetuk suatu tempat pada halaman, menggulir ke atas, menggulir ke bawah, dan kemudian melepaskan jari Anda pada posisi yang sama persis dengan yang Anda letakkan pada awalnya, FastClick akan menafsirkannya sebagai "klik", meskipun sebenarnya tidak. Setidaknya begitulah cara kerjanya di versi FastClick yang saya gunakan saat ini (1.0.0). Seseorang mungkin telah memperbaiki masalah ini sejak versi itu.
  2. FastClick menghilangkan kemampuan seseorang untuk "mengklik dua kali".
Troy
sumber
1
Maukah Anda berbagi contoh konkret lain tentang bagaimana saya dapat melakukan ini untuk situs web saya. Saya tidak tahu apa-apa tentang javascript jadi saya sedikit bingung tentang cara kerjanya. Saya memiliki semua tautan di situs saya yang biasanya diarahkan oleh pengguna sebelum mengklik, tetapi untuk ipad / seluler saya ingin membuatnya sehingga mereka tidak perlu mengklik dua kali.
Andy
@Andy - Tidak jelas apa yang Anda butuhkan dan apa yang Anda lewatkan ... Apa yang telah Anda coba, sejauh ini, dan kesalahan apa yang Anda lihat, jika ada? Mungkin akan lebih baik untuk membuat pertanyaan Stackoverflow baru, jika Anda belum melakukannya, dengan contoh dari apa yang Anda coba lakukan (?) Atau coba klarifikasi apa di atas, contoh jsfiddle yang tidak Anda lakukan. tidak mengerti.
Troy
dapatkah ini digunakan dalam aplikasi satu halaman? Maksud saya saat konten DOM diperbarui setiap saat
Sebastien Lorber
Ya, saya menggunakannya dengan aplikasi satu halaman.
Troy
16

Solusi yang lebih baik, tanpa JS, kelas css, dan pemeriksaan viewport: Anda dapat menggunakan Fitur Media Interaksi (Media Queries Level 4)

Seperti ini:

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

iOS Safari mendukungnya

Lebih lanjut tentang: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/

Estevão Lucas
sumber
Tidak didukung oleh Firefox (pada saat komentar ini tentu saja)
Frank
Ini sekarang didukung oleh Firefox, juga (FF 64+, dirilis Des 2018).
wunch
4

Pada dasarnya ada tiga skenario:

  1. Pengguna hanya memiliki perangkat mouse / penunjuk dan dapat mengaktifkan:hover
  2. Pengguna hanya memiliki layar sentuh, dan tidak dapat mengaktifkan :hoverelemen
  3. Pengguna memiliki kedua layar sentuh dan perangkat penunjuk

Jawaban yang diterima awalnya karya-karya besar jika hanya dua skenario pertama yang mungkin, di mana pengguna memiliki baik pointer atau touchscreen. Hal ini biasa terjadi ketika OP mengajukan pertanyaan 4 tahun lalu. Beberapa pengguna telah menunjukkan bahwa perangkat Windows 8 dan Surface membuat skenario ketiga lebih mungkin terjadi.

Solusi iOS untuk masalah tidak dapat mengarahkan pada perangkat layar sentuh (seperti yang dijelaskan oleh @Zenexer) cerdas, tetapi dapat menyebabkan kode langsung menjadi tidak benar (seperti dicatat oleh OP). Menonaktifkan hover hanya untuk perangkat layar sentuh berarti Anda masih perlu membuat kode alternatif ramah layar sentuh. Mendeteksi saat pengguna memiliki penunjuk dan layar sentuh semakin mengaburkan air (seperti dijelaskan oleh @Simon_Weaver).

Pada titik ini, solusi teraman adalah menghindari penggunaan :hoversebagai satu-satunya cara pengguna dapat berinteraksi dengan situs web Anda. Efek arahkan kursor adalah cara yang baik untuk menunjukkan bahwa link atau tombol dapat ditindaklanjuti, tetapi pengguna tidak perlu mengarahkan kursor ke elemen untuk melakukan tindakan di situs Anda.

Memikirkan ulang fungsionalitas "arahkan kursor" dengan layar sentuh memiliki diskusi yang baik tentang pendekatan UX alternatif. Solusi yang diberikan oleh jawabannya di sana meliputi:

  • Mengganti menu hover dengan tindakan langsung (link selalu terlihat)
  • Mengganti menu on-hover dengan menu-tap
  • Memindahkan konten on-hover dalam jumlah besar ke halaman terpisah

Ke depannya, ini mungkin akan menjadi solusi terbaik untuk semua proyek baru. Jawaban yang diterima mungkin adalah solusi terbaik kedua, tetapi pastikan untuk memperhitungkan perangkat yang juga memiliki perangkat penunjuk. Berhati-hatilah untuk tidak menghilangkan fungsionalitas saat perangkat memiliki layar sentuh hanya untuk mengatasi :hoverperetasan iOS .

orang ketiga
sumber
1

Versi JQuery di .css Anda menggunakan .no-touch .my-element: hover untuk semua aturan hover Anda termasuk JQuery dan skrip berikut

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

Kemudian di tag tubuh tambahkan class = "no-touch" ontouchstart = "removeHoverState ()"

segera setelah ontouchstart mengaktifkan kelas untuk semua status hover dihapus

Greg
sumber
0

Alih-alih hanya memiliki efek hover saat sentuhan tidak tersedia, saya membuat sistem untuk menangani peristiwa sentuh dan itu telah memecahkan masalah bagi saya. Pertama, saya menetapkan objek untuk menguji peristiwa "tap" (setara dengan "klik").

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

Kemudian, di event handler saya, saya melakukan sesuatu seperti berikut:

$('#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.
            });
donat
sumber
0

Terima kasih @Morgan Cheng untuk jawabannya, namun saya sedikit memodifikasi fungsi JS untuk mendapatkan " touchstart " (kode diambil dari jawaban @Timothy Perez ), meskipun, Anda memerlukan jQuery 1.7+ untuk ini

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

Mengingat tanggapan yang diberikan oleh Zenexer, pola yang tidak memerlukan tag HTML tambahan adalah:

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

Metode ini mengaktifkan gerakan mouse terlebih dahulu, klik kedua.

sangatphatic
sumber
0

Saya setuju menonaktifkan hover untuk disentuh adalah cara yang tepat.

Namun, untuk menghindari masalah menulis ulang css Anda, cukup bungkus :hoveritem apa saja@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)" />

Jordan Young
sumber
0

Bagi mereka yang memiliki kasus penggunaan umum untuk menonaktifkan :hoveracara di Safari iOS, cara paling sederhana adalah menggunakan kueri media dengan lebar minimum untuk :hoveracara Anda yang tetap berada di atas lebar layar perangkat yang Anda hindari. Contoh:

@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;
  }
}
Brian Scramlin
sumber
-6

Lihat saja ukuran layarnya ....

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

inilah kode yang ingin Anda tempatkan

// 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
}
Luke
sumber