Включить: сфокусируйтесь только на использовании клавиатуры (или нажмите клавишу)

Я хочу отключить :focus когда это не нужно, потому что мне не нравится, как выглядит моя навигационная система, когда фокус на ней. Он использует тот же стиль, что и .active и это запутывает. Однако я не хочу избавляться от него для людей, которые используют клавиатуру.

Я думал добавить класс с enabled-focus на тело при нажатии табуляции, а затем body.enabled-focus a:focus{...} но это добавит много дополнительного CSS для каждого элемента, который имеет фокус. Затем удалите этот класс из тела при первой мыши вниз.

Как я могу это сделать? Есть ли лучшее решение?

Ответ 1

Эта замечательная статья Романа Комарова представляет собой жизнеспособное решение для достижения стилей фокусировки только для клавиатуры для кнопок, ссылок и других элементов контейнера, таких как промежутки или div (которые искусственно создаются с возможностью фокусировки с атрибутом tabindex)

Решение:

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> 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>

Ответ 2

Пример из практики: страница входа в Facebook

Facebook использует чуть-чуть Javascript на своей странице входа в систему (июнь 2018 года).

Javascript определяет, когда пользователь щелкнул мышью или использовал клавиатуру, и включает и выключает класс на теле: <body class="using-mouse">

Тогда правила CSS могут использовать этот класс, чтобы показать или скрыть соответствующий стиль фокуса на соответствующих элементах.

Вот пример кода (также доступен на CodePen):

// Let the document know when the mouse is being used
document.body.addEventListener('mousedown', function() {
  document.body.classList.add('using-mouse');
});
document.body.addEventListener('keydown', function() {
  document.body.classList.remove('using-mouse');
});
/* The default outline styling, for greatest accessibility. */
/* You can skip this to just use the browser defaults. */
:focus {
  outline: #08f auto 2px;
}

/* When mouse is detected, ALL focused elements have outline removed. */
/* You could apply this selector only to buttons, if you wanted. */
body.using-mouse :focus {
  outline: none;
}
<input>
<button>Submit</button>

Ответ 3

Удаление outline ужасно для доступности! В идеале кольцо фокусировки появляется только тогда, когда пользователь намеревается использовать клавиатуру.

2018 Ответ: Использование : видимый фокус. В настоящее время это предложение W3C для стилизации фокуса только на клавиатуре с использованием CSS. Пока основные браузеры не поддерживают его, вы можете использовать этот надежный полифилл. Не требует добавления дополнительных элементов или изменения tabindex.

/* Remove outline for non-keyboard :focus */
*:focus:not(.focus-visible) {
  outline: none;
}

/* Optional: Customize .focus-visible */
.focus-visible {
  outline-color: lightgreen;
}

Я также написал более подробный пост на всякий случай, если вам нужно больше информации.

Ответ 4

Это проблема, с которой вам, вероятно, придется столкнуться. Хорошая вещь о таких проблемах - если вы когда-нибудь найдете решение, это вас больше не беспокоит.

Самое элегантное решение кажется самым простым: не удаляйте схему: focus, сделайте это: active вместо этого - в конце концов: active - это динамический псевдокласс, который явно ссылается на стили, которые должны применяться, когда фокусируемый элемент нажата или активирована иным образом.

a:hover, a:active { outline: none; }

Единственные незначительные проблемы с этим методом: если пользователь активирует ссылку и затем использует кнопку возврата к браузеру, контур становится видимым. Ох, и старые версии Internet Explorer заведомо путаются с точным значением: focus,: hover и: active, поэтому этот метод терпит неудачу в IE6 и ниже.

Типп

Существует тривиальное обходное решение для предотвращения контуров от " overflow:hidden " путем добавления простого overflow:hidden, что позволяет проверять контур вокруг кликабельной части самого элемента.

Ответ 5

Играя с принятым решением Danield, я нашел альтернативный, более простой способ, основанный на концепции внутреннего/внешнего div.

1) Создайте внешний и внутренний элементы. Дайте внешний элемент tabindex = "0" и внутренний элемент tabindex = "-1"

<div role="button" class="outer" tabindex="0">
    <span class="inner" tabindex="-1">
        I'm a button!
    </span>
</div>

2) В css удалите контур из внутреннего элемента при фокусировке:

.inner:focus{
    outline: none;
}

3) Примените обработчики событий мыши или кликов к внутреннему элементу. Примените любые фокусные события (onfocus, onblur, onkeydown) к внешнему элементу.

Например:

<div role="button" class="outer" tabindex="0" onfocus="focusEventHandler()" onkeydown="handleKeyDown.bind(this, myEventHandler)">
    <div class="inner" tabindex="-1" onClick="myEventHandler()">
        I'm a button!
    </div>
</div>

** Поддерживайте размер и расположение таким образом, чтобы внутренний элемент полностью перекрывал внешний элемент. Поместите всю "кнопку" с укладкой на внешний элемент.

Как это работает:

Когда пользователь нажимает кнопку "кнопка", они нажимают на внутренний элемент, который удаляет фокус. Невозможно щелкнуть по внешнему элементу, так как он покрыт внутренним элементом. Когда пользователь использует клавиатуру для перехода к "кнопке", они попадают во внешний элемент (tabindex = "0" делает элемент доступным с "вкладкой"), который получает контур фокуса, но внутренний элемент недоступен через tab (с tabindex = "-1") и не получает схему фокусировки при нажатии.

Ответ 6

Нет четкого решения. Я сделал одно решение Hackish: примените событие click на своем основном контейнере и напишите ниже код на клик

    _handleMouseClick = (event) => {
        if(event.detail){
            document.activeElement.blur();
        }
    }

Когда вы нажмете мышью, вы получите event.detail = 1, чтобы этот клик размыл этот элемент, чтобы он удалил контур и нажал на клавиатуру, мы получим event.detail = 0, поэтому в случае клавиатуры поведение нормальное

ИЛИ

В файле css

     body.disableOutline *:focus{
        outline: none !important;
    }

В Главном js

     document.addEventListener('click', _handleMouseClick,true);
            document.addEventListener('keydown',_keydown,true);
            function _handleMouseClick(event){
                if(event.detail){
                    document.getElementsByTagName("body")[0].classList.add("disableOutline");
                }
            }
            function _keydown(e){
                document.getElementsByTagName("body")[0].classList.remove("disableOutline");
            }

Ответ 7

&:focus:not(:hover) { }

Это не будет работать в 100% случаев, но я думаю, что для большинства людей этого должно быть достаточно.

Это предотвратит срабатывание :focus состояния при щелчке, потому что мышь должна находиться над элементом мыши, чтобы щелкнуть по нему.

https://codepen.io/heyvian/pen/eopOxr