ปิดใช้งานเอฟเฟกต์โฮเวอร์บนเบราว์เซอร์มือถือ


113

ฉันกำลังเขียนเว็บไซต์ที่ตั้งใจจะใช้ทั้งจากเดสก์ท็อปและแท็บเล็ต เมื่อมีการเยี่ยมชมจากเดสก์ท็อปฉันต้องการให้พื้นที่ที่คลิกได้ของหน้าจอสว่างขึ้นพร้อมเอ:hoverฟเฟกต์ (สีพื้นหลังที่แตกต่างกัน ฯลฯ ) เมื่อใช้แท็บเล็ตไม่มีเมาส์ดังนั้นฉันจึงไม่ต้องการเอฟเฟกต์แบบโฮเวอร์ใด ๆ

ปัญหาคือเมื่อฉันแตะอะไรบางอย่างบนแท็บเล็ตเบราว์เซอร์จะมี "เคอร์เซอร์ของเมาส์ที่มองไม่เห็น" บางชนิดซึ่งย้ายไปยังตำแหน่งที่ฉันแตะแล้วปล่อยไว้ที่นั่นดังนั้นสิ่งที่ฉันเพิ่งแตะจะสว่างขึ้นพร้อมกับ เลื่อนเอฟเฟกต์จนกว่าฉันจะแตะอย่างอื่น

ฉันจะรับเอฟเฟกต์โฮเวอร์ได้อย่างไรเมื่อฉันใช้เมาส์ แต่กดปุ่มเหล่านี้เมื่อฉันใช้หน้าจอสัมผัส

ในกรณีที่มีคนคิดจะแนะนำฉันไม่ต้องการใช้การดมกลิ่นของตัวแทนผู้ใช้ อุปกรณ์เดียวกันอาจมีทั้งหน้าจอสัมผัสและเมาส์ (อาจจะไม่ธรรมดาในปัจจุบัน แต่มีอีกมากมายในอนาคต) ฉันไม่สนใจอุปกรณ์นี้ฉันสนใจวิธีการใช้งาน: เมาส์หรือหน้าจอสัมผัส

ฉันพยายามแล้ว hooking touchstart, touchmoveและtouchendเหตุการณ์ที่เกิดขึ้นและเรียกpreventDefault()ทั้งหมดของพวกเขาซึ่งจะปราบ "การเคอร์เซอร์ของเมาส์ที่มองไม่เห็น" บางส่วนของเวลา; แต่ถ้าฉันแตะอย่างรวดเร็วไปมาระหว่างสององค์ประกอบที่แตกต่างกันหลังจากแตะสองสามครั้งมันจะเริ่มขยับ "เคอร์เซอร์ของเมาส์" และทำให้เอฟเฟกต์โฮเวอร์สว่างขึ้น - มันเหมือนกับว่าฉันpreventDefaultไม่ได้รับเกียรติเสมอไป ฉันจะไม่เบื่อคุณด้วยรายละเอียดเว้นแต่จำเป็น - ฉันไม่แน่ใจด้วยซ้ำว่านั่นเป็นแนวทางที่ถูกต้อง ถ้าใครมีวิธีแก้ไขที่ง่ายกว่านี้ฉันหูแว่ว


แก้ไข:สิ่งนี้สามารถทำซ้ำได้ด้วย CSS มาตรฐานปลอม:hoverแต่นี่เป็นคำอธิบายสั้น ๆ สำหรับการอ้างอิง

<style>
  .box { border: 1px solid black; width: 150px; height: 150px; }
  .box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>

ถ้าคุณวางเมาส์เหนือช่องใดช่องหนึ่งก็จะได้พื้นหลังเป็นสีน้ำเงินซึ่งฉันต้องการ แต่ถ้าคุณแตะที่ช่องใดช่องหนึ่งก็จะได้พื้นหลังเป็นสีน้ำเงินซึ่งเป็นสิ่งที่ฉันพยายามป้องกัน

ฉันยังโพสต์ตัวอย่างที่นี่ซึ่งทำตามข้างต้นและเชื่อมโยงเหตุการณ์เมาส์ของ jQuery คุณสามารถใช้มันเพื่อดูว่าเหตุการณ์ประปายังจะไฟmouseenter, และmousemovemouseleave


7
@ เบลนเดอร์อ่านคำถามแล้วหรือยัง? ฉันได้อธิบายไปแล้วว่าเหตุใดการดมกลิ่นของตัวแทนผู้ใช้จึงเป็นทางเลือกที่ไม่ดี
Joe White

เฮ้โจคุณพบวิธีแก้ปัญหานี้หรือไม่?
Ismatjon

ฉันกำลังค้นหาคำถามประเภทนี้ดีใจที่ได้พบ!
agpt

ดูคำถามนี้ซึ่งเกี่ยวข้องกับการปิดใช้งานการวางเมาส์บนอุปกรณ์ที่เปิดใช้งานระบบสัมผัสไม่ใช่เฉพาะมือถือ: stackoverflow.com/questions/23885255/…
ใบมีด

คำตอบ:


83

ฉันเข้าใจจากคำถามของคุณที่ว่าการวางเมาส์ของคุณจะเปลี่ยนเนื้อหาในเพจของคุณ ในกรณีนี้คำแนะนำของฉันคือ:

  • เพิ่มโฉบผลกระทบต่อและtouchstartmouseenter
  • นำผลกระทบเลื่อนบนmouseleave, และtouchmoveclick

หรือคุณสามารถแก้ไขเพจของคุณที่ไม่มีการเปลี่ยนแปลงเนื้อหาได้

พื้นหลัง

ในการจำลองเมาส์เบราว์เซอร์เช่น Webkit mobile จะยิงเหตุการณ์ต่อไปนี้หากผู้ใช้แตะและปล่อยนิ้วบนหน้าจอสัมผัส (เช่น iPad) (ที่มา: Touch And Mouseบน html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. ความล่าช้า 300 มิลลิวินาทีโดยที่เบราว์เซอร์ตรวจสอบให้แน่ใจว่าเป็นการแตะเพียงครั้งเดียวไม่ใช่การแตะสองครั้ง
  5. mouseover
  6. mouseenter
    • หมายเหตุ : ถ้าmouseover, mouseenterหรือmousemoveเหตุการณ์การเปลี่ยนแปลงเนื้อหาของหน้าเหตุการณ์ต่อไปนี้จะไม่ยิง
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

ดูเหมือนจะเป็นไปไม่ได้ที่จะบอกให้เว็บเบราว์เซอร์ข้ามเหตุการณ์ของเมาส์

ที่แย่ไปกว่านั้นคือหากเหตุการณ์วางเมาส์เปลี่ยนเนื้อหาของหน้าเหตุการณ์การคลิกจะไม่เริ่มทำงานตามที่อธิบายไว้ในคู่มือเนื้อหาเว็บ Safari - การจัดการเหตุการณ์โดยเฉพาะรูปที่ 6.4 ในเหตุการณ์ด้วยนิ้วเดียว "การเปลี่ยนแปลงเนื้อหา" คืออะไรจะขึ้นอยู่กับเบราว์เซอร์และเวอร์ชัน ฉันพบว่าสำหรับ iOS 7.0 การเปลี่ยนสีพื้นหลังไม่ใช่การเปลี่ยนแปลงเนื้อหา (หรือไม่มีอีกต่อไป)

อธิบายวิธีแก้ปัญหา

สรุป:

  • เพิ่มโฉบผลกระทบต่อและtouchstartmouseenter
  • นำผลกระทบเลื่อนบนmouseleave, และtouchmoveclick

โปรดทราบว่าไม่มีการดำเนินการใดtouchendๆ !

สิ่งนี้ใช้ได้กับเหตุการณ์ของเมาส์อย่างชัดเจน: mouseenterและmouseleave(เวอร์ชันปรับปรุงเล็กน้อยmouseoverและmouseout) จะเริ่มทำงานและเพิ่มและลบโฮเวอร์

หากผู้ใช้เป็นclickลิงก์จริงผลการวางเมาส์จะถูกลบออกไปด้วย เพื่อให้แน่ใจว่าจะถูกลบออกหากผู้ใช้กดปุ่มย้อนกลับในเว็บเบราว์เซอร์

นอกจากนี้ยังใช้ได้กับเหตุการณ์การสัมผัส: เมื่อแตะเริ่มต้นเอฟเฟกต์โฮเวอร์จะถูกเพิ่ม มันคือ '' 'ไม่' '' ถูกลบออกเมื่อสัมผัส มันถูกเพิ่มอีกครั้งmouseenterและเนื่องจากสิ่งนี้ทำให้ไม่มีการเปลี่ยนแปลงเนื้อหา (ได้ถูกเพิ่มไปแล้ว) clickเหตุการณ์จึงเริ่มทำงานและลิงก์จะตามมาโดยไม่จำเป็นให้ผู้ใช้คลิกอีกครั้ง!

ความล่าช้า 300 มิลลิวินาทีที่เบราว์เซอร์มีระหว่างtouchstartเหตุการณ์และclickถูกนำไปใช้งานจริงเนื่องจากเอฟเฟกต์โฮเวอร์จะแสดงในช่วงเวลาสั้น ๆ นี้

หากผู้ใช้ตัดสินใจที่จะยกเลิกการคลิกการเลื่อนนิ้วจะทำได้เหมือนปกติ โดยปกติปัญหานี้เป็นปัญหาเนื่องจากไม่มีการmouseleaveยิงเหตุการณ์และเอฟเฟกต์โฮเวอร์ยังคงอยู่ touchmoveโชคดีที่นี้สามารถแก้ไขโดยการเอาผลโฉบบน

แค่นั้นแหละ!

โปรดทราบว่าเป็นไปได้ที่จะลบการหน่วงเวลา 300 มิลลิวินาทีตัวอย่างเช่นการใช้ไลบรารี FastClickแต่คำถามนี้อยู่นอกขอบเขตสำหรับคำถามนี้

โซลูชั่นทางเลือก

ฉันพบปัญหาต่อไปนี้กับทางเลือกต่อไปนี้:

  • การตรวจจับเบราว์เซอร์:มีแนวโน้มที่จะเกิดข้อผิดพลาดอย่างมาก สมมติว่าอุปกรณ์มีเมาส์หรือระบบสัมผัสในขณะที่การใช้ทั้งสองอย่างร่วมกันจะกลายเป็นเรื่องปกติมากขึ้นเรื่อย ๆ เมื่อการแสดงผลแบบสัมผัสมีสัญญาณรบกวน
  • การตรวจจับสื่อ CSS:โซลูชัน CSS เท่านั้นที่ฉันรู้จัก ยังคงมีแนวโน้มที่จะเกิดข้อผิดพลาดและยังคงถือว่าอุปกรณ์มีเมาส์หรือสัมผัสในขณะที่ทั้งสองอย่างเป็นไปได้
  • จำลองเหตุการณ์การคลิกในtouchend:สิ่งนี้จะไปตามลิงก์อย่างไม่ถูกต้องแม้ว่าผู้ใช้จะต้องการเลื่อนหรือซูมเท่านั้นโดยไม่ได้ตั้งใจที่จะคลิกลิงก์จริงๆ
  • ใช้ตัวแปรเพื่อระงับเหตุการณ์ของเมาส์:ตั้งค่าตัวแปรtouchendที่ใช้เป็น if-condition ในเหตุการณ์ต่อมาของเมาส์เพื่อป้องกันการเปลี่ยนแปลงสถานะ ณ เวลานั้น ตัวแปรจะถูกรีเซ็ตในเหตุการณ์คลิก ดูคำตอบของ Walter Roman ในหน้านี้ นี่เป็นทางออกที่ดีหากคุณไม่ต้องการให้มีการวางเมาส์บนอินเทอร์เฟซแบบสัมผัส น่าเสียดายที่วิธีนี้ใช้ไม่ได้หาก a touchendถูกยิงด้วยเหตุผลอื่นและไม่มีเหตุการณ์การคลิกเริ่มทำงาน (เช่นผู้ใช้เลื่อนหรือซูม) และต่อมาพยายามติดตามลิงก์ด้วยเมาส์ (เช่นบนอุปกรณ์ที่มีทั้งเมาส์และอินเทอร์เฟซแบบสัมผัส )

อ่านเพิ่มเติม

  • http://jsfiddle.net/macfreek/24Z5M/ ทดสอบวิธีแก้ปัญหาข้างต้นด้วยตัวคุณเองในแซนด์บ็อกซ์นี้
  • http://www.macfreek.nl/memory/Touch_and_mouse_with_hover_effects_in_a_web_browser คำตอบเดียวกันนี้พร้อมพื้นหลังอีกเล็กน้อย
  • https://www.html5rocks.com/en/mobile/touchandmouse/ บทความพื้นหลังที่ดีใน html5rocks.com เกี่ยวกับการสัมผัสและเมาส์โดยทั่วไป
  • https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html คู่มือเนื้อหาเว็บ Safari - การจัดการเหตุการณ์ ดูในรูปที่ 6.4 โดยเฉพาะซึ่งอธิบายว่าจะไม่มีการเริ่มเหตุการณ์ใด ๆ อีกหลังจากการเปลี่ยนแปลงเนื้อหาระหว่างเหตุการณ์mouseoverหรือmousemoveเหตุการณ์

1
คำตอบที่ดี ฉันใช้ซอของคุณเพื่อเริ่มสร้างโซลูชันของฉันเอง อย่างไรก็ตามบางครั้งจำเป็นต้องมีการสัมผัส (เมื่อ touchmove ไม่ทำงาน - เช่นเมื่อผู้ใช้ย้ายออกจากเอกสารเอง ... )
Agamemnus

คำตอบที่ดี แต่ในกรณีส่วนใหญ่ผมขอแนะนำให้ใช้touchend แทนของtouchstartในกรณีส่วนใหญ่ที่จะหลีกเลี่ยงการเรียกการกระทำทันทีเมื่อผู้ใช้พยายามที่จะรูดเลื่อนขึ้นหรือลงหน้า จะยังคงเกิดขึ้น แต่มีโอกาสน้อยที่จะเบี่ยงเบนความสนใจหรือสับสน (สมมติว่าเป็นสิ่งที่ไม่เป็นอันตรายเช่นการแสดงฉลากไม่ใช่สิ่งที่ผู้ใช้จำเป็นต้องรู้ว่าเกิดขึ้น)
user56reinstatemonica8

19

ฉันจะรับเอฟเฟกต์โฮเวอร์ได้อย่างไรเมื่อฉันใช้เมาส์ แต่กดปุ่มเหล่านี้เมื่อฉันใช้หน้าจอสัมผัส

อาจจะไม่ได้คิดถึงมันมากเท่ากับการระงับเอฟเฟกต์โฮเวอร์สำหรับหน้าจอสัมผัส แต่เป็นการเพิ่มเอฟเฟกต์โฮเวอร์สำหรับเหตุการณ์เมาส์?

หากคุณต้องการเก็บเอ:hoverฟเฟกต์ใน CSS ของคุณคุณสามารถระบุสไตล์ที่แตกต่างกันสำหรับสื่อต่างๆ:

@media screen { /* hover styles here */ } 

@media handheld { /* non-hover styles here */ }

ยกเว้นว่ามีอุปกรณ์มือถือจำนวนมากที่เพิกเฉยต่อสิ่งนี้และเพียงแค่ใช้กฎหน้าจอ โชคดีที่เบราว์เซอร์มือถือ / แท็บเล็ตรุ่นใหม่ ๆ จำนวนมากรองรับข้อความค้นหาของสื่อที่น่าสนใจ:

@media screen and (max-width:800px) { /* non-hover styles here */ }

ดังนั้นแม้ว่าส่วน "หน้าจอ" หรือ "มือถือ" จะถูกเพิกเฉย แต่ "ความกว้างสูงสุด" ก็จะช่วยคุณได้ คุณสามารถสันนิษฐานได้ว่าอะไรก็ตามที่มีหน้าจอเล็กกว่า 800 พิกเซลจะต้องเป็นแท็บเล็ตหรือโทรศัพท์และไม่ใช้เอฟเฟกต์การวางเมาส์ สำหรับผู้ใช้ที่หายากที่ใช้เมาส์บนอุปกรณ์ที่มีความละเอียดต่ำพวกเขาจะไม่เห็นเอฟเฟกต์โฮเวอร์ แต่ไซต์ของคุณจะไม่เป็นไร

อ่านเพิ่มเติมเกี่ยวกับแบบสอบถามสื่อ? มีบทความมากมายเกี่ยวกับออนไลน์นี้ - นี่คือหนึ่ง: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet

หากคุณเปลี่ยนเอฟเฟกต์โฮเวอร์ออกจาก CSS ของคุณและนำไปใช้กับ JavaScript คุณสามารถเชื่อมโยงกับเหตุการณ์ของเมาส์โดยเฉพาะและ / หรืออีกครั้งคุณสามารถตั้งสมมติฐานตามขนาดหน้าจอโดยมี "ปัญหา" ในกรณีที่เลวร้ายที่สุดคือ ผู้ใช้ที่ใช้เมาส์พลาดเอฟเฟกต์โฮเวอร์


ฉันต้องการเพิ่มเอฟเฟกต์โฮเวอร์สำหรับเหตุการณ์เมาส์เท่านั้น แต่เหตุการณ์การสัมผัสจะเลียนแบบเหตุการณ์ของเมาส์ หากฉันเชื่อมโยงเหตุการณ์การสัมผัสและการโทรpreventDefault()ซึ่งบางครั้งจะระงับเหตุการณ์ของเมาส์ แต่อย่างที่ฉันพูดในคำถามของฉันมันไม่น่าเชื่อถือ
Joe White

6
สำหรับคำถามเกี่ยวกับสื่อจะเกิดอะไรขึ้นเมื่อ Windows 8 ออกมาและพีซีมีทั้งหน้าจอสัมผัสและเมาส์ หากผู้ใช้เลื่อนเมาส์พวกเขาจะเห็นเคอร์เซอร์ของเมาส์และฉันต้องการเอฟเฟกต์โฮเวอร์ ถ้าพวกเขาแตะด้วยหน้าจอสัมผัสฉันไม่ต้องการเอฟเฟกต์โฮเวอร์ แต่ฉันไม่พบวิธีที่เชื่อถือได้ในการตรวจจับความแตกต่างระหว่างการสัมผัสและเมาส์
Joe White

บางทีนักพัฒนาเบราว์เซอร์อาจมีแรงจูงใจในการตรวจจับที่สอดคล้องกันมากขึ้นเมื่อพวกเขามีผู้ใช้จำนวนมากบนอุปกรณ์ที่มีการสัมผัสและเมาส์ แต่สำหรับตอนนี้? ฉันจะเดาตามขนาดหน้าจอ แต่มีคำแนะนำอื่น ๆ ในคำตอบอื่น ๆ ขออภัยฉันไม่สามารถช่วยเพิ่มเติมได้
nnnnnn

9

ฉันเขียน JS ต่อไปนี้สำหรับโปรเจ็กต์ล่าสุดซึ่งเป็นไซต์บนเดสก์ท็อป / มือถือ / แท็บเล็ตที่มีเอฟเฟกต์โฮเวอร์ที่ไม่ควรปรากฏเมื่อแตะ

mobileNoHoverStateโมดูลด้านล่างมีตัวแปรpreventMouseover(สมัยก่อนประกาศเป็นfalse) ที่ถูกตั้งค่าให้trueเมื่อผู้ใช้ไฟเหตุการณ์เมื่อองค์ประกอบtouchstart$target

preventMouseoverจากนั้นจะถูกตั้งค่ากลับเป็นfalseเมื่อใดก็ตามที่mouseoverเหตุการณ์เริ่มทำงานซึ่งจะช่วยให้ไซต์ทำงานได้ตามที่ตั้งใจไว้หากผู้ใช้ใช้ทั้งหน้าจอสัมผัสและเมาส์

เรารู้ว่าmouseoverจะถูกเรียกหลังจากเพราะเพื่อที่พวกเขาจะถูกประกาศภายในtouchstartinit

var mobileNoHoverState = function() {

    var hoverClass = 'hover',
        $target = $(".foo"), 
        preventMouseover = false;

    function forTouchstart() {
        preventMouseover = true;
    }

    function forMouseover() {
        if (preventMouseover === false) {
            $(this).addClass(hoverClass);
        } else {
            preventMouseover = false;
        }
    }

    function forMouseout() {
        $(this).removeClass(hoverClass);
    }

    function init() {
        $target.on({
            touchstart  : forTouchstart,
            mouseover   : forMouseover,
            mouseout    : forMouseout
        });                
    }

    return {
        init: init
    };
}();

จากนั้นโมดูลจะถูกสร้างอินสแตนซ์ต่อไปในบรรทัด:

mobileNoHoverState.init();

"PreventMouseover จะถูกตั้งค่ากลับเป็นจริงเมื่อใดก็ตามที่เหตุการณ์เมาส์โอเวอร์เริ่มทำงานซึ่งจะช่วยให้ไซต์ทำงานได้ตามที่ตั้งใจไว้หากผู้ใช้ใช้ทั้งหน้าจอสัมผัสและเมาส์" - รหัสของคุณไม่ได้ทำเช่นนั้น ฉันพลาดอะไรไปรึเปล่า?
Redtopia

@ Redtopia ขอบคุณสำหรับหัวขึ้น! ฉันได้อัปเดตคำตอบด้วยบิตของรหัสที่ทิ้งไว้
Walter Roman

คุณไม่จำเป็นต้องใช้เครื่องหมายอัฒภาคหลังจากการประกาศฟังก์ชัน
nacholibre

@nacholibre มีการนำการใช้เซมิโคลอนที่เหมาะสมมาใช้
Walter Roman

6

ฉันต้องการcssวิธีแก้ปัญหาที่แท้จริงสำหรับตัวเองเนื่องจากการโรยโซลูชันจาวาสคริปต์ที่มีน้ำหนักมากรอบ ๆ มุมมองทั้งหมดของฉันดูเหมือนเป็นตัวเลือกที่ไม่พึงประสงค์ ในที่สุดก็พบข้อความค้นหา@ media.hoverซึ่งสามารถตรวจจับ "ว่ากลไกการป้อนข้อมูลหลักอนุญาตให้ผู้ใช้วางเมาส์เหนือองค์ประกอบหรือไม่" วิธีนี้หลีกเลี่ยงอุปกรณ์สัมผัสที่การ "วางเมาส์" เป็นการกระทำที่เลียนแบบมากกว่าความสามารถโดยตรงของอุปกรณ์อินพุต

ตัวอย่างเช่นหากฉันมีลิงก์:

<a href="/" class="link">Home</a>

จากนั้นฉันสามารถจัดรูปแบบได้อย่างปลอดภัยเฉพาะ:hoverเมื่ออุปกรณ์รองรับอย่างง่ายดายด้วยสิ่งนี้css:

@media (hover: hover) {
  .link:hover { /* hover styles */ }
}

ในขณะที่เบราว์เซอร์สมัยใหม่ส่วนใหญ่รองรับการสืบค้นคุณลักษณะสื่อปฏิสัมพันธ์ แต่เบราว์เซอร์ยอดนิยมบางประเภทเช่น IE และ Firefoxไม่รองรับ ในกรณีของฉันมันใช้งานได้ดีเนื่องจากฉันตั้งใจให้รองรับ Chrome บนเดสก์ท็อปและ Chrome และ Safari บนมือถือเท่านั้น


ทางออกที่ดีที่ดูเหมือนจะใช้งานได้เมื่อคุณจำลองอุปกรณ์ใน Chrome devtools แต่ก็ยังใช้ไม่ได้กับ Chrome Android :-(
Sjeiti

ฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่สะดวกและถูกต้องที่สุด หวังว่าจะมีการเพิ่มมาตรฐาน W3C ในเร็ว ๆ นี้
GProst

5

วิธีแก้ปัญหาของฉันคือการเพิ่มคลาส css ที่ใช้งานอยู่ในแท็ก HTML และใช้ในจุดเริ่มต้นของตัวเลือก CSS ทั้งหมดด้วย: วางเมาส์และลบคลาสนั้นในเหตุการณ์ทัชสตาร์ตแรก

http://codepen.io/Bnaya/pen/EoJlb

JS:

(function () {
    'use strict';

    if (!('addEventListener' in window)) {
        return;
    }

    var htmlElement = document.querySelector('html');

    function touchStart () {
        document.querySelector('html').classList.remove('hover-active');

        htmlElement.removeEventListener('touchstart', touchStart);
    }

    htmlElement.addEventListener('touchstart', touchStart);
}());

HTML:

<html class="hover-active">

CSS:

.hover-active .mybutton:hover {
    box-shadow: 1px 1px 1px #000;
}

'ontouchstart' in windowแทนที่จะฟังเหตุการณ์สัมผัสคุณสามารถทดสอบ เช่นif ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Yuval A.

@YuvalA เหตุผลที่ฉันกำลังรอเหตุการณ์การสัมผัสเนื่องจากมีอุปกรณ์ที่มีตัวชี้และการรองรับการสัมผัสและของผู้ใช้กำลังใช้ตัวชี้ฉันไม่ต้องการลบโฮเวอร์ เป็นไปได้ที่ผู้ใช้จะใช้การสัมผัสแล้วชี้ แต่ฉันไม่มีอะไรให้ทำมากนัก
Bnaya

2

สิ่งที่ฉันได้ทำเพื่อแก้ปัญหาเดียวกันคือต้องมีการตรวจจับคุณลักษณะ (ฉันใช้รหัสนี้ ) โดยดูว่ามีการกำหนด onTouchMove ไว้หรือไม่และถ้าเป็นเช่นนั้นฉันจะเพิ่มคลาส css "touchMode" ให้กับร่างกายฉันจะเพิ่ม " desktopMode"

จากนั้นทุกครั้งที่เอฟเฟกต์สไตล์บางอย่างใช้กับอุปกรณ์สัมผัสเท่านั้นหรือเฉพาะกับเดสก์ท็อปกฎ css จะถูกนำหน้าด้วยคลาสที่เหมาะสม:

.desktopMode .someClass:hover{ color: red }
.touchMode .mainDiv { width: 100%; margin: 0; /*etc.*/ }

แก้ไข : แน่นอนว่ากลยุทธ์นี้จะเพิ่มอักขระพิเศษบางตัวให้กับ css ของคุณดังนั้นหากคุณกังวลเกี่ยวกับขนาด css คุณสามารถค้นหานิยามของ touchMode และ desktopMode แล้วใส่ลงในไฟล์ต่างๆเพื่อให้คุณสามารถให้บริการ css ที่เหมาะสมที่สุดสำหรับแต่ละอุปกรณ์ พิมพ์; หรือคุณสามารถเปลี่ยนชื่อคลาสให้สั้นกว่านี้ก่อนที่จะทำการแยง


2

ใช่ฉันมีปัญหาที่คล้ายกัน แต่สามารถแก้ไขได้ด้วยแบบสอบถามสื่อและ CSS ง่ายๆ ฉันแน่ใจว่าฉันทำผิดกฎบางอย่างที่นี่ แต่มันก็ได้ผลสำหรับฉัน

โดยพื้นฐานแล้วฉันต้องใช้แอปพลิเคชั่นขนาดใหญ่ที่ใครบางคนสร้างขึ้นมาและทำให้มันตอบสนอง พวกเขาใช้ jQueryUI และขอให้ฉันอย่ายุ่งกับ jQuery ใด ๆ ของพวกเขาดังนั้นฉันจึงถูก จำกัด ให้ใช้ CSS เพียงอย่างเดียว

เมื่อฉันกดปุ่มใดปุ่มหนึ่งในโหมดหน้าจอสัมผัสเอฟเฟกต์โฮเวอร์จะดับวูบหนึ่งวินาทีก่อนที่การทำงานของปุ่มจะมีผล นี่คือวิธีที่ฉันแก้ไข

@media only screen and (max-width:1024px) {

       #buttonOne{
            height: 44px;
        }


        #buttonOne:hover{
            display:none;
        }
}   

2

ในโครงการของฉันเราแก้ไขปัญหานี้โดยใช้https://www.npmjs.com/package/postcss-hover-prefixและhttps://modernizr.com/ ก่อนอื่นเราโพสต์ไฟล์ css เอาต์พุตด้วยไฟล์postcss-hover-prefix. มันเพิ่ม.no-touchสำหรับhoverกฎcss ทั้งหมด

const fs = require("fs");
const postcss = require("postcss");
const hoverPrfx = require("postcss-hover-prefix");

var css = fs.readFileSync(cssFileName, "utf8").toString();
postcss()
   .use(hoverPrfx("no-touch"))
   .process(css)
   .then((result) => {
      fs.writeFileSync(cssFileName, result);
   });

CSS

a.text-primary:hover {
  color: #62686d;
}

กลายเป็น

.no-touch a.text-primary:hover {
  color: #62686d;
}

ที่รันไทม์Modernizrจะเพิ่มคลาส css เพื่อhtmlแท็กแบบนี้โดยอัตโนมัติ

<html class="wpfe-full-height js flexbox flexboxlegacy canvas canvastext webgl 
  no-touch 
  geolocation postmessage websqldatabase indexeddb hashchange
  history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage
  borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients
  cssreflections csstransforms csstransforms3d csstransitions fontface
  generatedcontent video audio localstorage sessionstorage webworkers
  applicationcache svg inlinesvg smil svgclippaths websocketsbinary">

หลังการประมวลผลของ css บวก Modernizr ดังกล่าวปิดใช้งานโฮเวอร์สำหรับอุปกรณ์สัมผัสและเปิดใช้งานสำหรับอุปกรณ์อื่น ๆ ในความเป็นจริงแนวทางนี้ได้รับแรงบันดาลใจจาก Bootstrap 4 วิธีที่พวกเขาแก้ปัญหาเดียวกัน: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile


1

คุณสามารถทริกเกอร์mouseLeaveเหตุการณ์เมื่อใดก็ตามที่คุณแตะองค์ประกอบบนหน้าจอสัมผัส นี่คือวิธีแก้ปัญหาสำหรับ<a>แท็กทั้งหมด:

function removeHover() {
    var anchors = document.getElementsByTagName('a');
    for(i=0; i<anchors.length; i++) {
        anchors[i].addEventListener('touchstart', function(e){
            $('a').mouseleave();
        }, false);
    }
}

JSHint บอกว่า "อย่าสร้างฟังก์ชันภายในลูป"
NetOperator Wibby

มันเป็นการแฮ็ก ไม่ใช่รหัสที่ใช้ซ้ำได้ซึ่งถือได้ว่าเป็นแนวทางปฏิบัติที่ดี @NetOperatorWibby
กล่าวว่า Kholov

การโพสต์โค้ดนั้นไม่มีประโยชน์จริงๆที่ถือเป็นการปฏิบัติที่ดีไม่ได้ นั่นเหมือนกับการใส่ Band-Aid ลงบนบาดแผลมีด
NetOperator Wibby

1

Iv พบวิธีแก้ปัญหา 2 วิธีซึ่งโดยนัยว่าคุณตรวจพบการสัมผัสกับ modernizr หรืออย่างอื่นและตั้งค่าระดับการสัมผัสในองค์ประกอบ html

สิ่งนี้ดี แต่ไม่ได้รับการสนับสนุนเป็นอย่างดี:

html.touch *:hover {
    all:unset!important;
}

แต่สิ่งนี้มีการสนับสนุนที่ดีมาก:

html.touch *:hover {
    pointer-events: none !important;
}

ใช้งานได้อย่างไม่มีที่ติสำหรับฉันมันทำให้เอฟเฟกต์โฮเวอร์ทั้งหมดเป็นเหมือนเมื่อคุณแตะที่ปุ่มมันจะสว่างขึ้น แต่ไม่จบลงด้วยบั๊กกี้เป็นเอฟเฟกต์โฮเวอร์เริ่มต้นสำหรับเหตุการณ์ของเมาส์

การตรวจจับการสัมผัสจากอุปกรณ์ที่ไม่มีการสัมผัสฉันคิดว่า modernizr ทำงานได้ดีที่สุด:

https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js

แก้ไข

ฉันพบวิธีแก้ไขปัญหานี้ที่ดีกว่าและง่ายกว่า

วิธีตรวจสอบว่าไคลเอนต์เป็นอุปกรณ์สัมผัสหรือไม่


0

การดู CSS ของคุณอาจช่วยได้เนื่องจากดูเหมือนเป็นปัญหาที่ค่อนข้างแปลก แต่อย่างไรก็ตามถ้ามันเกิดขึ้นและสิ่งอื่น ๆ เป็นไปด้วยดีคุณสามารถลองเปลี่ยนเอฟเฟกต์โฮเวอร์เป็นจาวาสคริปต์ (คุณสามารถใช้ jquery ได้เช่นกัน) เพียงแค่เชื่อมโยงกับเมาส์โอเวอร์หรือดีกว่ายังคง mouseenter เหตุการณ์และทำให้องค์ประกอบของคุณสว่างขึ้นเมื่อเหตุการณ์เริ่มขึ้น

ดูตัวอย่างสุดท้ายที่นี่: http://api.jquery.com/mouseover/คุณสามารถใช้สิ่งที่คล้ายกับบันทึกเมื่อเหตุการณ์เริ่มขึ้นและนำไปจากที่นั่น!


ไม่มีอะไรพิเศษเกี่ยวกับ CSS ดูการแก้ไขของฉัน และฉันพยายามแล้วmouseenter; ไม่มีลูกเต๋า การแตะจะเป็นการเลื่อน "เคอร์เซอร์ของเมาส์ที่มองไม่เห็น" ดังนั้นมันจะทริกเกอร์mouseenterและmousemove(และmouseleaveเมื่อคุณแตะที่อื่น)
Joe White

0

หากคุณพอใจที่จะใช้ JavaScript คุณสามารถใช้Modernizrในเพจของคุณได้ เมื่อโหลดหน้าเว็บเบราว์เซอร์หน้าจอที่ไม่ใช่ระบบสัมผัสจะเพิ่มคลาส ".no-touch" ลงในแท็ก html แต่สำหรับเบราว์เซอร์หน้าจอสัมผัสแท็ก html จะมีการเพิ่มคลาส ".touch" ลงในแท็ก html .

จากนั้นเป็นเพียงกรณีของการตรวจสอบเพื่อดูว่าแท็ก html มีคลาสแบบไม่ต้องสัมผัสหรือไม่ก่อนที่จะตัดสินใจเพิ่ม mouseenter และ mouseleave listeners ของคุณ

if($('html').hasClass('no-touch')){
    $('.box').on("mouseenter", function(event){
            $(this).css('background-color','#0000ff')
    });
    $('.box').on("mouseleave", function(event){
            $(this).css('background-color','')
    });
}

สำหรับอุปกรณ์หน้าจอสัมผัสเหตุการณ์จะไม่มีผู้ฟังดังนั้นคุณจะไม่มีเอฟเฟกต์โฮเวอร์เมื่อคุณแตะ


เมื่อสามารถทำได้ด้วย css อย่าใช้ javascript (jquery) มันเป็นการสิ้นเปลืองพลังงานคอมพิวเตอร์
Simon Dragsbæk

1
ง่ายกว่านั้นใน CSS ของคุณคุณสามารถกำหนดกฎแยกสำหรับ.touchและ.no-touch. หากต้องการเขียนคำตอบของคุณใหม่ใน CSS ร่วมกับ Modernizer html.no-touch .box:hover {background-color: "#0000ff"}และไม่ได้กำหนดสิ่งใดไว้สำหรับhtml.touch .box:hoverเคล็ดลับเนื่องจาก OP พยายามหลีกเลี่ยงอุปกรณ์เคลื่อนที่:hoverเท่านั้น
Walter Roman

0

ในโครงการที่ฉันทำเมื่อเร็ว ๆ นี้ฉันได้แก้ไขปัญหานี้ด้วยคุณลักษณะเหตุการณ์ที่ได้รับมอบหมายของ jQuery ค้นหาองค์ประกอบบางอย่างโดยใช้ตัวเลือก jQuery และเพิ่ม / ลบคลาส CSS ให้กับองค์ประกอบเหล่านั้นเมื่อเมาส์อยู่เหนือองค์ประกอบ ดูเหมือนว่าจะทำงานได้ดีเท่าที่ฉันสามารถทดสอบได้ซึ่งรวมถึง IE10 บนโน้ตบุ๊กที่รองรับระบบสัมผัสที่ใช้ Windows 8

$(document).ready(
    function()
    {
        // insert your own selector here: maybe '.hoverable'?
        var selector = 'button, .hotspot';

        $('body')
            .on('mouseover', selector, function(){ $(this).addClass('mouseover');    })
            .on('mouseout',  selector, function(){ $(this).removeClass('mouseover'); })
            .on('click',     selector, function(){ $(this).removeClass('mouseover'); });
    }
);

แก้ไข:แน่นอนว่าโซลูชันนี้ต้องการให้คุณแก้ไข CSS ของคุณเพื่อลบตัวเลือก ": hover" และพิจารณาล่วงหน้าว่าองค์ประกอบใดที่คุณต้องการให้ "hoverable"

หากคุณมีองค์ประกอบจำนวนมากบนหน้าเว็บของคุณ (เช่นหลายพันรายการ) อาจทำงานช้าเล็กน้อยเนื่องจากโซลูชันนี้จับเหตุการณ์สามประเภทในองค์ประกอบทั้งหมดในหน้าเว็บจากนั้นจะทำสิ่งนั้นหากตัวเลือกตรงกัน ฉันตั้งชื่อคลาส CSS ว่า "mouseover" แทนที่จะเป็น "hover" เพราะไม่ต้องการให้โปรแกรมอ่าน CSS อ่าน ": hover" โดยที่เขียนว่า ".hover"


0

นี่คือวิธีแก้ปัญหาของฉัน: http://jsfiddle.net/agamemnus/g56aw709/--โค้ดด้านล่าง

สิ่งที่ต้องทำก็คือการแปลง ": hover" เป็น ".hover" ... แค่นั้นเอง! ความแตกต่างใหญ่ระหว่างสิ่งนี้กับส่วนที่เหลือคือสิ่งนี้จะใช้ได้กับตัวเลือกองค์ประกอบที่ไม่ใช่เอกพจน์เช่น.my_class > *:hover {.

handle_css_hover_effects ()

function handle_css_hover_effects (init) {
 var init = init || {}
 var handle_touch_events = init.handle_touch_events || true
 var handle_mouse_events = init.handle_mouse_events || true
 var hover_class         = init.hover_class         || "hover"
 var delay_preferences   = init.delay_preferences   || {touch: {add: 500, remove: 500}}
 function default_handler (curobj, input_type, op) {
  var hovered_element_selector = "*" + ((op == "add") ? ":" : ("." + hover_class))
  var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll(hovered_element_selector))
  var modified_list = []
  while (true) {
   if ((curobj == null) || (curobj == document.documentElement)) break
   if (hovered_elements.indexOf(curobj) != -1) modified_list.push (curobj)
   curobj = curobj.parentNode
  }
  function do_hover_change () {modified_list.forEach (function (curobj) {curobj.classList[op](hover_class)})}
  if ((!delay_preferences[input_type]) || (!delay_preferences[input_type][op])) {
   do_hover_change ()
  } else {
   setTimeout (do_hover_change, delay_preferences[input_type][op])
  }
 }

 if (handle_mouse_events) {
  document.body.addEventListener ('mouseover' , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "add")})
  document.body.addEventListener ('mouseout'  , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
  document.body.addEventListener ('click'     , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
 }

 if (handle_touch_events) {
  document.body.addEventListener ('touchstart', function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "add")})
  document.body.addEventListener ('touchend'  , function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "remove")})
  document.body.addEventListener ('touchmove',  function (evt) {
   var curobj = evt.target
   var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll("*:hover"))
   var lastobj = null
   evt = evt.changedTouches[0]
   var elements_at_point = get_elements_at_point (evt.pageX, evt.pageY)
   // Get the last element that isn't at the current point but is still hovered over, and remove only its hover attribute.
   while (true) {
    if ((curobj == null) || (curobj == document.documentElement)) break
    if ((hovered_elements.indexOf(curobj) != -1) && (elements_at_point.indexOf(curobj) == -1)) lastobj = curobj
    curobj = curobj.parentNode
   }
   if (lastobj == null) return
   if ((!delay_preferences.touch) || (!delay_preferences.touch.remove)) {
    lastobj.classList.remove(hover_class)
   } else {
    setTimeout (function () {lastobj.classList.remove(hover_class)}, delay_preferences.touch.remove)
   }

   function get_elements_at_point (x, y) {
    var el_list = [], pe_list = []
    while (true) {
     var curobj = document.elementFromPoint(x, y)
     if ((curobj == null) || (curobj == document.documentElement)) break
     el_list.push (curobj); pe_list.push (curobj.style.pointerEvents)
     curobj.style.pointerEvents = "none"
    }
    el_list.forEach (function (current_element, i) {current_element.style.pointerEvents = pe_list[i]})
    return el_list
   }
  })
 }
}


0

สวัสดีคนจากอนาคตคุณอาจต้องการใช้pointerและ / หรือhoverแบบสอบถามสื่อ handheldแบบสอบถามสื่อได้รับการยกเลิก

/* device is using a mouse or similar */
@media (pointer: fine) {
  a:hover {
    background: red;
  }
}

-1

ลองใช้โซลูชัน jquery 2019 ที่ใช้งานง่ายนี้แม้ว่าจะมีมาสักพักแล้ว

  1. เพิ่มปลั๊กอินนี้ในส่วนหัว:

    src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. เพิ่มสิ่งนี้ใน js:

    $("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements

  3. รูปแบบที่แนะนำบางประการ ได้แก่ :

    $(":input, :checkbox,").on("touchend", function(e) {(this).focus);}); //specify elements
    
    $("*").on("click, touchend", function(e) { $(this).focus(); });  //include click event`
    
    css: body { cursor: pointer; } //touch anywhere to end a focus`

หมายเหตุ

  • วางปลั๊กอินก่อน bootstrap.js หากมีเพื่อหลีกเลี่ยงผลกระทบต่อคำแนะนำเครื่องมือ
  • ทดสอบบน iPhone XR ios 12.1.12 และ ipad 3 ios 9.3.5 โดยใช้ Safari หรือ Chrome เท่านั้น

อ้างอิง:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.