Jak používat CSS stav :focus

Publikováno: 28.3.2018

Proč je důležité stylovat stav :focus. Jak toho automaticky docílit a jaké jsou s tím problémy.

Celý článek

Text vyšel původně na autorově webu.

Odkazy, <input>y, tlačítka a všechny ostatní libovolné elementy s nezáporným atributem tabindex mohou mít :focus stav.

V praxi to znamená, že po kliknutí nebo odTabování je daný element zaměřitelný přes selektor :focus.

a:focus {
  /* styl vybraného odkazu */
}

Pro uživatele používající klávesnici je to dost užitečné, protože hezky vidí, kde se nacházejí. Dobrá ovladatelnost jen z klávesnice bývá u dobře přístupných webů samozřejmostí.

Výchozí :focus

Prakticky všechny novější prohlížeče se snaží focusovaný element nějak zvýraznit, aby to uživatel poznal.

Chrome a Opera tak činí 5px modrým rámečkem. Edge a Firefox potom 1px černým tečkovaným. Orámování je řešené vlastností outline. Ta dělá něco jako border, jen:

  1. Neovlivňuje obsah elementu, ale rámeček se dostane mimo.
  2. Může dosáhnout i nepravidelných tvarů (v Opeře a Chrome).
  3. Vyleze i přes nastavené oříznutí přes overflow: hidden.

Pokud tedy autor CSS do výchozího :focusu nezasahuje, má od tvůrců prohlížečů tuto schopnost úplně „zadarmo“. Pro překled se podívejte na Default Browser Focus Outline Styles, kde najdete přehled :focus stylů napříč prohlížeči.

Vlastní styl pro :focus

Bohužel ne vždy si jde s výchozím stylem vystačit. Trpí několika problémy:

  1. Nemusí vizuálně ladit k designu webu. Nebo nemusí být dostatečně kontrastní k pozadí na daném místě stránky.
  2. Vzhled se liší napříč prohlížeči.
  3. V některý případech se nehodí k tvaru tlačítek / ovládacích prvků. Typicky třeba u tlačítek s kulatými okraji.

Vypnutí výchozího rámečku tlačítka

Prosím vypnout ten ošklivý rámeček kolem tlačítek, který tam zůstává po kliknutí.

Bývají častá slova autora vizuálního návrhu při pohledu na jeho podobu převedenou do prohlížeče.

Návrhy vzhledu webů od grafiků se stavy pro :focus bývají spíš výjimkou než pravidlem (autor článku se s nakresleným :focus stavem ještě nesetkal), takže se na to snadno zapomene.

Jak vypnout?

:focus {
  outline: none;
}

Tento kód bohužel vylévá vaničku i s dítětem. Místo ošklivého rámečku nebude označení :focusu žádné a uživatel se při použití Tabztratí na stránce.

Skoro automatický :focus

Pokud se člověku nechce vymýšlet další styl prvků, je relativně dobré řešení převzít styl :hoveru (ten občas grafici namalují) a použít ho i pro :focus.

a:hover,
a:focus {
  /* styly pro :hover i :focus */
}

Stavy se sice od sebe nebudou lišit (to je trochu škoda), ale je to skoro bez práce. Postcss-hocus je filtr pro PostCSS, který umožní oba stavy napsat na jeden řádek.

V dávných dobách se do tohoto předpisu přidávala i třída :active, protože starší IE ji používal pro odkazy zaměřené Tabem. V roce 2017 a později už je to ale zbytečné až nežádoucí.

Stav :active (po stisknutí tlačítka myši) by měl být ovšem rovněž vizuálně navržen a měl by mít jiný vzhled než :hover.

Jaký styl pro :focus?

Nabízí se třeba změnit barvu nebo přidat rámeček okolo – pomocí outline.

Je-li potřeba rámeček s kulatými rohy, jde k tomu hezky použít 1px stín vytvořený vlastností box-shadow.

Zůstávání :focusu po kliknutí

Bohužel i při pečlivém návrhu se při střetu s realitou zjistí smutná věc.

Vlastní :focus styl se chová jinak. Dá se říct, že jeho současná implementace ve většině prohlížečů je rozbitá.

Některé prvky po vybrání myší sice získají :focus, ale výchozí outline prohlížeče se vůbec nezobrazí – zobrazí se jen při zaměření prvků klávesnicí.

Odlišné chování při zaměření myší a klávesnicí se týká:

  • odkazů,
  • tlačítek (<button> i <input type=submit>),
  • zaškrtávacích polí typu checkbox a radio,
  • volby rozsahu (<input type=range>),
  • možná ještě něčeho?

Tyto elementy po kliknutí myší :focusovaný stav nemají.

Naopak následující :focusovatelné prvky mají outline i po kliknutí:

  1. skoro všechny textové, číslené, telefonní a podobné <input>y,
  2. <textarea>,
  3. <select>,
  4. obecný element s tabindexem (kromě -1)

Styl :focusovaného elementu po kliknutí může vypadat rušivě. Navíc se v tomto chování liší od výchozího chování v prohlížečích.

Jediné, co jde bezpečně měnit, aby styl pro :focus po kliknutí nezůstal, je outline-color. Změny jiných vlastností se projeví i po kliknutí.

(Ne)řešení

Nějaké univerzální jednoduché řešení moc neexistuje. Nejsnazší je obvyklé nic nedělání: měnit u výchozího rámečku jen barvu nebo vůbec nic.

Jinak je potřeba využít JavaScript:

Vyvolání události blur

Po kliknutí na prvek u něj okamžitě zavolat blur() a tím zrušit :focus.

$('a, button, input[type=checkbox], input[type=radio]').click(
  function () {
    $(this).blur();
  }
);

Vypadá to relativně funkčně — dokonce si prohlížeče mimo MS Edge i pamatují, kde skončilo Tabování, a jsou schopny navázat.

Bohužel to trochu mění chování, protože prvky po kliknutí už skutečně ztratí focus – takže třeba zaškrtávátko checkbox už nepůjde znovu odškrtnout/zaškrtnout Mezerníkem. Stejně tak tlačítko <button> nepůjde z klávesnice vícekrát zmáčknou, to bude zvlášť problém u +/− tlačítek.

A trochu bych se bál, že to bude přinášet obtížně zjistitelné problémy do budoucna.

Přepínání tříd

Nabízí se myšlenka třeba při kliknutí myší na políčko (onmousedown) přidat elementu třídu typu is-mouse-focus a při onbluru ji zase odebírat.

V selektoru pro :focus potom použít ještě :not, aby se styly v tomto případě neaplikovaly.

Bohužel současná pravidla v prohlížečích jsou tak komplexní, že to úplně jednoduše zapsat nejde. Například zůstávání :focusu se liší u jednotlivých typů <input>ů – tlačítka, checkboxy, radia nebo rozsahy :focus mít nemají, ale všechno ostatní ano.

Dále je možné prvek :focusovat i kliknutím jinam, tj. přes značku <label>.

Touto problematikou se zabývají následující stránky:

Pseudotřída :focus-ring

Specifikace (draft) CSS 4 selektorů počítá s doplněním :focusu o :focus-ring. Selectors Level 4: The Input Focus-Ring Pseudo-class: :focus-ring.

Až bude fungovat, bude se pravděpodobně používat místo současného :focusu.

Tato pseudotřída dokáže v závislosti na použitém rozhraní (myš/klávesnice/dotyk) určit, jestli je žádoucí, aby se zobrazilo zvýraznění. Půjde tak docílit vlastního vzhledu, který se ale bude chovat jako současný nativní outline.

element:focus-ring {
  /* libovolné styly pro :focus */
}

Polyfill pro :focus-ring

Existuje hotový maličký JS polyfill, který daným prvkům nastavuje CSS třídu focus-ring ve stejných případech, jako prohlížeče výchozí outlinePolyfill for `:focus-ring` – stránka polyfillu s ukázkou.

Ve Firefoxu :moz-focusring

Ve Firefoxu už funguje tato vlastnost s prefixem a psaná bez spojovníku.

Knihovna What Input

Hotové JS řešení What Input? dokáže stránce přiřazovat atributy podle toho, zda se vstup provedl myší nebo z klávesnice. V případě, že proběhl myší, jde tak výchozí :focus v některých případech potlačit.

Focus uvnitř :focus-within

Docela novinka, ale podporovaná už v současných verzích většiny prohlížečů (kromě Edge a Android Browser).

Na nějakém rodičovském prvku (třeba značce <form>) jde zjistit, jestli nemá :focus něco uvnitř.

form:focus-within {
  box-shadow: 0 0 5px 0 red;
}

Takový formulář během vyplňování políček získá červený stín.

Odkazy

Nahoru
Tento web používá k poskytování služeb a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tímto souhlasíte. Další informace