我正在寻找允许获得焦点的 HTML 元素的明确列表,即当对它们调用
focus()
时哪些元素将成为焦点?
我正在编写一个 jQuery 扩展,它适用于可以成为焦点的元素。我希望这个问题的答案能让我具体说明我的目标元素。
没有明确的列表,这取决于浏览器。我们唯一的标准是 DOM Level 2 HTML,根据该标准,唯一具有
focus()
方法的元素是
HTMLInputElement
、HTMLSelectElement
、HTMLTextAreaElement
和HTMLAnchorElement
。这特别省略了 HTMLButtonElement
和 HTMLAreaElement
。
当今的浏览器在 HTMLElement 上定义
focus()
,但元素实际上不会获得焦点,除非它是以下之一:
disabled
(如果你尝试,IE 实际上会给你一个错误),并且出于安全原因,文件上传有异常行为tabindex
根据浏览器的不同,此行为可能还有其他细微的异常和添加。
这里我有一个基于 bobince 的 answer 的 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 */
}
}
我已将其添加为答案,因为当 Google 将我重定向到此 Stackoverflow 问题时,这就是我正在寻找的内容。
编辑: 还有一个选择器,可聚焦:
[contentEditable=true]
但是,这种方法很少使用。
$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])
,因为禁用的元素永远无法成为焦点。所以再次将其添加到每个元素中是没有用的。
function focus(el){
el.focus();
return el==document.activeElement;
}
返回值:true=成功,false=失败
参考:
https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElementhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
像下面的示例一样扩展元素原型。 然后你就可以像这样使用它:
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>
function isFocusable(el) {
const cs = window.getComputedStyle(el, null);
if (cs.getPropertyValue('visibility') == 'hidden' || cs.getPropertyValue('display') == 'none')
return false;
const natively = 'a[href], area[href], details, iframe, :is(button, input, select, textarea)';
if (el.matches(natively) || (el.hasAttribute('tabindex') && parseInt(el.getAttribute('tabindex')) >= 0) || el.isContentEditable)
return true;
return false;
}
*:focus {
outline: none !important;
border: 4px solid red;
box-shadow: 0 0 10px #FF5722;
}
<a id="e1" tabindex="0" role="button" aria-pressed="false">TOGGLE</a>
<span id="not-focusable">NOT FOCUSABLE</span>
<span id="e3" role="button">ACTION</span>
<button id="e4" aria-pressed="false">REAL BUTTON TOGGLE</button>
<button>REAL BUTTON ACTION</button>
<script>
const log = (ev) => {console.log('Focusable?', ev.target, isFocusable(ev.target) )}
document.getElementById('e1').addEventListener('click', log)
document.getElementById('not-focusable').addEventListener('click', log)
document.getElementById('e3').addEventListener('click', log)
document.getElementById('e4').addEventListener('click', log)
</script>