Diese ausgezeichneten Artikel von Roman Komarov stellt eine tragfähige Lösung für das Erreichen Tastatur-only Fokus Stile für Schaltflächen , Links und andere Containerelemente wie Spannweiten oder divs (die mit dem Attribut tabindex künstlich hergestellt fokussierbar sind)
Die Lösung:
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) Wickeln Sie den Inhalt des ursprünglichen interaktiven Elements in ein zusätzliches inneres Element mit tabindex="-1"
(siehe Erklärung unten).
Also anstatt zu sagen:
<button id="btn" class="btn" type="button">I'm a button!</button>
mach das:
<button id="btn" class="btn" type="button">
<span class="btn__content" tabindex="-1">
I'm a button!
</span>
</button>
2) Verschieben Sie das CSS-Styling auf das innere Element (Layout-CSS sollte auf dem ursprünglichen äußeren Element verbleiben) - so dass die Breite / Höhe des äußeren Elements vom inneren usw. stammt.
3) Entfernen Sie das Standard-Fokus-Styling von den äußeren und inneren Elementen:
.btn:focus,
.btn__content:focus {
outline: none;
}
4) Fügen Sie dem inneren Element nur dann wieder Fokus-Styling hinzu, wenn das äußere Element den Fokus hat:
.btn:focus > .btn__content {
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
Warum funktioniert das?
Der Trick hier ist das Setzen des inneren Elements mit tabindex="-1"
- siehe MDN :
Ein negativer Wert (normalerweise tabindex = "- 1" bedeutet, dass das Element fokussierbar sein sollte, aber nicht über die sequentielle Tastaturnavigation erreichbar sein sollte ...
Das Element kann also per Mausklick oder programmgesteuert fokussiert werden. Andererseits kann es nicht über Tastatur-Registerkarten erreicht werden.
Wenn also auf das interaktive Element geklickt wird, erhält das innere Element den Fokus. Es werden keine Fokusstile angezeigt, da wir sie entfernt haben.
.btn:focus,
.btn__content:focus {
outline: none;
}
Beachten Sie, dass zu einem bestimmten Zeitpunkt nur 1 DOM-Element fokussiert werden kann (und document.activeElement
dieses Element zurückgibt), sodass nur das innere Element fokussiert wird.
Auf der anderen Seite: Wenn wir mit der Tastatur tippen, wird nur das äußere Element fokussiert (denken Sie daran: Das innere Element hat tabindex = "- 1" und ist nicht über die sequentielle Tastaturnavigation erreichbar). fokussierbare äußere Elemente wie ein klickbares <div>
- wir müssen sie künstlich fokussierbar machen, indem wir hinzufügen tabindex="0"
]
Jetzt wird unser CSS aktiviert und die Fokusstile nur für die Tastatur hinzugefügt the inner element
.
.btn:focus > .btn__content {
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
Natürlich möchten wir sicherstellen, dass wir beim Aktivieren und Drücken enter
nicht unser interaktives Element beschädigt haben und das Javascript ausgeführt wird.
Hier ist eine Demo, die zeigt, dass dies tatsächlich der Fall ist. Beachten Sie jedoch, dass Sie diese nur für inhärent interaktive Elemente wie Schaltflächen und Links kostenlos erhalten (dh die Eingabetaste drücken, um ein Klickereignis auszulösen). Für andere Elemente wie z. B. Bereiche - Sie müssen das manuell codieren :)
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>
NB:
1) Obwohl dies eine übermäßig komplizierte Lösung zu sein scheint, ist sie für eine Nicht-Javascript-Lösung tatsächlich ziemlich beeindruckend. Einfachere CSS-only ‚Lösungen‘ beteiligt :hover
und :active
Pseudo-Klasse Styling tun einfach nicht funktionieren. (es sei denn, Sie gehen natürlich davon aus, dass das interaktive Element beim Klicken wie eine Schaltfläche innerhalb eines modalen Sprichworts sofort verschwindet.)
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) Diese Lösung ist nicht perfekt: Firefox unter Windows erhält weiterhin Fokusstile für Schaltflächen beim Klicken - aber das scheint ein Firefox-Fehler zu sein (siehe Artikel ).
3) Wenn Browser die Pseudoklasse : focus-ring implementieren - es gibt möglicherweise eine viel einfachere Lösung für dieses Problem - (siehe Artikel ) Für das, was es wert ist, gibt es eine Polyfüllung für :focus-ring
- siehe diesen Artikel von Chris DeMars
Eine pragmatische Alternative zu Nur-Tastatur-Fokusstilen
Das Erreichen von Nur-Tastatur-Fokusstilen ist daher überraschend schwierig. Eine Alternative / Problemumgehung, die viel einfacher ist und sowohl die Erwartungen des Designers erfüllt als auch zugänglich ist, besteht darin, den Fokus so zu gestalten, wie Sie ihn für den Schwebeflug stylen würden.
Obwohl dies technisch gesehen keine Nur-Tastatur-Stile implementiert, entfällt im Wesentlichen die Notwendigkeit von Nur-Tastatur-Stilen.
addClass()
die Elemente, um das Fokus-Styling zu erhalten.