Search code examples
htmlcssuser-agentonfocusoutline

Why does the internal css style of black outline on in-focus focusable elements, not apply on click+hold?


If you run the following demo, and click+hold(hold for 1sec before releasing the click) on the third link, you will see they get the same styles of :focus pseudo selector from the css(red outline).

.ext:focus {
  outline: 1px dotted red;
}
<a href="#">1. Get me in focus with tab to see black outline -- Browser default </a>
<br><br>

<a class="ext" href="#">2. Get me in focus with tab to see red outline -- ext css </a>

<br><br>

<a class="ext" href="#">3. Click+hold to see red outline -- supposody gets me in focus </a>
<br><br>
<a  href="#">4. Click+hold to see black outline -- doesnt work as expected!</a>

My gut feeling is that when you click+hold on any focusable element, it gets that element in focus, thats why you see a red dotted outline on #3 link.

Now, then why in the fourth link when you click+hold you don't see a black outline?


Solution

  • It is true that when you click on a focusable element it gets infocus as well, but your misconception is that the browsers internally apply the following css:

    a:focus {
      outline: 2px solid black;
    }
    

    In reality the browsers use the focus-visible css property like this:

    a:focus-visible {
      outline: 2px solid black;
    }
    

    focus-visible is a css4 level property recently introduced by most browsers(except safari). It has been designed specifically for what have you observed. This behaviour gets even more apparent in case of input fields(check out MDN's example), where you don't have to hold the click to see the result. In the case of anchor tags focus-visible applies style to only those elements who've been focused through the keyboard not the mouse. It should be noted that the button element behaves similar to a element, but the input element treats focus-visible identical to focus, that is even on click it gets the styles mention in input:focus-visible{...}.

    Example:

    input:focus-visible, button:focus-visible {
      outline: 2px dotted black;
    }
    <input type="text" value="Click/tab shows outline">
    
    <button>Only tab shows outline</button>

    Moreover, you can inspect element in your browser and toggle element's state to focus-visible. You will see the following styles being applied by the user-agent(chrome):

    a:-webkit-any-link:focus-visible {
        outline-offset: 1px;
    }
    user agent stylesheet
    a:-webkit-any-link {
        color: -webkit-link;
        cursor: pointer;
        text-decoration: underline;
    }
    user agent stylesheet
    :focus-visible {
        outline: -webkit-focus-ring-color auto 1px;
    }