Bagaimana cara mensimulasikan hover dengan sentuhan pada browser yang diaktifkan?

120

Dengan beberapa HTML seperti ini:

<p>Some Text</p>

Lalu beberapa CSS seperti ini:

p {
  color:black;
}

p:hover {
  color:red;
}

Bagaimana cara mengizinkan sentuhan lama pada perangkat yang mendukung sentuhan untuk mereplikasi hover? Saya dapat mengubah markup / menggunakan JS dll, tetapi tidak dapat memikirkan cara mudah untuk melakukan ini.

Bradshaw kaya
sumber
Saya secara khusus memikirkan iPhone OS - ini adalah demo animasi CSS yang bagi banyak orang mudah menggunakan hover daripada klik untuk memulai.
Rich Bradshaw

Jawaban:

172

Oke, saya sudah berhasil! Ini melibatkan sedikit mengubah CSS dan menambahkan beberapa JS.

Menggunakan jQuery untuk mempermudah:

$(document).ready(function() {
    $('.hover').on('touchstart touchend', function(e) {
        e.preventDefault();
        $(this).toggleClass('hover_effect');
    });
});

Dalam bahasa Inggris: saat Anda memulai atau mengakhiri sentuhan, aktifkan hover_effectatau nonaktifkan kelas .

Kemudian, di HTML Anda, tambahkan hover kelas ke apa pun yang Anda ingin ini bekerja dengannya. Di CSS Anda, ganti contoh apa pun dari:

element:hover {
    rule:properties;
}

dengan

element:hover, element.hover_effect {
    rule:properties;
}

Dan hanya untuk kegunaan tambahan, tambahkan ini ke CSS Anda juga:

.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;        
}

Untuk menghentikan browser yang meminta Anda untuk menyalin / menyimpan / memilih gambar atau apapun.

Mudah!

Bradshaw kaya
sumber
Ini bagus. Saya membagi fungsi domready karena toggleakan mengacaukan jika pengguna menyentuh satu elemen dan menyeret ke elemen lain (misalnya jika mereka menyentuh item yang salah dan mencoba membatalkan sentuhan)
Jacksonkr
Saya menghapus touchenddan preventDefault()di situs web saya dan berfungsi dengan baik tetapi sekarang menu tidak ditutup secara otomatis oleh tap di luar target.
Даниил Пронин
Saya juga membutuhkan beberapa saran tentang cara menutup menu seperti itu ketika pengguna menyentuh di tempat lain atau mulai menggulir. Saya kira mungkin ada touchstartpendengar lain di tubuh (atau serupa) tetapi saya bertanya-tanya apakah ada cara yang lebih baik. Terima kasih!
Darryl Young
2
Apakah ada cara untuk mengabaikan gerakan gulir? Ini melakukan apa yang saya butuhkan tetapi sekarang saya tidak dapat menggulir ke atas dan ke bawah konten yang memiliki efek ini.
juga
1
Saya menghapus preventDefault karena saya ingin pengguliran tersedia tetapi terima kasih atas tip tentang touchstart dan touchend! Tuhan mengirimkan ini adalah satu-satunya jawaban yang dapat diandalkan bekerja di semua browser.
Petraeus
54

Yang perlu Anda lakukan hanyalah mengikat touchstart pada orang tua. Sesuatu seperti ini akan berhasil:

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

Anda tidak perlu melakukan apa pun dalam fungsi tersebut, biarkan kosong. Ini akan cukup untuk membuat hover saat disentuh, sehingga sentuhan berperilaku lebih seperti: hover dan kurang seperti: aktif. Keajaiban iOS.

Razvan Cercelaru
sumber
2
Apakah solusi ini memungkinkan tautan dijalankan pada ketukan kedua?
samuelkobe
1
Tidak, itu memicu klik pada sentuhan pertama. Saya baru saja mengujinya.
Jack
Solusi luar biasa! Cepat dan mudah.
Hunter Turner
41

Coba ini:

<script>
document.addEventListener("touchstart", function(){}, true);
</script>

Dan di CSS Anda:

element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}

Dengan kode ini, Anda tidak memerlukan kelas .hover ekstra!

Anselmus
sumber
1
ini bekerja untuk saya .. beberapa hal lain yang mungkin membantu ini lebih banyak daripada menambahkan javascript, lakukan ini: <body ontouchstart = ""> lalu tambahkan timer kecil di css: active event: tr: active {background-color : # 118aab; transisi: semua .2s linier; -webkit-tap-sorot-warna: rgba (0,0,0,0); -webkit-user-select: none; -webkit-touch-callout: none}
Kozy
Bekerja untuk saya. Terima kasih ... Satu-satunya hal - agak lambat ... Maksud saya - setelah Anda menekan, tidak dimuat secara instan.
Roman Losev
Gunakan fastclick.js untuk menghapus lag
Anselm
25

Untuk menjawab pertanyaan utama Anda: “Bagaimana cara menyimulasikan gerakan kursor dengan sentuhan pada browser yang diaktifkan?”

Cukup izinkan 'mengklik' elemen (dengan mengetuk layar), lalu picu hoveracara menggunakan JavaScript.

var p = document.getElementsByTagName('p')[0];
p.onclick = function() {
 // Trigger the `hover` event on the paragraph
 p.onhover.call(p);
};

Ini seharusnya berfungsi, selama ada hoveracara di perangkat Anda (meskipun biasanya tidak digunakan).

Pembaruan: Saya baru saja menguji teknik ini di iPhone saya dan tampaknya berfungsi dengan baik. Coba di sini: http://jsfiddle.net/mathias/YS7ft/show/light/

Jika Anda ingin menggunakan 'sentuhan panjang' untuk memicu hover, Anda dapat menggunakan cuplikan kode di atas sebagai titik awal dan bersenang-senang dengan timer dan lainnya;)

Mathias Bynens
sumber
Saya tidak tahu tentang bit onhover.call (p), itu cukup keren. Tidak ada off hover meskipun ...
Rich Bradshaw
Sudahkah Anda menguji ini dengan banyak elemen dan sentuhan panjang? Artinya pengguna menggerakkan jarinya di sekitar layar, dan menampilkan gaya hover untuk setiap elemen?
Marcus
Sepertinya jika Anda sudah menggunakan jQuery, Anda mungkin bisa memanggil event hover dengan jQuery itu sendiri, misalnya: jQuery.hover (); Tidak yakin api mendukungnya.
Kzqai
Ups, itu adalah komentar yang lebih cocok untuk posting di atas yang benar-benar menggunakan jQuery, maaf.
Kzqai
Apakah Anda perlu memiliki skrip khusus atau memanggil fungsi tersebut? Ini berfungsi untuk saya tetapi hanya pada satu halaman dan saya tidak tahu apa perbedaannya.
Richard Young
13

Solusi Lebih Lanjut

Pertama saya menggunakan pendekatan Rich Bradshaw , tetapi kemudian masalah mulai muncul. Dengan melakukan e.preventDefault () pada 'touchstart' acara , halaman tidak lagi menggulung dan, tekan lama tidak dapat mengaktifkan menu opsi atau zoom klik ganda tidak dapat menyelesaikan eksekusi.

Solusinya bisa menemukan acara mana yang dipanggil dan hanya e.preventDefault () di yang kemudian, 'touchend' . Karena scroll 'touchmove' muncul sebelum 'touchend', ia tetap seperti secara default, dan 'klik' juga dicegah karena muncul kata penutup dalam rangkaian peristiwa yang diterapkan ke seluler, seperti:

// Binding to the '.static_parent' ensuring dynamic ajaxified content
$('.static_parent').on('touchstart touchend', '.link', function (e) {

    // If event is 'touchend' then...
    if (e.type == 'touchend') {
        // Ensuring we event prevent default in all major browsers
        e.preventDefault ? e.preventDefault() : e.returnValue = false;
    }

    // Add class responsible for :hover effect
    $(this).toggleClass('hover_effect');
});

Tapi kemudian, ketika menu opsi muncul, itu tidak lagi mengaktifkan 'sentuhan' yang bertanggung jawab untuk mematikan kelas, dan lain kali perilaku hover akan sebaliknya, benar-benar bercampur.

Sebuah solusi kemudian akan, sekali lagi, secara kondisional mencari tahu di acara mana kita berada, atau hanya melakukan yang terpisah, dan menggunakan addClass () dan removeClass () masing-masing pada 'touchstart' dan 'touchend' , memastikan itu selalu dimulai dan diakhiri dengan masing-masing menambah dan menghapus alih-alih memutuskannya secara bersyarat. Untuk menyelesaikannya, kami juga akan mengikat callback penghapusan ke jenis peristiwa 'focusout' , tetap bertanggung jawab untuk menghapus kelas hover link apa pun yang mungkin tetap aktif dan tidak pernah dikunjungi kembali, seperti:

$('.static_parent').on('touchstart', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('touchend focusout', '.link', function (e) {
    // Think double click zoom still fails here
    e.preventDefault ? e.preventDefault() : e.returnValue = false;
    $(this).removeClass('hover_effect');
});

Perhatian: Beberapa bug masih terjadi di dua solusi sebelumnya dan, juga berpikir (belum diuji), zoom klik dua kali masih gagal juga.

Rapi dan Semoga Solusi Javascript Bebas Bug (bukan :))

Sekarang , untuk yang kedua, lebih bersih, rapi dan responsif, lakukan pendekatan hanya menggunakan javascript (tidak ada campuran antara kelas .hover dan pseudo: hover) dan dari mana Anda dapat memanggil langsung perilaku ajax Anda pada acara 'klik' universal (seluler dan desktop) , Saya telah menemukan pertanyaan yang dijawab dengan cukup baik yang akhirnya saya mengerti bagaimana saya dapat mencampur peristiwa sentuh dan mouse bersama-sama tanpa beberapa peristiwa panggilan balik pasti mengubah satu sama lain di atas rantai peristiwa. Begini caranya:

$('.static_parent').on('touchstart mouseenter', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('mouseleave touchmove click', '.link', function (e) {
    $(this).removeClass('hover_effect');

    // As it's the chain's last event we only prevent it from making HTTP request
    if (e.type == 'click') {
        e.preventDefault ? e.preventDefault() : e.returnValue = false;

        // Ajax behavior here!
    }
});
Alexandre Rosário
sumber
3

hoverEfek mouse tidak dapat diterapkan di perangkat sentuh. Ketika saya muncul dengan situasi yang sama di safari iossaya dulu:active di css untuk membuat efek.

yaitu.

p:active {
  color:red;
}

Dalam kasus saya ini bekerja. Mungkin ini juga kasus yang dapat digunakan tanpa menggunakan javascript. Coba saja.

sijo vijayan
sumber
2

Tambahkan kode ini dan kemudian setel kelas "tapHover" ke elemen yang Anda ingin gunakan dengan cara ini. Pertama kali Anda menge-tap elemen, Anda akan mendapatkan pseudoclass ": hover" dan class "tapped". Acara klik akan dicegah. Kedua kalinya Anda mengetuk elemen yang sama - peristiwa klik akan diaktifkan.

// Activate only in devices with touch screen
if('ontouchstart' in window)
{
    // this will make touch event add hover pseudoclass
    document.addEventListener('touchstart', function(e) {}, true);

    // modify click event
    document.addEventListener('click', function(e) {
        // get .tapHover element under cursor
        var el = jQuery(e.target).hasClass('tapHover')
            ? jQuery(e.target)
            : jQuery(e.target).closest('.tapHover');

        if(!el.length)
            return;

        // remove tapped class from old ones
        jQuery('.tapHover.tapped').each(function() {
            if(this != el.get(0))
                jQuery(this).removeClass('tapped');
        });

        if(!el.hasClass('tapped'))
        {
            // this is the first tap
            el.addClass('tapped');
            e.preventDefault();
            return false;
        }
        else
        {
            // second tap
            return true;
        }
    }, true);
}
.box {
	float:		left;
	
	display:	inline-block;
	margin:		50px 0 0 50px;
	width:		100px;
	height:		100px;
	overflow:	hidden;
	
	font-size:	20px;
	
	border:		solid 1px black;
}
.box.tapHover {
	background:	yellow;
}
.box.tapped {
	border:		solid 3px red;
}
.box:hover {
	background:	red;
}
<div class="box" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>

100k
sumber
1

Tanpa perangkat (atau lebih tepatnya browser) JS khusus, saya cukup yakin Anda kurang beruntung.

Sunting: pikir Anda ingin menghindari itu sampai saya membaca ulang pertanyaan Anda. Dalam hal Mobile Safari, Anda dapat mendaftar untuk mendapatkan semua acara sentuh yang serupa dengan apa yang dapat Anda lakukan dengan UIView-s asli. Tidak dapat menemukan dokumentasinya sekarang, akan mencoba.

Joonas Trussmann
sumber
1

Salah satu cara untuk melakukannya adalah dengan melakukan efek hover saat sentuhan dimulai, lalu menghilangkan efek hover saat sentuhan bergerak atau berakhir.

Inilah yang dikatakan Apple tentang penanganan sentuh secara umum, karena Anda menyebut iPhone.

ditarik ke depan
sumber
Apakah konten tautan masih relevan sekarang?
Flavien Volken
1

Selera pribadi saya adalah menghubungkan :hovergaya dengan :focusnegara, seperti:

p {
    color: red;
}

p:hover, p:focus {
    color: blue;
}

Kemudian dengan HTML berikut:

<p id="some-p-tag" tabindex="-1">WOOOO</p>

Dan JavaScript berikut:

$("#some-p-tag").on("touchstart", function(e){
    e.preventDefault();
    var $elem = $(this);

    if($elem.is(":focus")) {
        //this can be registered as a "click" on a mobile device, as it's a double tap
        $elem.blur()
    }
    else {
        $elem.focus();
    }
});
pimbrouwers
sumber
1

Dipecahkan 2019 - Arahkan Saat Menyentuh

Sekarang tampaknya lebih baik untuk menghindari penggunaan hover sama sekali dengan ios atau sentuhan secara umum. Kode di bawah ini menerapkan css Anda selama sentuhan dipertahankan, dan tanpa flyout ios lainnya. Melakukan hal ini;

  1. Jquery add: $ ("p"). On ("touchstart", function (e) {$ (this) .focus (); e.preventDefault ();});

  2. CSS: ganti p: hover dengan p: focus, dan tambahkan p: active

Pilihan;

  • ganti selektor jquery p dengan kelas apapun dll

  • agar efek tetap ada, pertahankan p: hover juga, dan tambahkan body {cursor: ponter;} jadi ketukan di mana saja akan mengakhirinya

  • coba peristiwa klik & gerakan mouse serta touchstart dalam kode yang sama (tetapi tidak diuji)

  • hapus e.preventDefault (); untuk memungkinkan pengguna menggunakan ios flyout, misalnya menyalin

Catatan

  • hanya diuji untuk elemen teks, ios mungkin memperlakukan input dll secara berbeda

  • hanya diuji di iphone XR ios 12.1.12, dan ipad 3 ios 9.3.5, menggunakan Safari atau Chrome.

sayang
sumber
0

Campuran Javascript dan jQuery asli:

var gFireEvent = function (oElem,sEvent) 
{
 try {
 if( typeof sEvent == 'string' && o.isDOM( oElem ))
 {
  var b = !!(document.createEvent),
     evt = b?document.createEvent("HTMLEvents"):document.createEventObject();
  if( b )    
  {  evt.initEvent(sEvent, true, true ); 
    return !oElem.dispatchEvent(evt);
  }
  return oElem.fireEvent('on'+sEvent,evt);
 }
 } catch(e) {}
 return false;
};


// Next you can do is (bIsMob etc you have to determine yourself):

   if( <<< bIsMob || bIsTab || bisTouch >>> )
   {
     $(document).on('mousedown', function(e)
     {
       gFireEvent(e.target,'mouseover' );
     }).on('mouseup', function(e)
     {
       gFireEvent(e.target,'mouseout' );
     });
   }
Codebeat
sumber
1
maaf terlalu berlebihan tapi jquery adalah javacript
matpol
2
@ matpol: jQuery adalah javascript tetapi javascript bukan jQuery. Khusus buat kamu saya tambahkan kata 'pure', pure javascript. Puas pak?
Codebeat
Anda tidak dapat menggunakan jquery tanpa menggunakan javascript 'murni'. Saya hanya menjelaskan karena beberapa orang yang sering SO tidak mengetahui hal ini.
matpol
5
Campuran Javascript dan jQuery asli, Puas?
Codebeat
0

Solusi termudah yang saya temukan: Saya memiliki beberapa tag <span> dengan: hover aturan css di dalamnya. Saya beralih ke <a href = "javascript: void (0)"> dan voilà. Gaya hover di iOS mulai berfungsi.

Becario Senior
sumber
0

Gunakan dapat menggunakan CSS juga, menambahkan fokus dan aktif (untuk IE7 dan di bawah) ke tautan tersembunyi. Contoh menu ul di dalam div dengan menu kelas:

.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}

Ini terlambat dan belum teruji, harus bekerja ;-)

Mark Groen
sumber