Question

CSS - focus not working on any browser Why?

Hi there I really never had this problem but today I dont't really understand why the focus is not working - I tried to built a custom switch without using js --- and it looks good and with the mouse it is working. Unfortunately not with the focus state -

but here is the code:

input {
  appearance: none;
  position: relative;
  display: inline-block;
  background: lightgrey;
  height: 1.65rem;
  width: 2.76rem;
  vertical-align: middle;
  border-radius: 2rem;
  box-shadow: 0px 1px 3px #0003 inset;
  transition: 0.25s linear background;
}

input::before {
  content: "";
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  background: #fff;
  border-radius: 1.2rem;
  position: absolute;
  top: .2rem;
  left: .2rem;
  box-shadow: 0px 1px 3px #0003;
  transition: 0.25s linear transform;
  transform: translateX(0rem);
}

:checked {
  background: green;
}

:checked::before {
  transform: translateX(1rem);
}

input:focus-visible {
  outline: 2px solid dodgerblue;
  outline-offset: 2px;
}

input:focus {
  outline: none;
  outline-color: transparent;
}

`
<label for="awesomeFeature">
  <input type="checkbox" name="awesomeFeature" id="awesomeFeature">
  my awesome feature
 </label>

I expect the focus highlightning

 2  50  2
1 Jan 1970

Solution

 6

This is because the CSS selectors input:focus-visible and input:focus are both matching when the element is focused.

:focus-visible is not more specific than :focus. In the absence of any other selectors, the browser sees your input:focus-visible and input:focus selectors to be as important as each other. Now, your input:focus-visible rules have a visible outline, but your input:focus rules have an outline of none. The browser can't do both, so it picks the final rule of that specificity to be the one that's applied. The input:focus's rule wins out and the element is given an outline of none.

To fix this you could re-order your CSS:

input:focus {
  outline: none;
  outline-color: transparent;
}
input:focus-visible {
  outline: 2px solid dodgerblue;
  outline-offset: 2px;
}

With this the :focus-visible rule is last and thus will be the one applied.

2024-07-24
jla