Cách ngăn chặn hiệu ứng di chuột dính cho các nút trên thiết bị cảm ứng


144

Tôi đã tạo một băng chuyền với nút trước và nút tiếp theo luôn hiển thị. Các nút này có trạng thái di chuột, chúng chuyển sang màu xanh. Trên các thiết bị cảm ứng, như iPad, trạng thái di chuột bị dính, do đó nút vẫn giữ màu xanh sau khi chạm vào. Tôi không muốn điều đó.

  • Tôi có thể thêm một no-hoverlớp ontouchendcho mỗi nút và tạo CSS của mình như thế này: button:not(.no-hover):hover { background-color: blue; }nhưng điều đó có thể khá tệ đối với hiệu suất và không xử lý các thiết bị như Chromebook Pixel (có cả màn hình cảm ứng và chuột).

  • Tôi có thể thêm một touchlớp vào documentElementvà tạo CSS của mình như thế này: html:not(.touch) button:hover { background-color: blue; }Nhưng điều đó cũng không hoạt động ngay trên các thiết bị có cả chạm và chuột.

Những gì tôi muốn là loại bỏ trạng thái di chuột ontouchend . Nhưng có vẻ như điều đó là không thể. Tập trung một yếu tố khác không loại bỏ trạng thái di chuột. Khai thác một yếu tố khác theo cách thủ công, nhưng dường như tôi không thể kích hoạt điều đó trong JavaScript.

Tất cả các giải pháp tôi đã tìm thấy dường như không hoàn hảo. Có một giải pháp hoàn hảo?

Câu trả lời:


55

Bạn có thể xóa trạng thái di chuột bằng cách tạm thời xóa liên kết khỏi DOM. Xem http://testorms.handcraft.com/ipad.html


Trong CSS bạn có:

:hover {background:red;}

Trong JS bạn có:

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

Và sau đó trong HTML của bạn, bạn có:

<a href="#" ontouchend="this.onclick=fix">test</a>

3
@Chris Điểm hay, tôi đã thay đổi ví dụ để đặt trình xử lý onclick trong sự kiện ontouchend.
Sjoerd Visscher

4
Vui lòng xem xét thêm mã trình diễn tối thiểu vào câu trả lời của bạn. Cảm ơn! stackoverflow.com/help/how-to-answer
2540625

1
@SjoerdVisscher Tôi đã dán nó vào. StackOverflow thích mã được trả lời, vì các liên kết có thể biến mất. (Và trong trường hợp này, nó không chỉ cần nhấp qua, mà sau đó xem nguồn và tìm ra bit nào là kỹ thuật được đề cập.)
Darren Cook

2
@KevinBnings có trên một số thiết bị, thời gian trễ giữa việc loại bỏ và lắp lại phần tử có thể rất đáng chú ý. Thật không may, tôi thấy trên thiết bị Android 4.4 của mình làm việc này mà không có setTimeout không hoạt động.
Rodney

1
Ý tưởng này rất thú vị, nhưng tôi thấy nó hơi giật và không được hỗ trợ rộng rãi trên tất cả các thiết bị cảm ứng. Tôi muốn một giải pháp ít xâm lấn hơn dựa trên phát hiện hỗ trợ cảm ứng và css thuần túy như stackoverflow.com/a/39787268/885464
Lorenzo Polidori

83

Khi CSS Media Queries Cấp 4 được triển khai, bạn sẽ có thể làm điều này:

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

Hoặc bằng tiếng Anh: "Nếu trình duyệt hỗ trợ di chuột đúng / thật / không mô phỏng (ví dụ: có thiết bị nhập chính giống như chuột), thì hãy áp dụng kiểu này khi buttons được di chuột qua."

Vì phần này của Media Queries Cấp 4 cho đến nay chỉ được triển khai trong Chrome mới nhất, tôi đã viết một polyfill để giải quyết vấn đề này. Sử dụng nó, bạn có thể chuyển đổi CSS tương lai ở trên thành:

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

(Một biến thể về .no-touchkỹ thuật) Và sau đó sử dụng một số JavaScript phía máy khách từ cùng một polyfill phát hiện hỗ trợ cho việc di chuột, bạn có thể chuyển đổi sự hiện diện của my-true-hoverlớp tương ứng:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});

Cảm ơn! Đối với mục đích của tôi, điều này dường như được hỗ trợ trong hầu hết các trình duyệt caniuse.com/#search=media%20queries và hoạt động tuyệt vời, cảm ơn!
ragamufin

3
Thay vào đó, bạn cần xem caniuse.com/#feat=css-media-interaction và bạn sẽ thấy nó không được hỗ trợ trong Firefox và IE11 :( vì vậy bạn cần polyfill
CherryDT

Có vẻ như polyfill không còn được hỗ trợ (repo được lưu trữ) và nó yêu cầu jQuery ...
amoebe

Điều này hiện được hỗ trợ rộng rãi trong các trình duyệt di động và hoạt động như một cơ duyên. Tôi nghĩ rằng nó nên là câu trả lời được chấp nhận.
Trevor Burnham

Đây chắc chắn là cách dễ nhất để thực hiện và câu trả lời tốt nhất. Hoạt động trong Firefox trên Android Mobile và PC. Không chắc chắn về thiết bị cảm ứng kép và chuột.
HalfMens

28

Đây là một vấn đề phổ biến không có giải pháp hoàn hảo. Hành vi di chuột rất hữu ích với chuột và chủ yếu gây bất lợi khi chạm. Vấn đề là các thiết bị hỗ trợ cảm ứng và chuột (đồng thời, không kém!) Như Chromebook Pixel và Surface.

Giải pháp sạch nhất tôi tìm thấy là chỉ kích hoạt hành vi di chuột nếu thiết bị không được coi là hỗ trợ đầu vào cảm ứng.

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

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

Cấp, bạn mất di chuột trên các thiết bị có thể hỗ trợ nó. Tuy nhiên, đôi khi di chuột tác động nhiều hơn chính liên kết, ví dụ có lẽ bạn muốn hiển thị menu khi một phần tử được di chuột. Cách tiếp cận này cho phép bạn kiểm tra sự tồn tại của cảm ứng và có lẽ có điều kiện đính kèm một sự kiện khác.

Tôi đã thử nghiệm điều này trên iPhone, iPad, Chromebook Pixel, Surface và nhiều thiết bị Android. Tôi không thể đảm bảo rằng nó sẽ hoạt động khi đầu vào cảm ứng USB chung (như bút stylus) được thêm vào hỗn hợp.


1
Tuyệt vời, điều này làm việc cho tôi, không giống như câu trả lời của cộng đồng wiki / Darren Cook.
Jannik

1
Câu trả lời tốt. Đây là một giải pháp tương tự: stackoverflow.com/a/39787268/885464
Lorenzo Polidori

11

Với Modernizr, bạn có thể nhắm mục tiêu máy lượn của mình đặc biệt cho các thiết bị không chạm:

(Lưu ý: điều này không chạy trên hệ thống đoạn trích của StackOverflow, thay vào đó hãy kiểm tra 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;
}

Lưu ý rằng :activekhông cần phải nhắm mục tiêu .no-touchvì nó hoạt động như mong đợi trên cả thiết bị di động và máy tính để bàn.


Đây là câu trả lời tốt nhất IMO NHƯNG ví dụ không chính xác. Nó hiển thị trạng thái di chuột giống nhau cho các thiết bị cảm ứng và không cảm ứng. Nó chỉ nên áp dụng trạng thái di chuột nếu .no-touchcó trên htmlthẻ. Nếu không, câu trả lời này nhận được dấu phê duyệt của tôi.
morrisbret

2
Vấn đề là bây giờ các thiết bị hỗ trợ chuột có màn hình cảm ứng ở khắp mọi nơi, bạn không thể thực sự dựa vào phương pháp này nữa. Tuy nhiên tôi không thể thấy nhiều cách khác để làm điều đó ... đây là một vấn đề khá nan giải
dudewad

Tôi cho rằng một cách để làm điều đó là sử dụng cả Modernizr cũng như một thư viện như mobile-Det.js để đảm bảo đó là điện thoại hoặc máy tính bảng.
Gavin

Bạn là người cứu tinh nhờ rất nhiều điều này hoạt động hoàn hảo cho các thiết bị di động
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();
});

Bạn có thể cải thiện câu trả lời này bằng cách sử dụng on () thay vì click (). Bằng cách xóa phần tử khỏi DOM và đính kèm lại, tôi đã mất các sự kiện nhấp chuột. Khi tôi viết lại chức năng của mình với bật, liên kết với phần tử, sau đó loại bỏ và thêm hoạt động. Ví dụ: `$ ('body'). On ('click', '# Elementwithhover', function () {// clone, insertafter, remove}); Tôi sẽ bỏ phiếu này nếu bạn thực hiện thay đổi đó.
Will Lanni

bản sao thật sự bảo tồn sự kiện nhấp chuột trên elemenet mới thay thế cho phần tử với di chuột bị mắc kẹt. yếu tố ban đầu đang bị xóa khỏi dom sau khi được nhân bản.
Verard Sloggett

người anh em tuyệt vời, 10
Kaloyan Stamatov

Nhiều giờ tìm kiếm một bản sửa lỗi và điều này cuối cùng đã cung cấp một bản sửa lỗi. Cảm ơn rất nhiều!
phil917

8

Từ 4 cách để xử lý di chuột dính trên thiết bị di động : Đây là cách tự động thêm hoặc xóa can touchlớp "" vào tài liệu dựa trên loại đầu vào hiện tại của người dùng. Nó hoạt động với các thiết bị lai cũng là nơi người dùng có thể chuyển đổi giữa cảm ứng và chuột / bàn di chuột:

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

Đây là cách tốt nhất tôi tìm thấy, cộng với nếu bạn tăng bộ đếm thời gian lên 1000ms, bạn cũng có thể nhấn nút dài, xem tại đây . Công cụ tuyệt vời!
lowTechsun

8

Bạn có thể ghi đè hiệu ứng di chuột cho các thiết bị không hỗ trợ di chuột. Giống:

.my-thing {
    color: #BADA55;
}

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

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

Đã thử nghiệm và xác minh trên iOS 12

Hat tip đến https://stackoverflow.com/a/50285058/178959 để chỉ ra điều này.


Đây là giải pháp hiện đại hơn, không yêu cầu thao tác javascript hoặc DOM, có hỗ trợ trình duyệt đầy đủ (trừ IE) và phải là câu trả lời được chấp nhận.
funkju

3

Tôi sẽ đăng giải pháp của riêng mình, nhưng kiểm tra xem ai đó đã đăng nó chưa, tôi thấy rằng @Rodney gần như đã làm điều đó. Tuy nhiên, anh ấy đã bỏ lỡ nó một điều cốt yếu cuối cùng khiến nó không đáng tin, ít nhất là trong trường hợp của tôi. Ý tôi là, tôi cũng đã thực hiện việc .fakeHoverthêm / xóa lớp tương tự thông qua mouseentermouseleavephát hiện sự kiện, nhưng một mình, mỗi lần , hoạt động gần như chính xác như "chính hãng" :hover. Ý tôi là: khi bạn nhấn vào một yếu tố trong bảng của mình, nó sẽ không phát hiện ra rằng bạn đã "nhảy" nó - do đó giữ trạng thái "fakehover".

Những gì tôi đã làm chỉ đơn giản là để nghe click, vì vậy khi tôi "nhấn" nút, tôi tự kích hoạt a mouseleave.

Si đây là mã cuối cùng của tôi:

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

Bằng cách này bạn giữ bình thường hover chức năng khi sử dụng chuột khi chỉ cần "di chuột" trên các nút. Chà, gần như tất cả: nhược điểm duy nhất bằng cách nào đó là, sau khi nhấp vào nút bằng chuột, nó sẽ không ở hovertrạng thái. Giống như nếu bạn nhấp và nhanh chóng lấy con trỏ ra khỏi nút. Nhưng trong trường hợp của tôi, tôi có thể sống với điều đó.


2

Đây là những gì tôi đã đưa ra cho đến nay sau khi nghiên cứu phần còn lại của câu trả lời. Nó có thể hỗ trợ người dùng chỉ cảm ứng, chỉ chuột hoặc lai.

Tạo một lớp di chuột riêng cho hiệu ứng di chuột. Theo mặc định, thêm lớp di chuột này vào nút của chúng tôi.

Chúng tôi không muốn phát hiện sự hiện diện của hỗ trợ cảm ứng và vô hiệu hóa tất cả các hiệu ứng di chuột ngay từ đầu. Như đã đề cập bởi những người khác, các thiết bị lai đang trở nên phổ biến; mọi người có thể có hỗ trợ cảm ứng nhưng muốn sử dụng chuột và ngược lại. Do đó, chỉ loại bỏ lớp di chuột khi người dùng thực sự chạm vào nút.

Vấn đề tiếp theo là, nếu người dùng muốn quay lại sử dụng chuột sau khi chạm vào nút thì sao? Để giải quyết điều đó, chúng ta cần tìm một thời điểm thích hợp để thêm lại lớp di chuột mà chúng ta đã loại bỏ.

Tuy nhiên, chúng tôi không thể thêm lại ngay sau khi gỡ bỏ, vì trạng thái di chuột vẫn còn hoạt động. Chúng tôi có thể không muốn phá hủy và tạo lại toàn bộ nút.

Vì vậy, tôi đã nghĩ đến việc sử dụng thuật toán chờ bận (sử dụng setInterval) để kiểm tra trạng thái di chuột. Khi trạng thái di chuột bị vô hiệu hóa, chúng ta có thể thêm lại lớp di chuột và dừng chờ đợi bận, đưa chúng ta trở lại trạng thái ban đầu nơi người dùng có thể sử dụng chuột hoặc chạm.

Tôi biết chờ đợi bận rộn không phải là tuyệt vời nhưng tôi không chắc có một sự kiện thích hợp. Tôi đã xem xét để thêm nó trở lại trong sự kiện mouseleave, nhưng nó không mạnh mẽ lắm. Ví dụ: khi cảnh báo bật lên sau khi chạm vào nút, vị trí chuột sẽ dịch chuyển nhưng sự kiện mouseleave không được kích hoạt.

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>

Chỉnh sửa: Một cách tiếp cận khác mà tôi đã thử là gọi e.preventDefault()trong ontouchstart hoặc ontouchend. Nó dường như dừng hiệu ứng di chuột khi chạm vào nút, nhưng nó cũng dừng hoạt hình nhấp vào nút và ngăn chức năng onclick được gọi khi chạm vào nút, do đó bạn phải gọi thủ công trong trình xử lý ontouchstart hoặc ontouchend. Không phải là một giải pháp rất sạch sẽ.


1

Nó rất hữu ích cho tôi: 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");
                    }
                }
            }
        }
    }
}

Bạn cần gọi hoverTouchUnstick () một lần từ trình xử lý sự kiện ontouchstart toàn cầu. Và giải pháp này sẽ hoạt động hoàn hảo.
Jusid

1

Thêm mã JS này vào trang của bạn:

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

bây giờ trong CSS của bạn trước mỗi lần di chuột thêm lớp di chuột như thế này:

.hover .foo:hover {}

Nếu thiết bị được chạm, lớp cơ thể sẽ trống, nếu không, lớp của thiết bị sẽ được di chuột và các quy tắc được áp dụng!


Không làm việc cho tôi, nhưng điều này đã làm:document.body.className = 'ontouchstart' in window ? '' : 'hover';
drskullster

1

Tôi có thể thêm một lớp không di chuột ontouchend cho mỗi nút và tạo CSS của mình như> this: button: not (.no-hover): hover {background-color: blue; } nhưng điều đó có thể khá tệ đối với hiệu suất và không xử lý> các thiết bị như Chromebook Pixel (có cả màn hình cảm ứng và chuột)> chính xác.

Đây là điểm khởi đầu đúng. Bước tiếp theo: áp dụng / xóa lớp nohover cho các sự kiện sau (bản demo với jQuery)

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

Lưu ý: Nếu bạn muốn áp dụng các lớp khác cho nút, thì: không (.nohover) trong CSS sẽ không hoạt động như mong đợi. Thay vào đó, bạn phải thêm một định nghĩa riêng với giá trị mặc định và! Thẻ quan trọng để ghi đè kiểu di chuột: .nohover {nền-màu: trắng! Quan trọng}

Điều này thậm chí sẽ xử lý các thiết bị như Chromebook Pixel (có cả màn hình cảm ứng và chuột) một cách chính xác! Và tôi không nghĩ rằng đây là một kẻ giết người hiệu suất lớn ...


1

Một giải pháp đã làm việc cho tôi:

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

Thêm mã này vào biểu định kiểu của bạn.

Tôi muốn thoát khỏi nền màu xám xuất hiện trên iOS Safari khi nhấp vào liên kết. Nhưng nó xuất hiện để làm nhiều hơn nữa. Bây giờ bấm vào một nút (với một giả kính :hover!) Được mở ngay lập tức! Tôi chỉ thử nghiệm nó trên iPad, tôi không biết liệu nó có hoạt động trên các thiết bị khác không.


1

Tôi nghĩ rằng tôi đã tìm thấy một giải pháp (js tối thiểu) thanh lịch cho một vấn đề tương tự:

Sử dụng jQuery, bạn có thể kích hoạt di chuột trên cơ thể (hoặc bất kỳ yếu tố nào khác), bằng cách sử dụng .mouseover()

Vì vậy, tôi chỉ cần đính kèm một trình xử lý này vào ontouchendsự kiện của phần tử như vậy:

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

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

Tuy nhiên, điều này chỉ loại bỏ: pseudoclass di chuột khỏi thành phần sau khi một số sự kiện chạm khác được kích hoạt, như vuốt hoặc chạm khác


1
Đối với đoạn mã của bạn, hình vuông vẫn giữ nguyên màu hồng sau khi tôi chạm vào nó. Tôi đoán bạn đã không thực sự giải quyết vấn đề được hỏi trong câu hỏi này?
Kevin Lee

Giải pháp này không hoạt động. Đầu tiên, bạn đã sử dụng phương thức sai để gọi một sự kiện, bạn nên sử dụng .trigger () . Thứ hai, không hoạt động trên safari di động theo cách nào.
xHocquet

1

Tôi có giải pháp tốt đẹp mà tôi muốn chia sẻ. Trước tiên, bạn cần phát hiện xem người dùng có sử dụng điện thoại di động như thế này không:

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

Sau đó chỉ cần thêm:

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

Và trong CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}

2
Không hoạt động trên các thiết bị lai, ví dụ: PC màn hình cảm ứng Windows.
cspolton

1

Tôi đã trải qua vấn đề tương tự, ứng dụng của tôi tương thích với tất cả các kích thước màn hình có rất nhiều hiệu ứng di chuột ở kích thước màn hình máy tính để bàn thiết bị dựa trên / chuột trên và sau đó tôi nhận ra rằng các thiết bị dựa trên cảm ứng gây ra tình trạng gọi là dính -hover và đó là một trở ngại cho ứng dụng hoạt động đúng cho người dùng thiết bị cảm ứng.

Chúng tôi đã sử dụng SCSS trong ứng dụng của chúng tôi. và tôi đã xác định một mixin để chăm sóc thiết bị dựa trên cảm ứng.

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

và sau đó tôi đã đặt tất cả các lớp css của mình dưới đoạn trích được đề cập dưới đây.

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

Ví dụ, chúng tôi có một lớp để tạo hiệu ứng cho một biểu tượng và được sử dụng để kích hoạt một khi chúng tôi di chuột qua biểu tượng như bạn có thể thấy nó từ css, nhưng trong thiết bị dựa trên cảm ứng, nó đã bị ảnh hưởng bởi hiệu ứng di chuột dính và sau đó tôi đặt nó vào trong @ bao gồm hỗ trợ di chuột () để đảm bảo rằng di chuột chỉ áp dụng cho các thiết bị hỗ trợ di chuột.

@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}

1

Đây là một số mã JavaScript đơn giản không yêu cầu nhà phát triển chỉnh sửa CSS hoặc viết bất kỳ quy tắc CSS mới nào. Tôi đã viết cái này cho các nút Bootstrap class="btn", nhưng nó sẽ hoạt động với bất kỳ nút nào có tên lớp cụ thể.

Các bước là:

  1. xác định xem đây có phải là thiết bị cảm ứng không
  2. nếu có, lặp đi lặp lại qua mọi quy tắc CSS trong document.styleSheets
  3. xóa mọi quy tắc chứa cả hai .btn:hover

Việc loại bỏ tất cả .btn :hovercác quy tắc CSS đảm bảo rằng sẽ không có hiệu ứng di chuột trực quan trên một nút.

Bước 1: Phát hiện thiết bị cảm ứng

Kiểm tra truy vấn phương tiện cho sự hiện diện của (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;
    };

Bước 2: Xóa các quy tắc CSS chứa `btn` và`: 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;
    }

Mã hoàn chỉnh là trên GitHubnpm .

Bản demo trực tiếp tại terrymorse.com .


Không phải điều này cũng loại bỏ hiệu ứng di chuột cho các thiết bị màn hình cảm ứng bằng chuột / trackpad sao?
Jensei

@Jensei Có thể. Quy tắc di chuột được xóa nếu thiết bị khớp @media (hover:none)hoặc khi người dùng chạm vào màn hình lần đầu tiên. Bạn có thể dùng thử trên trang demo trực tiếp để chắc chắn.
terrymorse

0

Bạn có thể đặt màu nền ở :activetrạng thái và đưa ra :focus nền tự động.

nếu bạn đặt màu nền qua onfocus/ontouch, kiểu màu vẫn còn khi :focustrạng thái đã biến mất.
Bạn cũng cần thiết lập lại onblurđể khôi phục baut defaut khi mất tiêu điểm.


Nhưng tôi muốn duy trì hiệu ứng di chuột cho người dùng chuột.
Chris

: hover và: active có thể nhận cùng một CSS, đó là: tập trung bạn có vấn đề. Trên thực tế, nếu bạn đặt màu nền thông qua việc lấy nét, phong cách màu vẫn còn một khi tiêu điểm đã biến mất. bạn cũng cần thiết lập lại onlur để khôi phục defaut bg
G-Cyrillus

0

Điều này làm việc cho tôi: đặt kiểu di chuột vào một lớp mới

.fakehover {background: red}

Sau đó thêm / xóa lớp theo yêu cầu

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

Lặp lại cho các sự kiện touchstart và touchend. Hoặc bất kỳ sự kiện nào bạn muốn để có được kết quả mong muốn, ví dụ tôi muốn hiệu ứng di chuột được bật trên màn hình cảm ứng.


0

Dựa trên câu trả lời của Darren Cooks cũng hoạt động nếu bạn di chuyển ngón tay qua một yếu tố khác.

Xem Tìm ngón tay phần tử được bật trong một sự kiện touchend

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


0

Bạn có thể thử theo cách này.

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

0

Những gì tôi đã làm cho đến nay trong các dự án của tôi là hoàn nguyên các :hoverthay đổi trên thiết bị cảm ứng:

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

Tất cả các tên lớp và màu được đặt tên chỉ nhằm mục đích trình diễn ;-)


0

Điều này hoạt động hoàn hảo trong 2 bước.

  1. Đặt thẻ cơ thể của bạn là như thế này <body ontouchstart="">. Tôi không phải là fan hâm mộ của "hack" này, nhưng nó cho phép Safari trên iOS phản ứng với các cú chạm ngay lập tức. Không chắc làm thế nào, nhưng nó hoạt động.

  2. Thiết lập lớp cảm ứng của bạn như thế này:

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

Bạn có thể muốn xóa bất kỳ hình ảnh động trên lớp cảm ứng của bạn là tốt. Android Chrome dường như chậm hơn một chút so với iOS.

Điều này cũng sẽ dẫn đến trạng thái hoạt động được áp dụng nếu người dùng cuộn trang trong khi chạm vào lớp của bạn.


0

Một số sự cố dính hoặc bị kẹt :hover :focus :activetrên thiết bị di động có thể do thiếu <meta name="viewport" content="width=device-width">do trình duyệt cố gắng thao tác trên màn hình.


0

Giải pháp cho tôi là sau khi touchend là sao chép và thay thế nút ... tôi ghét làm điều này nhưng thậm chí cố gắng sơn lại phần tử bằng offsetHeight không hoạt động

    let cloneNode = originNode.cloneNode( true );
    originNode.parentNode.replaceChild( cloneNode, originNode );

Cuối cùng, điều này không hiệu quả với tôi ... trường hợp của tôi, tôi sẽ phải sao chép toàn bộ ES6 được mở rộng và một số người nghe sự kiện và nó bắt đầu trở nên phức tạp để giải quyết một điều nhỏ nhặt như vậy.
Cấm

0

Nó có thể được thực hiện bằng cách hoán đổi một lớp HTML. Nó sẽ ít bị trục trặc hơn là loại bỏ toàn bộ thành phần, đặc biệt là với các liên kết hình ảnh lớn, vv

Chúng tôi cũng có thể quyết định xem chúng tôi có muốn kích hoạt trạng thái di chuột hay không khi cuộn bằng cảm ứng (touchmove) hoặc thậm chí thêm thời gian chờ để trì hoãn chúng.

Thay đổi đáng kể duy nhất trong mã của chúng tôi sẽ là sử dụng lớp HTML bổ sung, chẳng hạn như <a class='hover'></a>trên các phần tử thực hiện hành vi mới.

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 (với jQuery)

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

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

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

Thí dụ

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

-

Mặc dù vậy, tôi không có bất kỳ thiết bị nào có cả chuột và cảm ứng để kiểm tra đúng cách.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.