>>
Основное решение: свойство document.activeElement
Для определения текущего сфокусированного DOM-элемента используется свойство document.activeElement. Оно возвращает ссылку на элемент, который в данный момент находится в фокусе (например, <input>, <textarea>, <button>, <a> с tabindex, <select> и т.д.). Если ни один элемент не имеет фокуса, возвращается <body> или null.
В вашем коде проблема в том, что вы вызываете document.activeElement сразу после загрузки страницы, когда фокус ещё не установлен ни на один из элементов. В этот момент активным элементом является <body> (или <html>). Чтобы получить корректный результат, нужно вызывать проверку после того, как пользователь кликнул на элемент или перешёл к нему с помощью Tab.
Правильный пример использования
// HTML:
// <input type="text" id="name" placeholder="Введите имя">
// <textarea id="message" placeholder="Ваше сообщение"></textarea>
// <button id="btn">Отправить</button>
// JavaScript:
document.getElementById('name').addEventListener('focus', function() {
console.log('Текущий фокус:', document.activeElement); // <input id="name">
});
// Или универсальный обработчик на все фокусируемые элементы:
document.addEventListener('focusin', function() {
let focused = document.activeElement;
console.log('Активный элемент:', focused.tagName, focused.id || '(без id)');
});
Как отслеживать изменения фокуса в реальном времени
Для этого используйте события focusin и focusout (или focus и blur). focusin всплывает, поэтому его можно повесить на родительский контейнер или на document:
document.addEventListener('focusin', function(event) {
// event.target — это элемент, который получил фокус
let target = event.target;
console.log('Фокус на:', target);
// Пример: подсветка активного поля
target.style.outline = '2px solid blue';
});
document.addEventListener('focusout', function(event) {
// event.target — элемент, который потерял фокус
let target = event.target;
target.style.outline = ''; // убираем подсветку
});
Важные нюансы
- Работа во всех браузерах:
document.activeElement поддерживается всеми современными браузерами, включая IE9+. Для старых IE (8 и ниже) может возвращать null вместо <body>.
- Элементы, которые могут получить фокус: по умолчанию это
<input>, <textarea>, <select>, <button>, <a href>, а также элементы с атрибутом tabindex (например, <div tabindex="0">).
- Проверка на null: в некоторых случаях (например, при скрытии элемента)
document.activeElement может вернуть null. Всегда проверяйте: if (document.activeElement) { ... }.
- Разница между focus и focusin:
focus не всплывает, поэтому его нужно вешать на каждый элемент отдельно. focusin всплывает, что удобно для делегирования.
Пример: получение id или класса активного элемента
function getActiveElementInfo() {
const active = document.activeElement;
if (!active || active === document.body) {
return 'Фокус не на интерактивном элементе';
}
return {
tag: active.tagName,
id: active.id,
class: active.className,
type: active.type || '—'
};
}
// Используйте в любом обработчике
document.addEventListener('click', function() {
console.log(getActiveElementInfo());
});
Таким образом, document.activeElement — это ваш главный инструмент. А в паре с событиями focusin/focusout вы сможете легко отслеживать и реагировать на изменения фокуса.
<<>>
Альтернативный подход: использование querySelector с :focus
В CSS существует псевдокласс :focus, который можно применить и в JavaScript через метод querySelector. Это может быть удобно, когда нужно найти единственный сфокусированный элемент в определённом контейнере или если вы работаете с Shadow DOM.
// Найти сфокусированный элемент во всём документе
let focusedElement = document.querySelector(':focus');
console.log(focusedElement);
// Найти сфокусированный элемент внутри конкретного контейнера
let container = document.getElementById('myForm');
let focusedInside = container.querySelector(':focus');
console.log(focusedInside); // null, если фокус вне контейнера
Преимущества:
- Работает даже в старых браузерах (IE8+), если использовать полифиллы для
querySelector.
- Позволяет легко проверить фокус внутри конкретной области, а не во всём документе.
- Может быть полезен при работе с теневой DOM (Shadow DOM), где
document.activeElement не всегда видит элементы внутри теневого дерева.
Недостатки:
- Возвращает
null, если ни один элемент не находится в фокусе, в отличие от document.activeElement, который возвращает <body>. Это может быть как плюсом, так и минусом в зависимости от задачи.
- Медленнее, чем прямое обращение к
document.activeElement, так как выполняет поиск по DOM-дереву.
В большинстве случаев document.activeElement предпочтительнее, но querySelector(':focus') — хорошая альтернатива для специфических сценариев.
// Пример: подсветка только если фокус внутри формы
if (document.querySelector('#myForm :focus')) {
console.log('Фокус внутри формы');
} else {
console.log('Фокус вне формы');
}