Це відмінна стаття від Романа Комарова є ефективне рішення для досягнення клавіатури тільки стилів фокуса для кнопок , посилань і інших елементів контейнерів , таких як прольоти або діви (які штучно фокусируемое з атрибутом 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;
}
.btn__content {
position: relative;
}
.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;
}
.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>
2) Перемістіть стиль css до внутрішнього елемента (макет css повинен залишатися на вихідному зовнішньому елементі) - отже, ширина / висота зовнішнього елемента походить від внутрішнього і т.д.
3) Видаліть стиль фокусування за замовчуванням як із зовнішніх, так і з внутрішніх елементів:
.btn:focus,
.btn__content:focus {
outline: none;
}
4) Додайте стиль фокусування назад до внутрішнього елемента лише тоді, коли зовнішній елемент має фокус:
.btn:focus > .btn__content {
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
Чому це працює?
Фокус тут полягає у встановленні внутрішнього елемента за допомогою tabindex="-1"
- див. MDN :
Негативне значення (зазвичай tabindex = "- 1") означає, що елемент повинен бути сфокусованим, але не повинен бути доступним за допомогою послідовної навігації по клавіатурі ...
Отже, елемент можна сфокусувати за допомогою клацання миші або програмно, але з іншого боку - до нього неможливо дістатися за допомогою «вкладки» клавіатури.
Отже, коли натискається інтерактивний елемент - внутрішній елемент отримує фокус. Жодні стилі фокусування не відображатимуться, оскільки ми їх видалили.
.btn:focus,
.btn__content:focus {
outline: none;
}
Зверніть увагу, що лише 1 елемент DOM може бути сфокусований в даний момент часу (і document.activeElement
повертає цей елемент) - так лише буде сфокусовано внутрішній елемент.
З іншого боку: коли ми виконуємо вкладки за допомогою клавіатури - фокус буде потрапляти лише на зовнішній елемент (пам’ятайте: внутрішній елемент має tabindex = "- 1", і до нього неможливо дістатись за допомогою послідовної навігації на клавіатурі) [Зверніть увагу, що для власних не- фокусуються зовнішні елементи, як клікабельні <div>
- ми повинні штучно зробити їх фокусуючими, додавши tabindex="0"
]
Тепер наш CSS запускає і додає стилі фокусування лише на клавіатурі the inner element
.
.btn:focus > .btn__content {
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
Звичайно, ми хочемо переконатися, що, коли ми натискаємо таб enter
- ми не порушили наш інтерактивний елемент, і javascript запуститься.
Ось демонстрація, яка показує, що це справді так, зауважте, що ви отримуєте це безкоштовно лише (тобто натискаючи клавішу Enter, щоб викликати подію клацання) для властивих інтерактивних елементів, таких як кнопки та посилання ... для інших елементів, таких як прольоти - потрібно кодувати це вручну :)
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;
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;
}
.btn__content {
position: relative;
}
.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;
}
.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>
Примітка:
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>
2) Це рішення не ідеальне: firefox у Windows все одно отримуватиме стилі фокусування для кнопок при натисканні - але це, здається, помилка firefox (див . Статтю )
3) Коли браузери реалізувати : фокус-кільце псевда клас - може бути набагато більш простим рішенням цієї проблеми - (див статті ) Для чого це коштує, є polyfill для :focus-ring
- см цій статті Кріса Демарсе
Прагматична альтернатива стилям фокусування лише на клавіатурі
Тож досягти стилів фокусування лише на клавіатурі напрочуд важко. Один із альтернативних способів, який набагато простіший і може відповідати очікуванням дизайнера, а також бути доступним, було б спрямувати увагу на фокус так само, як і стиль наведення.
Отже, хоча технічно це не реалізує стилі лише для клавіатури, це, по суті, позбавляє потреби в стилях лише для клавіатури.
addClass()
елементами, які хочуть мати такий стиль фокусування.