htmlcssbuttonhyperlinkclick

CSS button/link not registering on some clicks


I want a button to "depress" when clicked. However, the method I have attempted has an undesirable effect - some clicks in certain locations on the button aren't being registered.

This question is not about JavaScript. I have linked to a JSFiddle below, which uses a JavaScript click event listener, but this is only to describe the problem better. The actual problem I'm facing is nothing todo with event listeners - the hyperlink itself does not work when clicked in various places (the browser doesn't navigate to the linked page, and even though the CSS :active class works fine, the browser behaves as if there wasn't even a click).

Fat button

The fat, depressible button I'm trying to style.

a.fatButton {
  display: inline-block;
  position: relative;
  margin: 8px;
  padding: 16px;
  background: #faa;
  border-radius: 16px;
  box-shadow: 0 8px 0 0 #f88;
  text-decoration: none;
  color: #000;
}

a.fatButton:active {
  top: 8px;
  box-shadow: none;
}
<div id="linkContainer">
  <a class="fatButton" href="#">Click me</a>
</div>

The problem is when there is any movement in the button... this could be a change of the "top" property - as in this example - a margin-top, a negative margin-bottom, a translateY, padding-top ... there must be a way to create this type of button-press effect without having this problem?

I am using Chrome 29, which was used to record the video, but the problem is also apparent in Firefox 23, although the "dud area" is in a different place on the button within Firefox.


Solution

  • super late to the party but i did happen to find a css only solution for this, the trick is to use padding for the offset bits of the main button element and then use pseudo elements that are offset by that same exact amount. the button's width and height should include the offset values and the pseudo elements should subtract this offset from their width and heights, example below (javascript added to prove that clicks will be registered in the offset parts of the button:

    const $btn = document.querySelector('button');
    const $count = document.querySelector('clicked-count');
    let clickedCount = 0;
    
    $btn.addEventListener('click', () => {
      clickedCount++;
      $count.textContent = `clicked count: ${clickedCount}`;
    });
    button-box {
      display: flex;
      width: 100dvw;
      height: 60dvh;
      align-items: center;
      justify-content: center;
     }
     
     button {
      /*reset*/
      appearance: none;
      border-width: 0;
      padding: 0;
      outline: 0;
      cursor: pointer;
      color: transparent;
      background-color: transparent;
      position: relative;
      
      /*the magic*/
      width: calc(200px + 8px); /*width + offset*/
      height: calc(56px + 8px); /*height + offset*/ 
      padding-left: 8px;
      padding-top: 8px;
     }
    
    button:before, button:after {
      position: absolute;
      border-radius: 10000px;
      
      /*the magic*/
      width: calc(100% - 8px); /*height - offset*/
      height: calc(100% - 8px); /*height - offset*/
      left: 8px;
      top: 8px;
    }
    
    button:before {
      content: ""; 
      z-index: 0;
      background-color: #00EE00;
    }
    
    button:after {
      content: attr(data-content) / "";
      background-color: #99EE99;
      transform: translate(-8px, -8px);
      transition: transform 0.24s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #009900;
      font-size: 1.2rem;
    }
    
    button:active:after {
      transform: translate(0, 0);
    }
    
    count-box {
      width: 100dvw;
      height: 40dvh;
      display: flex;
      align-items: flex-start;
      justify-content: center;
     }
     
     clicked-count {
      display: block;
      text-align: center;
      font-size: 0.88rem;
      line-height: 1rem;
      font-family: sans-serif;
     }
      
    <button-box>
      <button data-content="Hello World">Hello World</button>
    </button-box>
    <count-box>
      <clicked-count></clicked-count>
    </count-box>