iPhone / iPad 사용자를 위해 : hover 가상 클래스를 강제로 무시할 수 있습니까?


94

내 사이트에 :hover(js없이) 확장되는 CSS 메뉴가 있습니다.

이것은 iDevices에서 약간 깨진 방식으로 작동합니다. 예를 들어 탭은 :hover규칙 을 활성화 하고 메뉴를 확장하지만 다른 곳을 탭해도 :hover. 또한 :hover'ed' 요소 내부에 링크가있는 경우 링크 를 활성화하려면 두 번 탭해야합니다 (첫 번째 탭 트리거 :hover, 두 번째 탭 트리거 링크).

touchstart이벤트 를 바인딩하여 iPhone에서 잘 작동하도록 만들 수있었습니다 .

문제는 때때로 모바일 사파리가 여전히 내 이벤트 대신:hover CSS 에서 규칙 을 트리거하도록 선택한다는 입니다 touchstart!

:hoverCSS에서 모든 규칙을 수동으로 비활성화 하면 모바일 사파리가 훌륭하게 작동 하기 때문에 이것이 문제라는 것을 알고 있습니다 (하지만 일반 브라우저는 더 이상 그렇지 않음).

:hover사용자가 모바일 사파리를 사용할 때 특정 요소에 대한 규칙 을 동적으로 "취소"하는 방법이 있습니까?

여기에서 iOS 동작을보고 비교하십시오. http://jsfiddle.net/74s35/3/ 참고 : 일부 css 속성 만 두 번 클릭 동작을 트리거합니다. 예 : display : none; 그러나 배경은 아님 : 빨간색; 또는 텍스트 장식 : 밑줄;


7
'터치'이벤트가 있다고해서 호버링을 비활성화하지 마십시오. 이는 터치 및 마우스 입력 장치가있는 랩톱 사용자에게 부정적인 영향을 미칩니다. 자세한 내용은 내 대답을 참조하십시오
Simon_Weaver

답변:


77

iPhone / iPad Safari에서 ": hover"를 예측할 수 없습니다. 때로는 요소를 탭하여 해당 요소를 ": hover"로 만들고 때로는 다른 요소로 이동합니다.

당분간은 몸에 "노터치"수업이 있습니다.

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

그리고 ".no-touch"아래에 ": hover"가있는 모든 CSS 규칙이 있습니다.

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

페이지 어딘가에 본문에서 노터치 클래스 를 제거하는 자바 스크립트가 있습니다.

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

완벽 해 보이지는 않지만 어쨌든 작동합니다.


5
이것이 할 수있는 유일한 방법입니다. 나를 괴롭히는 것은 "정상적인"사이트를 거기에 속하지 않고 관련이없는 것으로 오염 시킨다는 것입니다. 오 잘. 감사.
Christopher Camps 2011 년

IE에 대한 대체와 함께 미디어 쿼리를 사용할 수도 있습니다
Lime

2
@Shackrock : "한 번 탭하여 호버링하고 두 번 클릭"하는 방식이 좋은 해결책이라고 생각하지 않습니다. 실제로 터치 장치에는 실제 호버링이 없기 때문에 (손가락으로 호버링하는 것을 감지하는 화면이 나올 때까지) 호버링을 전혀 시뮬레이션하지 않는 것이 좋습니다. 버튼 및 링크에 일반적인 효과와 같은 효과의 경우 효과를 건너 뜁니다. 마우스 오버시 확장되는 메뉴의 경우 탭 / 클릭시 확장되도록합니다. 내 2c.
아드리안 슈미트

18
나는 때문에 터치와 마우스 입력을 갖춘 새로운 Windows 8 시스템에 접근 이런 종류의에서 최근 문제를 발견했습니다

4
Tom의 의견에 +1-ontouchstart를 확인하면 외부 모니터 (호버 상태가있는 마우스 친화적 인 사이트가 더 바람직 함)에 연결된 경우에도 터치 지원 랩톱에서 true가 반환됩니다.
gregdev 2013-04-29

45

:hover여기서 문제가 아닙니다. iOS 용 Safari는 매우 이상한 규칙을 따릅니다. 그것은 발사 mouseover되고 mousemove먼저; 이러한 이벤트 중에 변경된 사항이 있으면 '클릭'및 관련 이벤트가 시작되지 않습니다.

iOS의 터치 이벤트 다이어그램

mouseenter그리고 mouseleave그들이 차트에서 지정하지 않는하지만, 포함시킬 것으로 보인다.

이러한 이벤트의 결과로 무언가를 수정하면 클릭 이벤트가 시작되지 않습니다. 여기에는 DOM 트리의 상위 항목이 포함됩니다. 예를 들어 다음과 같이 jQuery를 사용하여 웹 사이트에서 단일 클릭이 작동하지 않도록합니다.

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

편집 : 설명을 위해 jQuery의 hover이벤트에는 mouseentermouseleave. click콘텐츠가 변경되면 둘 다 방지 됩니다.


5
물론 : hover가 문제입니다 :-) 또는 오히려 Safari의 버그가있는 구현입니다. 이것은이 문제에 대한 흥미로운 배경이지만,이 끔찍한 행동을 고칠 수있는 유일한 업체는 Apple입니다. 요소 외부의 무언가를 클릭 할 때 '언 호버 (unhover)'하거나 애초에 '호버링'하지 않아야합니다. 현재 동작은 기본적으로 사용하는 모든 웹 사이트를 나누기 : 호버를 마우스에 대한
Simon_Weaver

이것은 jquery hover핸들러가 별도의 click핸들러가 타격을받는 것을 막고 있다는 것을 깨닫는 데 도움이 되었습니다 .
Simon_Weaver 2014 년

1
내가 만난 문제에 대한 훌륭한 대답과 최고의 설명. "더블 클릭"문제를 일으키는 것은 CSS 호버뿐만 아니라 말 그대로 마우스 오버 / 마우스 등 이벤트 이후의 모든 DOM 수정입니다.
올리버 조셉 애쉬


@Oliver Joseph Ash Right, 따라서 대답의 JS 예제. ;)
Zenexer

18

브라우저 기능 감지 라이브러리 Modernizer 에는 터치 이벤트 확인이 포함되어 있습니다.

기본 동작은 감지되는 각 기능에 대해 html 요소에 클래스를 적용하는 것입니다. 그런 다음 이러한 클래스를 사용하여 문서 스타일을 지정할 수 있습니다.

터치 이벤트가 활성화되지 않은 경우 Modernizr는 다음 클래스를 추가 할 수 있습니다 no-touch.

<html class="no-touch">

그런 다음이 클래스로 호버 스타일의 범위를 지정하십시오.

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

당신은 할 수 있습니다 사용자 정의 모더 나이저 빌드를 다운로드 당신이 필요로하는 몇 가지 또는 여러 기능 탐지로 포함 할 수 있습니다.

다음은 적용될 수있는 일부 클래스의 예입니다.

<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가 "터치"를보고하는 데스크톱 용 Chrome 최신 버전에 유의하세요. 이것은 touchevents를 사용하여 버전 3에서 분명히 수정되었습니다.
Craig Jacobs

18

일부 장치 (다른 사람이 말했듯이)에는 터치 및 마우스 이벤트가 모두 있습니다. 예를 들어 Microsoft Surface에는 터치 스크린, 트랙 패드 및 화면 위로 마우스를 가져갈 때 실제로 호버 이벤트를 발생시키는 스타일러스가 있습니다.

:hover'터치'이벤트의 존재에 따라 비활성화되는 모든 솔루션은 Surface 사용자 (및 기타 유사한 장치)에도 영향을 미칩니다. 많은 새로운 랩톱은 터치 식이며 터치 이벤트에 반응하므로 호버링을 비활성화하는 것은 정말 나쁜 습관입니다.

이것은 사파리의 버그이며,이 끔찍한 행동에 대한 정당성은 전혀 없습니다. 몇 년 동안 있었던 iOS Safari의 버그 때문에 iOS가 아닌 브라우저를 방해하지 않습니다. 나는 그들이 다음 주에 iOS8에서 이것을 고치기를 정말로 희망하지만 그 동안 ....

내 솔루션 :

일부는 이미 Modernizr 사용을 제안했지만 Modernizr를 사용하면 자체 테스트를 만들 수 있습니다. 내가 여기서 기본적으로하는 것은 :hoverModernizr 테스트를 지원하는 브라우저의 아이디어를 '추상화'하는 것인데, 이는 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;
 });

그러면 CSS는 다음과 같이됩니다.

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

iOS에서만이 테스트가 실패하고 롤오버가 비활성화됩니다.

이러한 추상화의 가장 좋은 부분은 특정 Android에서 중단되거나 iOS9에서 수정 된 경우 테스트를 수정할 수 있다는 것입니다.


이 솔루션은 불쾌하고 최고입니다. 호버링으로 어려움을 겪는 브라우저에 터치와 클릭이 모두있는 경우에만 중단되지만 ipad / iphone의 터치 전용 브라우저의 경우에는 그렇지 않습니다. 내 제안은 최적화 수정으로 만 구현하고 (이미 fastclick.js를 사용할 때 호버 깜박임을 제거하기 위해) 모든 것이 그것 없이도 작동하는지 확인하는 것입니다.
Gersom

감사. 나는 동의한다. iOS 9이이 문제에 대해 무엇을하는지 궁금합니다.
Simon_Weaver

: 나는 반대 방향으로 갔다html:not(.no-hover) .category:hover { ...
크리스 Marisic

"사파리는 제대로 다루지 못하는 것을 세계에 '발표'하지 않습니다 가져가"에 대한 +1이 문제는 ... 내 의견으로는 IE의 모든 버전보다 더 아이폰 OS 길을 만든다
스펜서 오라일리

16

페이지에 FastClick 라이브러리 를 추가하면 모바일 장치의 모든 탭이 사용자가 클릭하는 위치에 관계없이 클릭 이벤트로 전환되므로 모바일 장치의 호버 문제도 수정해야합니다. 예를 들어 바이올린을 편집했습니다. http://jsfiddle.net/FvACN/8/ .

페이지에 fastclick.min.js lib를 포함하고 다음을 통해 활성화하십시오.

FastClick.attach(document.body);

부수적 인 이점으로 모바일 장치가 겪는 성가신 300ms onClick 지연도 제거됩니다.


사이트에 중요 할 수도 있고 중요하지 않을 수도있는 FastClick 사용에는 몇 가지 사소한 결과가 있습니다.

  1. 페이지 어딘가를 탭하고 위로 스크롤하고 다시 아래로 스크롤 한 다음 처음에 배치 한 위치와 똑같은 위치에서 손가락을 떼면 FastClick은 분명히 그렇지 않더라도이를 "클릭"으로 해석합니다. 적어도 이것이 제가 현재 사용하고있는 FastClick 버전 (1.0.0)에서 작동하는 방식입니다. 누군가가 해당 버전 이후 문제를 해결했을 수 있습니다.
  2. FastClick은 누군가가 "더블 클릭"하는 기능을 제거합니다.

1
제 웹 사이트에서 어떻게이 작업을 수행 할 수 있는지에 대한 또 다른 구체적인 예를 공유해 주시겠습니까? 나는 자바 스크립트에 대해 아무것도 모르기 때문에 이것이 어떻게 작동하는지 약간 혼란 스럽습니다. 사용자가 일반적으로 클릭하기 전에 마우스를 가져가는이 모든 링크가 내 웹 사이트에 있지만 ipad / 모바일의 경우 두 번 클릭 할 필요가 없도록 만들고 싶습니다.
Andy

@Andy-무엇이 필요하고 무엇을 놓치고 있는지 정확히 명확하지 않습니다 ... 지금까지 무엇을 시도했으며 어떤 오류가 표시됩니까? 새로운 Stackoverflow 질문을 작성하는 것이 가장 좋을 것입니다. 아직 작성하지 않은 경우 수행하려는 작업에 대한 예제 (?) 또는 위의 jsfiddle 예제에서 설명하지 않는 것이 무엇인지 명확히하십시오. t 이해합니다.
Troy

단일 페이지 응용 프로그램에서 사용할 수 있습니까? 나는 DOM 내용이 매번 업데이트 될 때 의미
세바스티앙 Lorber

예, 단일 페이지 응용 프로그램과 함께 사용하고 있습니다.
Troy

16

JS, CSS 클래스 및 뷰포트 확인없이 더 나은 솔루션 : 상호 작용 미디어 기능 (미디어 쿼리 레벨 4)을 사용할 수 있습니다.

이렇게 :

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

iOS Safari에서 지원

추가 정보 : https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/


하지만 Firefox에서 지원되지 않음 (물론이 댓글 당시)
Frank

이제 Firefox에서도 지원됩니다 (FF 64+, 2018 년 12 월 출시).
wunch

4

기본적으로 세 가지 시나리오가 있습니다.

  1. 사용자 는 마우스 / 포인터 장치 가지고 있으며 활성화 할 수 있습니다.:hover
  2. 사용자 는 터치 스크린 가지고 있으며 활성화 할 수 없습니다.:hover 요소를
  3. 사용자는 둘 다 터치 스크린과 포인터 장치를 .

원래 허용 된 답변은 처음 두 시나리오 만 가능하면 잘 작동합니다. 포인터 나 터치 스크린을. 이것은 OP가 4 년 전에 질문했을 때 일반적이었습니다. 몇몇 사용자는 Windows 8 및 Surface 장치가 세 번째 시나리오를 더 가능성있게 만들고 있다고 지적했습니다.

터치 스크린 장치 (@Zenexer에 의해 자세히 설명 됨)에서 호버링 할 수없는 문제에 대한 iOS 솔루션은 영리하지만 (OP에서 언급 한대로) 간단한 코드가 오작동 할 수 있습니다. 터치 스크린 장치에 대해서만 마우스 오버를 비활성화하면 터치 스크린 친화적 인 대안을 코딩해야합니다. 사용자가 포인터와 터치 스크린을 모두 가지고있을 때 감지하면 @Simon_Weaver의 설명대로 물이 더 흐려집니다.

이 시점에서 가장 안전한 해결책은 :hover사용자가 웹 사이트와 상호 작용할 수있는 유일한 방법으로 사용하지 않는 것 입니다. 호버 효과는 링크 또는 버튼이 실행 가능함을 나타내는 좋은 방법이지만 사용자가 웹 사이트에서 작업을 수행하기 위해 요소를 마우스로 가리킬 필요는 없습니다.

터치 스크린을 염두에두고 "호버"기능을 다시 생각 하면 대체 UX 접근 방식에 대한 좋은 논의가 있습니다. 답변으로 제공되는 솔루션은 다음과 같습니다.

  • 호버 메뉴를 직접 조치로 대체 (항상 표시되는 링크)
  • 마우스 오버 메뉴를 탭 메뉴로 바꾸기
  • 많은 양의 마우스 오버 콘텐츠를 별도의 페이지로 이동

앞으로는 모든 새로운 프로젝트에 가장 적합한 솔루션이 될 것입니다. 허용되는 대답은 아마도 두 번째로 좋은 솔루션 일 수 있지만 포인터 장치도있는 장치를 고려해야합니다. iOS의 :hover해킹 문제를 해결하기 위해 기기에 터치 스크린이있는 경우 기능을 제거하지 않도록주의하세요 .


1

.css의 JQuery 버전은 모든 호버 규칙에 대해 .no-touch .my-element : hover를 사용합니다. 여기에는 JQuery와 다음 스크립트가 포함됩니다.

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

그런 다음 본문 태그에 class = "no-touch"ontouchstart = "removeHoverState ()"를 추가합니다.

ontouchstart가 실행되면 모든 호버 상태에 대한 클래스가 제거됩니다.


0

터치를 사용할 수 없을 때만 호버 효과를 갖는 대신 터치 이벤트를 처리하기위한 시스템을 만들었으며 그로 인해 문제가 해결되었습니다. 먼저 "탭"( "클릭"과 동일) 이벤트를 테스트하기위한 개체를 정의했습니다.

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

그런 다음 이벤트 처리기에서 다음과 같은 작업을 수행합니다.

$('#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

답변에 대해 @Morgan Cheng에게 감사드립니다. 그러나 " touchstart "(@ Timothy Perez 답변 에서 가져온 코드) 를 얻기 위해 JS 함수를 약간 수정 했지만,이를 위해서는 jQuery 1.7+가 필요합니다.

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

0

Zenexer에서 제공하는 응답을 고려할 때 추가 HTML 태그가 필요하지 않은 패턴은 다음과 같습니다.

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

이 메서드는 먼저 마우스 오버를 시작하고 두 번째로 클릭합니다.


0

터치시 마우스 오버를 비활성화하는 것이 방법에 동의합니다.

그러나 CSS를 다시 작성하는 수고를 덜기 위해 :hover항목을 @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

:hoveriOS Safari에서 이벤트를 비활성화하는 일반적인 사용 사례를 사용하는 사람들의 경우 가장 간단한 방법은 :hover피하려는 장치의 화면 너비보다 높게 유지되는 이벤트에 대해 최소 너비 미디어 쿼리를 사용하는 것입니다. 예:

@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

화면 크기를보세요 ....

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

-12

여기에 배치 할 코드가 있습니다.

// 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
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.