Addaw, anar a la pàgina d'inici Donar

Lliçó 3 de 10 · 15 min de lectura · Revisada el 26/10/2026

CSS per a la interacció: focus visible, objectius de punter, elements fixos i contingut emergent

Estàs llegint una lliçó oberta. Matricula't gratis per fer els tests i els exercicis, desar el teu progrés i aconseguir el certificat.

En la lliçó anterior vas veure com el CSS decideix què s'oculta, què s'injecta i en quin ordre es mostra. Aquesta lliçó s'ocupa d'una altra part del CSS que pesa igual: la que governa la interacció. L'indicador de focus, la mida dels botons, les capçaleres que es queden fixes en fer scroll i les bombolles que apareixen en passar el punter s'escriuen gairebé sempre al full d'estils, i en depenen cinc criteris: 2.4.7 Focus visible, 2.4.11 Focus no ocult (mínim), 2.4.13 Aparença del focus (AAA), 2.5.8 Mida de l'objectiu (mínim) i 1.4.13 Contingut en passar el cursor o en rebre el focus.

Un indicador de focus que funcioni sobre qualsevol fons

La pseudoclasse :focus s'aplica sempre que un element rep el focus; :focus-visible només quan el navegador considera que la persona necessita veure'l: en arribar-hi amb el teclat, en enfocar per programa després d'una acció de teclat i sempre en els camps de text. En canvi, en fer clic amb el ratolí en un botó, no s'activa. Així desapareix l'excusa de treure el contorn «perquè molesta en fer clic».

Error freqüent

/* Treu el focus a tothom, també a qui navega amb teclat */
*:focus { outline: none; }

/* Indicador fet només amb ombra: desapareix en mode de colors forçats */
.boton:focus { outline: none; box-shadow: 0 0 0 3px #7aa7ff; }

El primer incompleix 2.4.7 en tot el web d'una tirada. El segon sembla correcte, però els modes de colors forçats eliminen box-shadow, i el focus desapareix just per a les persones que més el necessiten (ho veuràs a fons en la lliçó següent). A més, un blau clar sobre fons blanc no arriba al 3:1 de 1.4.11 Contrast no textual.

Una base robusta fa servir outline, que no altera la mida de la caixa, segueix el border-radius en els navegadors actuals i sobreviu als colors forçats. Perquè l'indicador es vegi sobre fons clars, foscos i fotografies, combina un contorn fosc amb un halo clar:

:focus-visible {
  outline: 3px solid #1a1a1a;
  outline-offset: 0;
  box-shadow: 0 0 0 6px #ffffff; /* halo clar per fora del contorn */
}

Queda un anell fosc de 3 píxels envoltat d'un altre de clar. Si els colors forçats eliminen l'ombra, el contorn continua allà amb el color del sistema.

Quant focus és suficient

  • 2.4.7 (AA) només demana que el focus sigui visible. 1.4.11 afegeix que l'indicador, com a informació visual necessària per identificar un estat, tingui un contrast d'almenys 3:1 amb els colors adjacents.
  • 2.4.13 Aparença del focus (AAA) concreta una mesura: una àrea com a mínim equivalent a un perímetre de 2 píxels CSS al voltant del component i un contrast de 3:1 entre l'estat enfocat i el no enfocat. Un contorn sòlid de 2 o 3 píxels amb bon contrast el compleix amb escreix; un subratllat fi o un lleuger canvi de color de fons, no.

Que el focus no quedi tapat: capçaleres fixes, barres i avisos

2.4.11 Focus no ocult (mínim) (AA, nou a WCAG 2.2) exigeix que, quan un component rep el focus, no quedi completament ocult per contingut creat per l'autor. La seva versió AAA, 2.4.12 Focus no ocult (millorat), demana que no en quedi oculta cap part. Els culpables habituals són elements amb position: sticky o position: fixed: la capçalera sticky (enganxosa: es queda fixa a dalt en desplaçar la pàgina), la barra d'accions inferior en mòbil, el bàner de galetes, el giny de xat i el botó «torna a dalt».

Quan la persona prem Maj + Tab per tornar cap amunt, el navegador desplaça la pàgina el just perquè l'element enfocat entri a la finestra… i el deixa exactament sota la capçalera fixa. La solució és en CSS: scroll-padding al contenidor de desplaçament (normalment html) reserva un marge que el navegador respecta en desplaçar-se cap a un element enfocat o cap a una àncora.

Exemple

Seu electrònica amb una capçalera fixa i una barra inferior amb el botó «Continua el tràmit»:

:root {
  --alto-cabecera: 4.5rem;
  --alto-barra: 4rem;
}
html {
  scroll-padding-top: calc(var(--alto-cabecera) + 1rem);
  scroll-padding-bottom: calc(var(--alto-barra) + 1rem);
}
.cabecera { position: sticky; top: 0; min-height: var(--alto-cabecera); }
.barra-tramite { position: fixed; bottom: 0; min-height: var(--alto-barra); }

/* Amb zoom alt o pantalles baixes, la capçalera deixa de ser fixa */
@media (max-height: 30em) {
  .cabecera { position: static; }
  html { scroll-padding-top: 1rem; }
}

L'última regla és clau: al 400 % de zoom en un portàtil, la finestra fa uns 200 píxels CSS d'alçada; una capçalera fixa de 72 píxels es menjaria un terç de la pantalla. Deixar-la anar millora alhora 2.4.11 i 1.4.10 Reajustament dels elements.

Si l'alçada de la capçalera canvia, fes servir unitats rem o actualitza la variable amb un ResizeObserver. Per als bàners i avisos no modals, la regla és senzilla: mentre siguin a la pantalla, no han de tapar els controls; reserva'ls espai o fes que es tanquin amb una acció simple i que no tornin a aparèixer.

Prova-ho tu

Obre un web amb capçalera fixa (un diari o una botiga en línia), baixa fins al peu i recorre la pàgina cap amunt amb Maj + Tab. Compta quantes vegades el focus queda completament ocult sota la capçalera. Després, a les eines de desenvolupament, afegeix scroll-padding-top a l'element html amb l'alçada de la capçalera i repeteix-ho: el problema desapareix sense tocar l'HTML.

Objectius de punter d'almenys 24 per 24

2.5.8 Mida de l'objectiu (mínim) (AA, nou a WCAG 2.2) exigeix que els objectius de punter facin almenys 24 per 24 píxels CSS, amb excepcions: que tinguin prou espai (un cercle de 24 píxels de diàmetre centrat en cada objectiu petit no talla cap altre objectiu ni el seu cercle), que hi hagi un control equivalent que sí que compleixi, que estiguin dins d'un text (un enllaç en una frase), que la mida la decideixi el navegador sense modificació de l'autor o que la presentació sigui essencial. La versió AAA, 2.5.5 Mida de l'objectiu (millorat), puja a 44 per 44, una xifra propera a les recomanacions d'iOS i Android per a pantalles tàctils.

Amb la mida de lletra per defecte, 24 píxels CSS són 1.5rem. Els errors típics: botons d'icona (tancar, eliminar), fletxes de carrusel, punts de paginació i enllaços del peu apilats. No cal fer més gran el dibuix, sinó la zona activa.

/* Icona de 16 px dins d'un botó que fa 24 x 24 o més */
.boton-icono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  min-height: 1.5rem;
  padding: 0.25rem;
}

/* Ampliar la zona activa sense canviar l'aspecte */
.punto-paginacion { position: relative; width: 0.75rem; height: 0.75rem; }
.punto-paginacion::after {
  content: "";
  position: absolute;
  inset: -0.375rem; /* 12 px + 6 px per cada costat = 24 px */
}

El pseudoelement forma part de l'element a efectes de clic, així que amplia la zona que es pot prémer. Comprova que les zones ampliades no se superposin amb les dels controls veïns.

Contingut que apareix amb el punter o amb el focus

1.4.13 Contingut en passar el cursor o en rebre el focus (AA) s'aplica a tot contingut addicional que apareix en passar el punter o en enfocar alguna cosa (bombolles d'ajuda, submenús, previsualitzacions) i exigeix tres coses:

  1. Descartable: es pot tancar sense moure el punter ni el focus, normalment amb Escape, tret que no tapi res ni comuniqui un error.
  2. S'hi pot passar el punter per sobre: si apareix amb hover, la persona pot moure el punter fins a ell sense que desaparegui. Qui fa servir una lupa de pantalla ho necessita per llegir-lo.
  3. Persistent: continua visible fins que es treu el punter o el focus, es descarta o deixa de ser vàlid.

Una bombolla feta només amb CSS sol fallar en les tres: apareix únicament amb :hover, deixa un buit entre el disparador i la bombolla pel qual «cau» el punter i no es tanca amb Escape.

/* Incorrecte: només ratolí i amb un buit de 8 px */
.ayuda:hover .burbuja { display: block; margin-top: 8px; }

/* Millor: també amb el focus, sense buit i amb una petita demora en tancar */
.burbuja { visibility: hidden; position: absolute; top: 100%; padding-top: 0.5rem;
           transition: visibility 0s linear 300ms; }
.ayuda:hover .burbuja,
.ayuda:focus-within .burbuja { visibility: visible; transition-delay: 0s; }
.ayuda.descartada .burbuja { visibility: hidden; }

El farciment superior (en lloc del marge) fa que la bombolla comenci enganxada al disparador, i la demora de 300 mil·lisegons perdona els moviments en diagonal, cosa que també agraeixen els submenús desplegables. La condició «descartable» necessita una línia de JavaScript que afegeixi la classe descartada en prémer Escape; el patró complet és al curs de components interactius. L'atribut title queda fora del criteri perquè la seva bombolla la controla el navegador, però no és una alternativa: no apareix amb el teclat ni en pantalles tàctils.

Punt clau

La interacció es programa en CSS tant com en JavaScript: outline a :focus-visible amb bon contrast, scroll-padding perquè cap barra fixa no tapi el focus, zones actives de 24 píxels CSS com a mínim i contingut emergent que aparegui també amb el focus, que es pugui recórrer amb el punter i que es tanqui amb Escape.

Resum

  • Fes servir :focus-visible amb un outline d'almenys 2-3 píxels i un contrast de 3:1; no confiïs només en box-shadow.
  • Les capçaleres i barres fixes no poden tapar el focus (2.4.11): reserva'n l'espai amb scroll-padding i deixa-les anar amb zoom alt.
  • 2.5.8 demana objectius de 24 per 24 píxels CSS o un espai equivalent; amplia la zona activa amb farciment o pseudoelements.
  • El contingut que apareix amb hover o focus ha de ser descartable, recorrible amb el punter i persistent (1.4.13).

Portes 5 lliçons d'aquest curs: que no es perdin

Crea el teu compte gratis i desa el que ja has llegit i segueix el curs amb tot:

  • El test d'aquesta lliçó (3 preguntes) per comprovar el que has après
  • Exercicis pràctics amb pàgines reals
  • El teu progrés desat: continues on ho vas deixar, des de qualsevol dispositiu
  • Constància del curs amb les hores i certificat gratuït del nivell 3 quan aprovis l'examen

Entres amb el teu compte de Google o només amb el teu correu electrònic. No cal contrasenya.