哪些HTML元素可以获得焦点?

322

我正在寻找一个HTML元素的明确列表,这些元素可以被聚焦,即在这些元素上调用focus()时将把它们放入焦点状态。

我正在编写一个jQuery扩展,适用于可以聚焦的元素。我希望这个问题的答案能够让我具体地确定我要定位的元素。

6个回答

404

没有一个确定的列表,它由浏览器决定。我们唯一有的标准是根据DOM Level 2 HTML,其规定具有 focus() 方法的元素只有HTMLInputElementHTMLSelectElementHTMLTextAreaElementHTMLAnchorElement。这显然排除了HTMLButtonElementHTMLAreaElement

今天的浏览器在HTMLElement上定义了focus(),但实际上只有以下元素才会获得焦点:

  • 带有href属性的HTMLAnchorElement/HTMLAreaElement
  • HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement,但不包括disabled(如果尝试会在IE中出错),而文件上传因安全原因具有异常行为
  • HTMLIFrameElement(尽管将其聚焦不会有任何有用的操作)。其他嵌入元素也可能如此,我没有测试过所有元素。
  • 任何具有tabindex属性的元素

根据浏览器,这个行为可能还会有其他微妙的例外和补充。


3
我发现了一些有趣的结果:http://jsfiddle.net/B7gn6/ 这表明“tabindex”属性至少在Chrome中不足以工作。 - Jon z
33
HTML5标准化了tabindex属性,"允许作者控制元素是否应该可以聚焦": http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute。基本上,值为0的元素可以被聚焦,但其顺序由浏览器决定。 - natevw
13
所有具有 element.isContentEditable === true 属性的元素也可获得焦点。 注意,在 IE -10(11+?)中,任何 display:blocktable 的元素(如 div、span 等)都可以获得焦点。 - mems
22
具有tabindex值为-1的元素可以通过focus方法在程序中获得焦点,但无法通过tab键进行访问。 - jessebeach
9
除非tabindex为-1,否则无法聚焦。>> 这并不正确,如果tabindex为-1,通过点击可以进行聚焦,但是通过按“Tab”键进行聚焦是不可能的。-1使元素可聚焦,只是它没有添加到标签顺序中。请参见:http://jsfiddle.net/0jz0kd1a/,首先尝试单击元素,然后将tabindex更改为0并尝试使用tab键。 - daremkd
显示剩余12条评论

54

这里我有一个基于bobince回答的CSS选择器,可以选择任何可聚焦的HTML元素:

  a[href]:not([tabindex='-1']),
  area[href]:not([tabindex='-1']),
  input:not([disabled]):not([tabindex='-1']),
  select:not([disabled]):not([tabindex='-1']),
  textarea:not([disabled]):not([tabindex='-1']),
  button:not([disabled]):not([tabindex='-1']),
  iframe:not([tabindex='-1']),
  [tabindex]:not([tabindex='-1']),
  [contentEditable=true]:not([tabindex='-1'])
  {
      /* your CSS for focusable elements goes here */
  }

或者在SASS中更美观一点:

a[href],
area[href],
input:not([disabled]),
select:not([disabled]),
textarea:not([disabled]),
button:not([disabled]),
iframe,
[tabindex],
[contentEditable=true]
{
    &:not([tabindex='-1'])
    {
        /* your SCSS for focusable elements goes here */
    }
}

当我在谷歌搜索时,被重定向到这个 Stackoverflow 问题,但这正是我正在寻找的答案,因此我将其作为回答添加了进来。

编辑: 还有一个可聚焦的选择器:

[contentEditable=true]

然而,这种用法非常罕见。


@TWiStErRob - 你的选择器没有像@ReeCube的选择器一样针对相同的元素,因为你的选择器不包括那些没有明确设置tabindex属性的元素。例如<a href="foo.html">Bar</a>肯定是可获得焦点的,因为它是一个具有href属性的a元素。但是你的选择器并没有包括它。 - jbyrd
@jbyrd,那只是根据bobince的说法发起的编辑请求:“…除非tabindex为-1,否则无法聚焦。”,它从来没有打算替换ReeCube的答案;请参阅编辑历史记录。 - TWiStErRob
SASS(或CSS)是为上述问题提供严谨答案的适当形式(除浏览器不一致外)。 - Roy Tinker
tabindex="-1"不会使元素无法聚焦,只是不能通过按Tab键来聚焦。仍然可以通过单击它或使用HTMLElement.focus()在编程上获得焦点;同样适用于任何其他负数。请参见:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex - Lazzaro
我不会排除tabindex-1的项目。用户将无法通过任何输入设备进行聚焦,但您可能仍希望以编程方式设置和显示该焦点。 - James Westgate
3
我建议使用 input:not([type="hidden"]),除非你想要选择器聚焦一个在浏览器默认情况下被视觉和屏幕阅读器隐藏的元素。 - Bashu Naimi-Roy

14
$focusable:
  'a[href]',
  'area[href]',
  'button',
  'details',
  'input',
  'iframe',
  'select',
  'textarea',

  // these are actually case sensitive but i'm not listing out all the possible variants
  '[contentEditable=""]',
  '[contentEditable="true"]',
  '[contentEditable="TRUE"]',

  '[tabindex]:not([tabindex^="-"])',
  ':not([disabled])';

我正在创建一个SCSS列表,列出所有可聚焦的元素,因为我认为这可能会对某些人有所帮助,因为这个问题在Google排名中比较靠前。

需要注意几点:

  • 我将:not([tabindex="-1"])更改为:not([tabindex^="-"]),因为生成-2是完全有可能的。安全起见,对吧?
  • 向所有其他可聚焦选择器添加:not([tabindex^="-"])是完全毫无意义的。当使用[tabindex]:not([tabindex^="-"])时,它已经包括了您要用:not否定的所有元素!
  • 我包括了:not([disabled]),因为禁用的元素永远不能成为可聚焦的。所以把它添加到每个单独的元素中是无用的。

2
关于不必在每一行上添加 :not([disabled]) 的部分是错误的。不相信我?执行 document.querySelectorAll(':not([disabled])') 然后看看会发生什么。未禁用意味着您想要所有已启用的元素。 - Jeff Luyet
同样地,关于不必添加 :not([tabindex^="-"] 的部分。证明:在控制台中尝试运行以下代码: document.querySelectorAll('a, [tabindex]:not([tabindex="-1"]')[0]它将选择一个节点,例如 <a href="shouldnt-be-focused" tabindex="-1">nope</a>就我所知,这是由于误解了这些选择器是由“或”连接而不是“和”,因此一旦遇到 <a> 标签,它就满足了选择器。 - Bashu Naimi-Roy

11

7

3
可以运行,但会丢失当前的焦点状态。 :) - Deykun

2

有一种更加优雅的处理方式:

像下面的示例一样扩展元素原型。 然后你可以这样使用它:

element.isFocusable()

*如果“element”可聚焦,则返回 true ,否则返回 false

/**
* Determining if an element can be focused on
* @return   {Boolean}
*/
HTMLElement.prototype.isFocusable = function () {
  var current = document.activeElement
  if (current === this) return true
  var protectEvent = (e) => e.stopImmediatePropagation()
  this.addEventListener("focus", protectEvent, true)
  this.addEventListener("blur", protectEvent, true)
  this.focus({preventScroll:true})
  var result = document.activeElement === this
  this.blur()
  if (current) current.focus({preventScroll:true})
  this.removeEventListener("focus", protectEvent, true)
  this.removeEventListener("blur", protectEvent, true)
  return result
}

// A SIMPLE TEST
console.log(document.querySelector('a').isFocusable())
console.log(document.querySelector('a[href]').isFocusable())
<a>Not focusable</a>
<a href="#">Focusable</a>


你介意如果也有像“onfocus”这样的功能吗?任何通过UI来完成操作的函数都会很快失望。 - MMMahdy-PAPION
不好意思,我要告诉你的是,你的函数方式可能会出现错误。例如,如果元素添加了焦点事件,那么当开发人员检查该元素是否可聚焦时,它将运行。 - MMMahdy-PAPION
亲爱的,这不是问题,你可以轻松地添加一个事件保护函数来聚焦和模糊,并稍后将其删除。我已经为你添加了它,亲爱的。 - Bondsmith
更好但仍有问题,如果元素有一个被动的EventListener,就像我们添加临时的那个一样,它将在stopImmediatePropagation()起作用之前运行 - 看起来Safari还不支持preventScroll。 - MMMahdy-PAPION
1
这确实是一个优雅的解决方案。干得好!我唯一的问题是,我们不应该为其他与焦点相关的事件(如focusinfocusout)注册事件保护器吗?而且,我们不应该也为current添加事件保护器吗? - aradalvand
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接