Activer: se concentrer uniquement sur l'utilisation du clavier (ou appuyer sur l'onglet)

je veux désactiver :focus quand ce n'est pas nécessaire parce que je n'aime pas à quoi ressemble ma navigation lorsque l'accent est mis sur elle. Il utilise le même style que .active et c'est déroutant. Cependant, je ne veux pas m'en débarrasser pour les gens qui utilisent le clavier.

je pensais ajouter une classe enabled-focus sur le corps sur l'onglet de presse et ensuite body.enabled-focus a:focus{...} mais cela ajouterait beaucoup de CSS supplémentaires pour chaque élément qui a mis l'accent. Puis enlever cette classe du corps sur la première souris vers le bas.

Comment pourrais-je aller à ce sujet? Est-il une meilleure solution?

17
demandé sur Miro 2015-07-14 12:19:22

6 réponses

cet excellent article par Romain Komarov Pose une solution viable pour atteindre styles de mise au point pour clavier seulementboutons,liens et d'autres éléments de conteneur tels que travées ou divs (qui sont artificiellement focusable avec l'attribut tabindex)

le Solution:

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

Codepen

1) envelopper le contenu de l'élément interactif original à l'intérieur d'un élément intérieur additionnel avec tabindex="-1" (voir l'explication ci-dessous)

Donc au lieu de dire:

<button id="btn" class="btn" type="button">I'm a button!</button>

faire ceci:

<button id="btn" class="btn" type="button">
    <span class="btn__content" tabindex="-1">
        I'm a button!
    </span>
</button>

2) Déplacer le style css vers l'élément intérieur ( layout css doit rester sur l'élément extérieur d'origine) - de sorte que la largeur / hauteur de l'élément extérieur venir de l'intérieur etc.

3) supprimer le style de mise au point par défaut des éléments extérieurs et intérieurs:

.btn:focus,
.btn__content:focus {
    outline: none;
}

4) Ajouter le concentrer de style de retour à l'intérieur de l'élément uniquement quand l'extérieur de l'élément a le focus:

.btn:focus > .btn__content  {
    box-shadow: 0 0 2px 2px #51a7e8; /* keyboard-only focus styles */
    color: lime; /* keyboard-only focus styles */
} 

Pourquoi ce travail?

le truc ici est de définir l'élément intérieur avec tabindex="-1" - MDN:

Une valeur négative (généralement tabindex="-1" signifie que l'élément devrait être focalisable, mais ne doit pas être accessible via un clavier séquentiel navigation...

donc l'élément est focalisable par clics de souris ou par programmation, mais d'un autre côté - il n'est pas possible d'y accéder par des 'onglets'de clavier.

Ainsi, lorsque l'élément interactif est cliqué -intérieur de l'élément obtient la concentration. Aucun Style de mise au point ne sera montré parce que nous les avons enlevés.

.btn:focus,
.btn__content:focus {
    outline: none;
}

Notez que seulement 1 Élément du DOM peut être porté à un moment donné (et document.activeElement retourne cet élément) - l'intérieur de l'élément.

d'un autre côté: lorsque nous tabulons en utilisant le clavier -seulement l'élément extérieur obtenir le focus (rappelez-vous: l'élément intérieur a tabindex= "-1" et n'est pas accessible via la navigation séquentielle au clavier) [notez que pour les éléments externes intrinsèquement non focalisables comme un cliquable <div> - nous devons faire artificiellement leur focusable en ajoutant tabindex="0"]

maintenant notre CSS s'active et ajoute les styles de mise au point pour clavier seulement à the inner element.

.btn:focus > .btn__content  {
    box-shadow: 0 0 2px 2px #51a7e8; /* keyboard-only focus styles */
    color: lime; /* keyboard-only focus styles */
} 

bien sûr, nous voulons nous assurer que lorsque nous l'onglet et appuyez sur enter - nous n'avons pas brisé notre élément interactif et le javascript s'exécute.

Voici une démo pour montrer que c'est bien le cas, notez cependant que vous ne l'obtenez que GRATUITEMENT (c'est à dire en pressant enter pour provoquer un événement de clic) pour des éléments intrinsèquement interactifs comme des boutons et des liens... pour d'autres éléments tels que les couvre - vous besoin de code manuellement :)

//var elem = Array.prototype.slice.call(document.querySelectorAll('.btn'));
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;
  // 13 = Return, 32 = Space
  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;
}


/* Fixing the Safari bug for `<button>`s 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 + enter - behold - our interactive elements work</p>

Codepen


NB:

1) bien que cela semble comme une solution trop compliquée, pour une solution non-javascript c'est en fait assez impressionnant. "Solutions" CSS-only impliquant :hover et :active pseudo classe style tout simplement ne pas travail. (à moins, bien sûr, que l'on suppose que l'élément interactif disparaît immédiatement en cliquant comme un bouton dans un say modal)

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>

Codepen

2) Cette solution n'est pas parfaite: firefox sur windows aura toujours des styles de mise au point pour les boutons sur click - mais cela semble être un bug firefox (voir l'article)

3) lorsque les navigateurs implémentent le : focus-ring pseudo class - il peut y avoir une solution beaucoup plus simple à ce problème - (voir l'article) Pour ce que ça vaut, il y a un polyfill:focus-ring -cet article par Chris DeMars


Une alternative pragmatique à clavier uniquement l'accent styles

il est donc étonnamment difficile d'obtenir des styles de mise au point sur clavier seulement. Une solution de remplacement / solution de contournement qui est beaucoup plus simple et peut à la fois satisfaire les attentes du concepteur et également être accessible de focus style comme style pour le vol stationnaire.

Codepen

donc, bien que techniquement ce ne soit pas la mise en place de styles de clavier seulement, il supprime essentiellement le besoin de styles de clavier seulement.

22
répondu Danield 2017-08-10 09:22:58

C'est un problème, vous rencontrez probablement beaucoup. La bonne chose à propos de ces problèmes est, si vous trouver une solution, il ne vous dérangera pas plus.

la solution la plus élégante semble être la plus simple: ne retirez pas le contour sur :focus, faites – le sur :active à la place-après tout, :active est la pseudo-classe dynamique qui traite explicitement des styles qui devraient être appliqués lorsqu'un élément focalisable est cliqué ou autrement activé.

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

La seule problèmes mineurs avec cette méthode: si un utilisateur active un lien et utilise ensuite le bouton Précédent du navigateur, le contour devient visible. Oh, et les anciennes versions D'Internet Explorer sont notoirement confondues par la signification exacte de :focus, :hover et :active, donc cette méthode échoue dans IE6 et ci-dessous.

Tipp

il y a une solution de contournement triviale pour empêcher les contours de "déborder" en ajoutant un simple overflow:hidden, ce qui permet de contrôler le contour autour du cliquable la partie de l'élément lui-même.

11
répondu Jeremy Zahner 2015-07-14 09:29:06

Supprimer outline est terrible pour l'accessibilité! Idéalement, l'anneau de mise au point apparaît seulement lorsque l'utilisateur a l'intention d'utiliser le clavier.

2018 réponse: Utiliser :focus-visible. Il s'agit actuellement d'une proposition du W3C pour la mise au point d'un clavier à l'aide de CSS. Jusqu'à ce que les principaux navigateurs en charge, vous pouvez utiliser cette robuste polyfill. Il n'est pas nécessaire d'ajouter des éléments supplémentaires ou de modifier le tabindex.

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

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

j'ai aussi a écrit plus de détail post juste au cas où vous avez besoin de plus d'infos.

4
répondu Aaron Noel De Leon 2018-05-28 17:22:51

étude de cas: page de connexion Facebook

Facebook utilise un tout petit peu de Javascript sur sa page de connexion en ce moment (juin 2018).

le Javascript détecte quand l'Utilisateur a cliqué sur la souris ou utilisé son clavier, et bascule une classe sur le corps sur et Hors: <body class="using-mouse">

alors les règles CSS peuvent utiliser cette classe pour montrer ou cacher le style de focus approprié sur les éléments pertinents.

Voici un exemple de code (également disponible sur 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's 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>

étude de cas: page de connexion GMail

autrement, GMail ne fait que coiffer les boutons focalisés avec une ombre plus lourde que les boutons non focalisés, que l'utilisateur soit sur la souris ou sur le clavier.

c'est cohérent, plus simple à mettre en œuvre et à tester, et ne nécessite pas de Javascript.

Mais c'est un compromis. Il transmet des informations de focus que les utilisateurs de souris ne sont pas vraiment intéressé, et c'est sans doute un peu trop subtil pour les utilisateurs de clavier.

Encore, ce compromis est beaucoup mieux que l'un des extrêmes (forte contour partout, ou pas de contour).

4
répondu joeytwiddle 2018-07-26 02:55:43

en jouant avec la solution acceptée par Danield, j'ai trouvé une solution alternative, plus simple basée sur le concept de div interne/externe.

1) Créer un élément extérieur et intérieur. Donnez l'élément externe tabindex= "0"et l'élément intérieur tabindex="-1"

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

2) dans le css, enlever le contour de l'élément intérieur lorsqu'il est focalisé:

.inner:focus{
    outline: none;
}

3) Appliquez n'importe quel gestionnaire d'événements de souris ou de clic à l'élément intérieur. Appliquer tous les événements focus (onfocus, onblur, onkeydown) à l'élément extérieur.

Par exemple:

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

**maintenir la taille et le positionnement de sorte que l'élément intérieur chevauche complètement l'élément extérieur. Placez le "bouton" entier avec le style sur l'élément extérieur.

Comment cela fonctionne:

lorsque l'utilisateur clique sur le "bouton", il clique sur l'élément intérieur dont le contour de mise au point est enlevé. Il n'est pas possible de cliquer sur l'élément extérieur, car il est couvert par l'intérieur de l'élément. Lorsque l'utilisateur utilise le clavier pour tabuler le "bouton", il arrive à l'élément externe (tabindex="0" rend l'élément accessible avec 'tab') qui obtient un contour de mise au point, mais l'élément interne n'est pas accessible à travers l'onglet (avec tabindex="-1") et ne reçoit pas de contour de mise au point lorsque cliqué.

3
répondu nutsandbolts 2017-11-20 21:50:42

Il n'y a pas de solution claire. J'ai fait une solution Hackish : appliquer l'événement de clic sur votre conteneur principal et écrire le code ci-dessous sur le clic

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

lorsque vous cliquez en utilisant la souris vous obtiendrez l'événement.détail = 1 sur ce clic obscurcissent cet élément de sorte qu'il va supprimer le contour et sur le clic de clavier nous obtenons l'événement.détail = 0 donc dans le cas du clavier se comporter normal

OR

dans le fichier css

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

Dans les Principales 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");
            }
0
répondu pareshm 2018-06-08 11:18:00