我想在不需要的时候禁用:focus,因为我不喜欢焦点放在它上时导航的外观.它使用与.active相同的风格,而且令人困惑.不过,我不想为使用键盘的人go 掉它.

我想在Tab键上的Body上添加一个类enabled-focus,然后有body.enabled-focus a:focus{...}个,但这会 for each 有焦点的元素添加很多额外的CSS.然后在第一次按下鼠标时将该类从主体中移除.

我该怎么做呢?有没有更好的解决方案?

推荐答案

Update: This issue may no longer be relevant

other0other02提到了:focus-visible伪类-现在有像样的browser support.

我想补充的是,在spec which covers the :focus-visible pseudo class的基础上,浏览器现在应该只有indicate focus个,当它对用户有帮助时-例如在用户通过键盘或其他非定点设备与页面交互的情况下

这基本上意味着原始问题不再相关,因为现在,当用户单击/点击按钮(或其他可聚焦元素)时,用户代理将不再显示聚焦环——即使按钮已聚焦——因为在这种情况下,聚焦环对用户没有帮助.

the spec开始:

而:focus伪类始终与当前聚焦的

事实上,从90版开始,Chromium的用户代理样式表从:focus切换到:focus-visible,并且由于这种更改,点击按钮不再调用焦点环

此外,在version 87版本中,Firefox还在其用户代理风格上使用:Focus-Visible.

话虽如此,如果需要自定义焦点样式,因为焦点样式现在已经从:focus变为:focus-visible,所以当用自定义焦点样式覆盖默认样式时-应该使用:focus-visible伪类.

比如:

button:focus-visible {
  /* remove default focus style */
  outline: none;
  /* custom focus styles */
  box-shadow: 0 0 2px 2px #51a7e8;
  color: lime;
}

向后兼容:

像这样使用:Focus-Visible可能存在的问题是,不支持:focus-visible的浏览器将显示默认的焦点环,根据设计的不同,默认的焦点环可能不清晰或不可见.

Šime Vidas在this article年中描述了一种可行的策略,目前使用:focus visible伪类,即使在尚不支持:focus visible的浏览器中也可以使用-

开始使用的一个好方法是:定义焦点

不支持:Focus-Visible的浏览器使用Focus样式 在:Focus规则中定义,并完全忽略第二个样式规则 (因为:焦点-可见对他们来说是未知的).

在支持"焦点可见"的浏览器中,第二个样式规则

button:focus {
  outline: none;
  background: #ffdd00; /* gold */
}

button:focus:not(:focus-visible) {
  background: white; /* undo gold */
}

Original Answer:

This excellent articlexRoman Komarov为实现buttonslinks和其他容器元素(如spansdivs)(通过tabindex属性人工设置为可聚焦)实现keyboard-only focus styles提供了一个可行的解决方案

解决方案:

button {
  -moz-appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  outline: none;
  font-size: inherit;
}

.btn {
  all: initial;
  margin: 1em;
  display: inline-block; 
}

.btn__content {
  background: orange;
  padding: 1em;
  cursor: pointer;
  display: inline-block;
}


/* Fixing the Safari bug for `<button>`s overflow */
.btn__content {
    position: relative;
}

/* All the states on the inner element */
.btn:hover > .btn__content  {
    background: salmon;
}

.btn:active > .btn__content  {
    background: darkorange;
}

.btn:focus > .btn__content  {
    box-shadow: 0 0 2px 2px #51a7e8;
    color: lime;
}

/* Removing default outline only after we've added our custom one */
.btn:focus,
.btn__content:focus {
    outline: none;
}
<h2>Keyboard-only focus styles</h2>

<button id="btn" class="btn" type="button">
    <span class="btn__content" tabindex="-1">
        I'm a button!
    </span>
</button>

<a class="btn" href="#x">
    <span class="btn__content" tabindex="-1">
        I'm a link!
    </span>
</a>

<span class="btn" tabindex="0">
    <span class="btn__content" tabindex="-1">
        I'm a span!
    </span>
</span>

<p>Try clicking any of the the 3 focusable elements above - no focus styles will show</p>
<p>Now try tabbing - behold - focus styles</p>

代码笔

  1. 将原始交互元素的内容放在一个附加的内部元素中,用tabindex="-1"表示(参见下面的说明)

因此,与其说:

<button id="btn" class="btn" type="button">I'm a button!</button>

执行此操作:

<button id="btn" class="btn" type="button">
    <span class="btn__content" tabindex="-1">
        I'm a button!
    </span>
</button>
  1. 将CSS样式移至内部元素(布局CSS应保留在原始外部元素上)-因此外部元素的宽度/高度来自内部元素,依此类推.

  2. 从外部和内部元素中删除默认焦点样式:

    .btn:专注,

  3. 将焦点样式添加回内部元素only when.外部元素具有焦点:

    .btn:焦点>;.btn__内容{ 方框阴影:0 0 2px 2px#51a7e8;/*纯键盘聚焦样式/ color: lime; /纯键盘聚焦样式*/ }

为什么这个管用呢?

这里的诀窍是将内部元素设置为tabindex="-1"-请参见MDN:

负值(通常为tabindex="-1"表示元素应 可聚焦,但不能通过顺序键盘到达 导航.

所以元素是focusable,通过鼠标点击或编程,但另一方面-它不能通过键盘的"制表符"到达.

因此,当点击交互元素时,inner element将获得焦点.不会显示焦点样式,因为我们已删除它们.

.btn:focus,
.btn__content:focus {
    outline: none;
}

请注意,only 1 DOM element can be focused at a given time(document.activeElement返回此元素)-因此only内部元素将成为焦点.

另一方面:当我们使用键盘-only the outer element will get the focus进行制表符时(请记住:内部元素的tabindex="-1",不能通过顺序键盘导航访问)[请注意,对于像可单击<div>这样的固有不可聚焦的外部元素,我们必须通过添加tabindex="0"来人为地使它们可聚焦]

现在我们的CSS开始发挥作用,并将纯键盘焦点样式添加到the inner element.

.btn:focus > .btn__content  {
    box-shadow: 0 0 2px 2px #51a7e8; /* keyboard-only focus styles */
    color: lime; /* keyboard-only focus styles */
} 

当然,我们希望确保当我们点击并按下enter键时,我们没有 destruct 我们的交互元素,javascript将运行.

这里有一个演示来证明事实的确如此,不过请注意,你只能免费获得(即按Enter键导致点击事件),用于按钮和链接等固有的交互元素.对于其他元素(如跨度),您需要手动编码:)

//var elem = Array.prototype.slice.call(document.querySelectorAll('.btn'));
var btns = document.querySelectorAll('.btn');
var fakeBtns = document.querySelectorAll('.btn[tabindex="0"]');


var animate = function() {
  console.log('clicked!');
}

var kbAnimate = function(e) {
  console.log('clicking fake btn with keyboard tab + enter...');
  var code = e.which;
  // 13 = Return, 32 = Space
  if (code === 13) {
    this.click();
  }  
}

Array.from(btns).forEach(function(element) {
  element.addEventListener('click', animate);
});

Array.from(fakeBtns).forEach(function(element) {
  element.addEventListener('keydown', kbAnimate);
});
button {
  -moz-appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  outline: none;
  font-size: inherit;
}

.btn {
  all: initial;
  margin: 1em;
  display: inline-block; 
}

.btn__content {
  background: orange;
  padding: 1em;
  cursor: pointer;
  display: inline-block;
}


/* Fixing the Safari bug for `<button>`s overflow */
.btn__content {
    position: relative;
}

/* All the states on the inner element */
.btn:hover > .btn__content  {
    background: salmon;
}

.btn:active > .btn__content  {
    background: darkorange;
}

.btn:focus > .btn__content  {
    box-shadow: 0 0 2px 2px #51a7e8;
    color: lime;
}

/* Removing default outline only after we've added our custom one */
.btn:focus,
.btn__content:focus {
    outline: none;
}
<h2>Keyboard-only focus styles</h2>

<button id="btn" class="btn" type="button">
    <span class="btn__content" tabindex="-1">
        I'm a button!
    </span>
</button>

<a class="btn" href="#x">
    <span class="btn__content" tabindex="-1">
        I'm a link!
    </span>
</a>

<span class="btn" tabindex="0">
    <span class="btn__content" tabindex="-1">
        I'm a span!
    </span>
</span>

<p>Try clicking any of the the 3 focusable elements above - no focus styles will show</p>
<p>Now try tabbing + enter - behold - our interactive elements work</p>

代码笔


NB:

  1. 虽然这似乎是一个过于复杂的解决方案,但对于非javascript解决方案来说,它实际上相当令人印象深刻.更简单的仅限于css的"解决方案"涉及:hover:active个伪类样式,根本不起作用.(当然,除非你假设交互元素在点击时立即消失,就像一个模式中的按钮一样)

button {
  -moz-appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  font-size: inherit;
}

.btn {
  margin: 1em;
  display: inline-block; 
  background: orange;
  padding: 1em;
  cursor: pointer;
}

.btn:hover, .btn:active {
  outline: none;
}
<h2>Remove css :focus outline only on :hover and :active states</h2>

<button class="btn" type="button">I'm a button!</button>

<a class="btn" href="#x">I'm a link!</a>

<span class="btn" tabindex="0">I'm a span!</span>

<h3>Problem: Click on an interactive element.As soon as you hover out - you get the focus styling back - because it is still focused (at least regarding the button and focusable span) </h3>

代码笔

  1. 这个解决方案并不完美:Windows上的Firefox仍然会在点击时获得按钮的焦点样式-但这似乎是Firefox的一个错误(参见the article)

  2. 当浏览器实现:fo­cus-ring个伪类时-这个问题可能有一个简单得多的解决方案-(参见the article) 不管它值多少钱,:focus-ringa polyfill--见this article by Chris DeMars


一种实用的键盘焦点样式替代品

因此,实现只使用键盘的焦点样式是出人意料的困难.一种替代/变通方法是much simpler,它既可以满足设计者的期望,又可以使用--就像设计悬停时的样式一样聚焦于样式.

代码笔

因此,虽然从技术上讲,这并不是实现仅键盘样式,但它基本上消除了对仅键盘样式的需要.

Css相关问答推荐

Angular中嵌套数组的网格

在ReactJS中使用动画在栅格上添加柱

此css Select 器的总体特性是什么?按钮:不是(#mainBtn,.cta)

为什么继承时1rem值不同?

如何使用 :has() 父 Select 器 Select 父元素的子元素,在父元素和子元素之间没有中间层的情况下?

flex-wrap 导致 children 身高加倍

为什么所有选项卡都没有显示在 React 的 MUI 选项卡组件中?

如何使用 Sass to CSS 创建 H1 到 H6 标题并减小字体大小

从 React MUI 自定义不同组件的正确方法?

没有 colored颜色 Select 器的 JavaFX colored颜色 Select 器

tailwind 类的别名?

使用 Webpack5 在 CSS 文件中内联字体和图像?

适合剩余高度

CSS3 的 :root 伪类和 html 有什么区别?

使用 float:left 后如何获得新行?

从 css 添加标题属性

为什么在 CSS3 中启用硬件加速会降低性能?

Select 器.class.class和.class.class有什么区别?

可变高度的 CSS 浮动 div

仅针对使用的类优化 Font Awesome