찾다
웹 프론트엔드CSS 튜토리얼클릭이 클릭 한 번만 있지 않은 경우

When a Click is Not Just a Click

The click event is quite simple and easy to use; you listen for the event and run code when the event is fired. It works on just about every HTML element there is, a core feature of the DOM API.

As often the case with the DOM and JavaScript, there are nuances to consider. Some nuances with the click event are typically not much a concern. They are minor and probably most people would never even notice them in the majority of use cases.

Take, for example, the click event listening to the grandfather of interactive elements, the

How do we distinguish between different types of clicks? That’s what we’re diving into!

First things first

The

The HTML element represents a clickable button, used to submit forms or anywhere in a document for accessible, standard button functionality. By default, HTML buttons are presented in a style resembling the platform the user agent runs on, but you can change buttons’ appearance with CSS.

The part we’ll cover is obviously the “anywhere in a document for accessible, standard button functionality” part of that description. As you may know, a button element can have native functionality within a form, for example it can submit a form in some situations. We are only really concerning ourselves over the basic clicking function of the element. So consider just a simple button placed on the page for specific functionality when someone interacts with it.

Consider that I said “interacts with it” instead of just clicking it. For historical and usability reasons, one can “click” the button by putting focus on it with tabbing and then using the Space or Enter key on the keyboard. This is a bit of overlap with keyboard navigation and accessibility; this native feature existed way before accessibility was a concern. Yet the legacy feature does help a great deal with accessibility for obvious reasons.

In the example above, you can click the button and its text label will change. After a moment the original text will reset. You can also click somewhere else within the pen, tab to put focus on the button, and then use Space or Enter to “click” it. The same text appears and resets as well. There is no JavaScript to handle the keyboard functionality; it’s a native feature of the browser. Fundamentally, in this example the button is only aware of the click event, but not how it happened.

One interesting difference to consider is the behavior of a button across different browsers, especially the way it is styled. The buttons in these examples are set to shift colors on its active state; so you click it and it turns purple. Consider this image that shows the states when interacting with the keyboard.

The first is the static state, the second is when the button has focus from a keyboard tabbing onto it, the third is the keyboard interaction, and the fourth is the result of the interaction. With Firefox you will only see the first two and last states; when interacting with either Enter or Space keys to “click” it you do not see the third state. It stays with the second, or “focused”, state during the interaction and then shifts to the last one. The text changes as expected but the colors do not. Chrome gives us a bit more as you’ll see the first two states the same as Firefox. If you use the Space key to “click” the button you’ll see the third state with the color change and then the last. Interestingly enough, with Chrome if you use Enter to interact with the button you won’t see the third state with the color change, much like Firefox. In case you are curious, Safari behaves the same as Chrome.

The code for the event listener is quite simple:

const button = document.querySelector('#button');

button.addEventListener('click', () => {
  button.innerText = 'Button Clicked!';
  
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
});

Now, let’s consider something here with this code. What if you found yourself in a situation where you wanted to know what caused the “click” to happen? The click event is usually tied to a pointer device, typically the mouse, and yet here the Space or Enter key are triggering the same event. Other form elements have similar functionality depending on context, but any elements that are not interactive by default would require an additional keyboard event to work. The button element doesn’t require this additional event listener.

I won’t go too far into reasons for wanting to know what triggered the click event. I can say that I have occasionally ran into situations where it was helpful to know. Sometimes for styling reasons, sometimes accessibility, and sometimes for specific functionality. Often different context or situations provide for different reasons.

Consider the following not as The Way™ but more of an exploration of these nuances we’re talking about. We’ll explore handling the various ways to interact with a button element, the events generated, and leveraging specific features of these events. Hopefully the following examples can provide some helpful information from the events; or possibly spread out to other HTML elements, as needed.

Which is which?

One simple way to know a keyboard versus mouse click event is leveraging the keyup and mouseup events, taking the click event out of the equation.

Now, when you use the mouse or the keyboard, the changed text reflects which event is which. The keyboard version will even inform you of a Space versus Enter key being used.

Here’s the new code:

const button = document.querySelector('#button');

function reset () {
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
}

button.addEventListener('mouseup', (e) => {
  if (e.button === 0) {
    button.innerText = 'MouseUp Event!';
    reset();
  }
});

button.addEventListener('keyup', (e) => {
  if (e.code === 'Space' || e.code === 'Enter') {
    button.innerText = `KeyUp Event: ${e.code}`;
    reset();
  }
});

A bit verbose, true, but we’ll get to a slight refactor in a bit. This example gets the point across about a nuance that needs to be handled. The mouseup and keyup events have their own features to account for in this situation.

With the mouseup event, about every button on the mouse could trigger this event. We usually wouldn’t want the right mouse button triggering a “click” event on the button, for instance. So we look for the e.button with the value of 0 to identify the primary mouse button. That way it works the same as with the click event yet we know for a fact it was the mouse.

With the keyup event, the same thing happens where about every key on the keyboard will trigger this event. So we look at the event’s code property to wait for the Space or Enter key to be pressed. So now it works the same as the click event but we know the keyboard was used. We even know which of the two keys we’re expecting to work on the button.

Another take to determine which is which

While the previous example works, it seems like a bit too much code for such a simple concept. We really just want to know if the “click” came from a mouse or a keyboard. In most cases we probably wouldn’t care if the source of the click was either the Space or Enter keys. But, if we do care, we can take advantage of the keyup event properties to note which is which.

Buried in the various specifications about the click event (which leads us to the UI Events specification) there are certain properties assigned to the event. Some browsers have more, but I want to focus on the detail property for the moment. This property is tied directly to the mouse input that fired the event itself. So if the mouse button was used then the property should return a 1 as the value. It can also potentially report a higher number representing multiple clicks that is often tied to the double-click threshold determined by the OS of the device. As a bonus, this property reports a zero for the click event being caused by something other than the mouse input, such as the keyboard.

I’ll take a moment for a shout out to Jimmy down in the comments. I originally had a different method to determining keyboard versus mouse clicking, yet it wasn’t consistent across all browsers since Safari reported values slightly different. Jimmy suggested the detail property as it was more consistent; so I updated my examples accordingly. Thanks to Jimmy for the suggestion!

Here’s our new code:

const button = document.querySelector('#button');

button.addEventListener('click', (e) => {
  button.innerText = e.detail === 0 ? 'Keyboard Click Event!' : 'Mouse Click Event!';
  
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
});

Back to just the click event, but this time we look for the property value to determine whether this is a keyboard or mouse “click.” Although notice we no longer have a way to determine what key was used on the keyboard, but that is not much of a concern in this context.

Which one out of many?

Now is a good time to talk about Pointer Events. As described by MDN:

Much of today‘s web content assumes the user’s pointing device will be a mouse. However, since many devices support other types of pointing input devices, such as pen/stylus and touch surfaces, extensions to the existing pointing device event models are needed. Pointer events address that need.

So now let’s consider having a need for knowing what type of pointer was involved in clicking that button. Relying on just the click event doesn’t really provide this information. Chrome does have an interesting property in the click event, sourceCapabilities. This property in turn has a property named firesTouchEvents that is a boolean. This information isn’t always available since Firefox and Safari do not support this yet. Yet the pointer event is available much everywhere, even IE11 of all browsers.

This event can provide interesting data about touch or pen events. Things like pressure, contact size, tilt, and more. For our example here we’re just going to focus on pointerType, which tells us the device type that caused the event.

Another point to make in relation to the detail property in the click event mentioned above. The pointer event also has a detail property but at this time the spec states that the value of that property should always be zero. Which obviously conflicts with the previous idea that a value of zero means the keyboard and a value above zero means mouse input. Since we can’t rely on that property in the pointer event, that it makes it difficult to include both click and pointer events within the same situation. To be fair, you probably wouldn’t want to do that anyway.

Clicking on the button will now tell you the pointer that was used. The code for this is quite simple:

const button = document.querySelector('#button');

button.addEventListener('pointerup', (e) => {
  button.innerText = `Pointer Event: ${e.pointerType}`;
  
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
});

Really, not that much different than the previous examples. We listen for the pointerup event on the button and output the event’s pointerType. The difference now is there is no event listener for a click event. So tabbing onto the button and using space or enter key does nothing. The click event still fires, but we’re not listening for it. At this point we only have code tied to the button that only responds to the pointer event.

That obviously leaves a gap in functionality, the keyboard interactivity, so we still need to include a click event. Since we’re already using the pointer event for the more traditional mouse click (and other pointer events) we have to lock down the click event. We need to only allow the keyboard itself to trigger the click event.

The code for this is similar to the “Which Is Which” example up above. The difference being we use pointerup instead of mouseup:

const button = document.querySelector('#button');

function reset () {
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
}

button.addEventListener('pointerup', (e) => {
  button.innerText = `Pointer Event: ${e.pointerType}`;
  reset();
});

button.addEventListener('click', (e) => {
  if (e.detail === 0) {
    button.innerText = 'Keyboard  ||Click Event!';
    reset();
  }
});

Here we’re using the detail property again to determine if the click was caused by the keyboard. This way a mouse click would be handled by the pointer event. If one wanted to know if the key used was space or enter, then the keyup example above could be used. Even then, the keyup event could be used instead of the click event depending on how you wanted to approach it.

Anoher take to determine which one out of many

In the ever-present need to refactor for cleaner code, we can try a different way to code this.

Yep, works the same as before. Now the code is:

const button = document.querySelector('#button');

function btn_handler (e) {
  if (e.type === 'click' && e.detail > 0) {
    return false;
  } else if (e.pointerType) {
    button.innerText = `Pointer Event: ${e.pointerType}`;
  } else if (e.detail === 0) {
    button.innerText = 'Keyboard Click Event!';
  } else {
    button.innerText = 'Something clicked this?';
  }
  
  window.setTimeout(() => {
    button.innerText = '"click" me';
  }, 2000);
}

button.addEventListener('pointerup', btn_handler);
button.addEventListener('click', btn_handler);

Another scaled down version to consider: this time we’ve reduced our code down to a single handler method that both pointerup and click events call. First we detect if the mouse “click” caused the event because the detail property has a value higher than zero; if it does, we wish to ignore it in favor of the pointer event.

Then the method checks for the pointer event, and upon finding that, it reports which pointer type occurred. Otherwise, the method checks for keyboard interactions, if detail equals zero, and reports accordingly. If neither of those are the culprit, it just reports that something caused this code to run.

So here we have a decent number of examples on how to handle button interactions while reporting the source of those interactions. Yet, this is just one of the handful of form elements that we are so accustomed to using in projects. How does similar code work with other elements?

Checking checkboxes

Indeed, similar code does work very much the same way with checkboxes.

There are a few more nuances, as you might expect by now. The normal usage of is a related label element that is tied to the input via the for attribute. One major feature of this combination is that clicking on the label element will check the related checkbox.

Now, if we were to attach event listeners for the click event on both elements, we get back what should be obvious results, even if they are a bit strange. For example, we get one click event fired when clicking the checkbox. If we click the label, we get two click events fired instead. If we were to console.log the target of those events, we’ll see on the double event that one is for the label (which makes sense as we clicked it), but there’s a second event from the checkbox. Even though I know these should be the expected results, it is a bit strange because we’re expecting results from user interactions. Yet the results include interactions caused by the browser.

So, the next step is to look at what happens if we were to listen for pointerup, just like some of the previous examples, in the same scenarios. In that case, we don’t get two events when clicking on the label element. This also makes sense as we’re no longer listening for the click event that is being fired from the checkbox when the label is clicked.

There’s yet another scenario to consider. Remember that we have the option to put the checkbox inside the label element, which is common with custom-built checkboxes for styling purposes.

<label for="newsletter">
  <input type="checkbox">
  Subscribe to my newsletter
</label>

In this case, we really only need to put an event listener on the label and not the checkbox itself. This reduces the number of event listeners involved, and yet we get the same results. Clicks events are fired as a single event for clicking on the label and two events if you click on the checkbox. The pointerup events do the same as before as well, single events if clicking on either element.

These are all things to consider when trying to mimic the behavior of the previous examples with the button element. Thankfully, there’s not too much to it. Here’s an example of seeing what type of interaction was done with a checkbox form element:

This example includes both types of checkbox scenarios mentioned above; the top line is a checkbox/label combination with the for attribute, and the bottom one is a checkbox inside the label. Clicking either one will output a message below them stating which type of interaction happened. So click on one with a mouse or use the keyboard to navigate to them and then interact with Space; just like the button examples, it should tell you which interaction type causes it.

To make things easier in terms of how many event listeners I needed, I wrapped the checkboxes with a container div that actually responds to the checkbox interactions. You wouldn’t necessarily have to do it this way, but it was a convenient way to do this for my needs.

const checkbox_container = document.querySelector('#checkbox_container');
const checkbox_msg = document.querySelector('#checkbox_msg');

function chk_handler (e) {
  if (e.target.tagName === 'LABEL' || e.target.tagName === 'INPUT') {
    if (e.pointerType) {
      checkbox_msg.innerText = `Pointer Event: ${e.pointerType}`;
    } else if (e.code === 'Space') {
      checkbox_msg.innerText = `Keyboard Event: ${e.code}`;
    }
    
    window.setTimeout(() => {
      checkbox_msg.innerText = 'waiting...';
    }, 2000);
  }
}

checkbox_container.addEventListener('pointerup', chk_handler);
checkbox_container.addEventListener('keyup', chk_handler);

So, since we’re listening for these events on a container div I wanted to lock down the targets to just the label and the input. Technically it would be possible in some cases to “click” on the container div itself; which we wouldn’t want to happen. Then we check for a pointer event and update the message. After that we try to identify the Space key code that would have come from the keyup event. You may remember that the button examples above used both the Enter and Space keys. It turns out that checkboxes often don’t react to the Enter key in browsers. Another fun nuance to keep in mind.

Radioing your radio buttons

Thankfully, for radio button inputs, we can still use the same code with similar HTML structures. This mostly works the same because checkboxes and radio buttons are essentially created the same way—it’s just that radio buttons tend to come in groups tied together while checkboxes are individuals even in a group. As you’ll see in the following example, it works the same:

Again, same code attached to a similar container div to prevent having to do a number of event listeners for every related element.

When a nuance can be an opportunity

I felt that “nuance” was a good word choice because the things we covered here are not really “issues” with the typical negative connotation that word tends to have in programming circles. I always try to see such things as learning experiences or opportunities. How can I leverage things I know today to push a little further ahead, or maybe it’s time to explore outward into new things to solve problems I face. Hopefully, the examples above provide a somewhat different way to look at things depending on the needs of the project at hand.

Despite this article focusing more on form elements because of the click nuance they tend to have with keyboard interactions, some or all of this can be expanded into other elements. It all depends on the context of the situation. For example, I recall having to do multiple events on the same elements depending on the context many times; often for accessibility and keyboard navigation reasons. Have you built a custom

Just remember: a “click” today doesn’t always have to be what we think a click has always been.

위 내용은 클릭이 클릭 한 번만 있지 않은 경우의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
마우스 움직임을 시뮬레이션합니다마우스 움직임을 시뮬레이션합니다Apr 22, 2025 am 11:45 AM

라이브 토크 나 수업 중에 대화식 애니메이션을 표시해야한다면 슬라이드와 상호 작용하기가 항상 쉽지 않다는 것을 알 수 있습니다.

Astro Actions 및 Fuse.js로 검색을 전원합니다Astro Actions 및 Fuse.js로 검색을 전원합니다Apr 22, 2025 am 11:41 AM

Astro를 사용하면 빌드 중에 대부분의 사이트를 생성 할 수 있지만 Fuse.js와 같은 것을 사용하여 검색 기능을 처리 할 수있는 작은 서버 측 코드가 있습니다. 이 데모에서는 퓨즈를 사용하여 개인 "북마크"세트를 검색합니다.

정의되지 않은 : 세 번째 부울 가치정의되지 않은 : 세 번째 부울 가치Apr 22, 2025 am 11:38 AM

문서가 저장되는 동안 Google 문서에서 볼 수있는 것과 유사한 프로젝트 중 하나에서 알림 메시지를 구현하고 싶었습니다. 다시 말해, a

제 3의 진술의 방어에서제 3의 진술의 방어에서Apr 22, 2025 am 11:25 AM

몇 달 전에 나는 해커 뉴스를 썼고 (하나와 마찬가지로) IF 문을 사용하지 않는 것에 대한 (현재 삭제 된) 기사를 가로 질러 달렸습니다. 이 아이디어를 처음 접한다면 (나처럼

다국어 번역에 웹 스피치 API 사용다국어 번역에 웹 스피치 API 사용Apr 22, 2025 am 11:23 AM

공상 과학 소설의 초기부터 우리는 우리와 대화하는 기계에 대해 환상을 가지고 있습니다. 오늘은 평범합니다. 그럼에도 불구하고 제작 기술

Jetpack Gutenberg 블록Jetpack Gutenberg 블록Apr 22, 2025 am 11:20 AM

Gutenberg가 핵심으로 풀려 났을 때를 기억합니다. 왜냐하면 나는 그날 WordCamp에 있었기 때문입니다. 지금은 몇 달이 지났으므로 점점 더 많은 것을 상상합니다.

VUE에서 재사용 가능한 페이지 매김 구성 요소 생성VUE에서 재사용 가능한 페이지 매김 구성 요소 생성Apr 22, 2025 am 11:17 AM

대부분의 웹 애플리케이션의 배후에있는 아이디어는 데이터베이스에서 데이터를 가져 와서 최상의 방법으로 사용자에게 제시하는 것입니다. 우리가 거기에서 데이터를 다룰 때

'Box Shadows'와 Clip-Path를 함께 사용합니다'Box Shadows'와 Clip-Path를 함께 사용합니다Apr 22, 2025 am 11:13 AM

#039;는 당신이 의미있는 것처럼 보일 수있는 상황에 대한 약간의 단계를 수행하자. 이것에서

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.