web-dev-qa-db-ja.com

有効:キーボード使用(またはタブプレス)のみにフォーカス

:focusが不要な場合は無効にします。フォーカスが置かれているときのナビゲーションの外観が気に入らないためです。 .activeと同じスタイルを使用し、混乱を招きます。しかし、キーボードを使用する人のためにそれを取り除きたくありません。

クラスenabled-focusをタブプレスの本文に追加してからbody.enabled-focus a:focus{...}を追加することを考えていましたが、フォーカスがあるすべての要素に多くの余分なCSSを追加します。次に、最初のマウスダウンでそのクラスをボディから削除します。

どうすればいいですか?より良い解決策はありますか?

36
Miro

この優れた記事 by Roman Komarov は、キーボードのみのフォーカススタイル forボタンを実現するための実行可能なソリューションを提示しますリンクおよびspansまたはdivsなどの他のコンテナ要素(これらは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>`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)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; /* keyboard-only focus styles */
    color: Lime; /* keyboard-only focus styles */
} 

なぜこれが機能するのですか?

ここでのコツは、tabindex="-1"で内部要素を設定することです- [〜#〜] mdn [〜#〜] を参照してください:

負の値(通常tabindex = "-1"は、要素がフォーカス可能でなければならないことを意味しますが、シーケンシャルキーボードナビゲーションを介して到達可能ではありません...

そのため、要素はfocusableであり、マウスクリックまたはプログラムにより、ただしキーボードの「タブ」からは到達できません。

したがって、インタラクティブ要素がクリックされると、内部要素がフォーカスを取得します。フォーカススタイルは削除されているため表示されません。

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

特定の時間にフォーカスできるDOM要素は1つのみ(およびdocument.activeElementはこの要素を返します)-only内部要素がフォーカスされることに注意してください。

一方、キーボードを使用してタブで移動する場合は、外側の要素のみがフォーカスを取得します(内側の要素にはtabindex = "-1"があり、キーボードの順次ナビゲーションでは到達できません) [クリック可能な<div>のような本質的にフォーカス不可能な外部要素の場合、tabindex="0"を追加することで人為的にフォーカス可能にする必要があることに注意してください。

CSSが起動し、キーボードのみのフォーカススタイルがthe inner elementに追加されます。

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

もちろん、タブを押してenterを押すと、インタラクティブ要素が壊れておらず、javascriptが実行されることを確認する必要があります。

これは実際にそうであることを示すデモです。ただし、ボタンやリンクなどの本質的にインタラクティブな要素については無料で取得できます(つまり、Enterキーを押してクリックするなど)。手動でコーディングする必要があります:)

//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)これは非常に複雑なソリューションのように見えますが、非JavaScriptソリューションの場合、実際には非常に印象的です。 :hoverおよび:active疑似クラススタイリングを含む、よりシンプルなCSSのみの「ソリューション」は、単に機能しません。 (もちろん、モーダル発言内のボタンのように、クリックするとインタラクティブな要素がすぐに消えると仮定しない限り)

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)この解決策は完璧ではありません:Windows上のFirefoxはクリック時にボタンのフォーカススタイルを取得しますが、Firefoxのバグのようです( the article を参照)

3)ブラウザが :focus-ring 擬似クラスを実装する場合-この問題に対するより簡単な解決策があるかもしれません-( the article を参照)価値があります、:focus-ringには a polyfill があります-Chris DeMarsによる この記事を参照してください


キーボードのみのフォーカススタイルの実用的な代替手段

そのため、キーボードのみのフォーカススタイルを実現することは驚くほど困難です。 はるかに単純であり、デザイナーの期待を満たし、アクセスしやすい代替案/回避策の1つは、ホバーのスタイル設定と同じようにフォーカスをスタイル設定することです。

Codepen

技術的には、これはキーボードのみのスタイルを実装していませんが、キーボードのみのスタイルの必要性を本質的に取り除きます。

54
Danield

ケーススタディ:Facebookログインページ

Facebookは現在、ログインページでごく一部のJavascriptを使用しています(2018年6月)。

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

上記の:focus*:focusと同等であり、すべての要素に一致することに注意してください。


ケーススタディ:Gmailのログインページ

または、その時点で、GMailは、ユーザーがマウスまたはキーボードを使用しているかどうかに関係なく、フォーカスされていないボタンよりも濃い影でフォーカスされたボタンをスタイリングしていました。

これは実装と理解が簡単で、Javascriptを必要としません。

:focus {
  outline: none;
  box-shadow: 0 0px 16px #0005;
}

しかし、それは妥協です。これは、マウスユーザーが実際に興味を持たないフォーカス情報を伝え、キーボードユーザーにとっては少し微妙かもしれません

それでも、この妥協案はおそらく、極端なもの(すべてのユーザーにとって強力なアウトライン、またはまったくアウトラインなし)のいずれかよりも優れています。


StackOverflowのプライマリボタンは、GMailと同様のアプローチを使用しますが、より様式化された外観を備えています。

box-shadow: inset 0 1px 0 0 rgba(102,191,255,0.5), 0 0 0 4px rgba(0,149,255,0.15);

個人的には、アクセシビリティのために、より強い(より高いコントラストの)色を使用します。

29
joeytwiddle

outlineを削除すると、アクセシビリティが悪くなります!理想的には、ユーザーがキーボードの使用を意図している場合にのみ、フォーカスリングが表示されます。

2018 Answer::focus-visible を使用します。現在、CSSを使用してキーボードのみのフォーカスをスタイリングするためのW3Cの提案です。主要なブラウザがサポートするまで、この堅牢な polyfill を使用できます。余分な要素を追加したり、tabindexを変更したりする必要はありません。

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

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

また、より詳細な情報が必要な場合のために、より詳細な post を作成しました。

15

これはあなたがたぶん遭遇する問題です。このような問題の良い点は、一度解決策を見つければ、それ以上気にすることはないということです。

最もエレガントな解決策は最も簡単なようです::focusのアウトラインを削除せず、代わりに:activeで実行してください–結局、:activeは動的な擬似クラスであり、フォーカス可能な要素がクリックされるか、アクティブになります。

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

この方法の唯一の小さな問題:ユーザーがリンクをアクティブにし、ブラウザの戻るボタンを使用すると、アウトラインが表示されます。ああ、古いバージョンのInternet Explorerは、:focus、:hover、および:activeの正確な意味で混乱しているため、この方法はIE6以下では失敗します。

ヒント

シンプルなoverflow:hiddenを追加することにより、アウトラインが「あふれる」のを防ぐための簡単な回避策があります。これにより、要素自体のクリック可能な部分の周りにアウトラインがチェックされます。

13
Jeremy Zahner

Danieldが受け入れたソリューションで遊んでいると、inner/outer 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")をクリックし、クリックしてもフォーカスのアウトラインを受け取りません。

4
nutsandbolts
&:focus:not(:hover) { }

100%のケースでは機能しませんが、ほとんどの人のニーズにはこれで十分だと思います。

:focusクリックするためにマウスが要素の上にある(ホバリングしている)必要があるため、クリック時にトリガーされる状態。

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

1

明確な解決策はありません。私は1つのHackishソリューションを実行しました:メインコンテナにクリックイベントを適用し、クリック時に以下のコードを記述します

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

マウスを使用してクリックすると、そのクリックでevent.detail = 1になり、その要素がぼやけてアウトラインが削除され、キーボードクリックでevent.detail = 0になり、キーボードの場合は通常の動作になります

OR

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");
            }
0
pareshm