CSS

CSS

Tutorial CSS: Accesibilidad web con CSS

Aprende a mejorar la accesibilidad web con CSS usando contraste de color, estilos de foco, media queries y patrones de diseño accesibles.

Aprende CSS y certifícate

Contraste de color y variables para temas accesibles

El contraste de color es uno de los pilares fundamentales de la accesibilidad web. Un contraste adecuado entre texto y fondo permite que personas con diferentes capacidades visuales puedan percibir y comprender el contenido de nuestra página. Combinado con las variables CSS, podemos crear temas accesibles que se adapten a diferentes necesidades.

Fundamentos del contraste de color

El contraste se refiere a la diferencia de luminosidad entre dos colores adyacentes. Para que un texto sea legible, necesita tener suficiente contraste con su fondo. Las Pautas de Accesibilidad para el Contenido Web (WCAG) establecen criterios específicos:

  • Nivel AA: Requiere una relación de contraste mínima de 4.5:1 para texto normal y 3:1 para texto grande
  • Nivel AAA: Requiere una relación de contraste mínima de 7:1 para texto normal y 4.5:1 para texto grande

Veamos un ejemplo de contraste insuficiente versus adecuado:

/* Contraste insuficiente */
.low-contrast {
  color: #767676;
  background-color: #EEEEEE;
  /* Relación de contraste aproximada: 2.5:1 */
}

/* Contraste adecuado (nivel AA) */
.good-contrast {
  color: #595959;
  background-color: #FFFFFF;
  /* Relación de contraste aproximada: 4.5:1 */
}

/* Contraste excelente (nivel AAA) */
.excellent-contrast {
  color: #333333;
  background-color: #FFFFFF;
  /* Relación de contraste aproximada: 8:1 */
}

Variables CSS para temas accesibles

Las variables CSS (también llamadas propiedades personalizadas) son una herramienta poderosa para crear temas accesibles. Nos permiten definir valores que podemos reutilizar y modificar fácilmente en toda nuestra hoja de estilos.

La sintaxis básica para definir y usar variables CSS es:

:root {
  --variable-name: value;
}

.selector {
  property: var(--variable-name);
}

Podemos aprovechar estas variables para crear un sistema de colores accesible:

:root {
  /* Colores base */
  --color-text: #333333;
  --color-background: #FFFFFF;
  --color-primary: #0056b3;
  --color-secondary: #6c757d;
  --color-accent: #e91e63;
  
  /* Elementos interactivos */
  --color-link: #0056b3;
  --color-link-hover: #003d7a;
  --color-button-bg: #0056b3;
  --color-button-text: #FFFFFF;
}

body {
  color: var(--color-text);
  background-color: var(--color-background);
}

a {
  color: var(--color-link);
}

a:hover {
  color: var(--color-link-hover);
}

.button {
  background-color: var(--color-button-bg);
  color: var(--color-button-text);
}

Creando temas alternativos con variables CSS

Una de las grandes ventajas de usar variables CSS es la capacidad de crear temas alternativos que podemos aplicar fácilmente. Esto es especialmente útil para ofrecer un modo oscuro o un modo de alto contraste para usuarios con necesidades visuales específicas.

/* Tema claro (predeterminado) */
:root {
  --color-text: #333333;
  --color-background: #FFFFFF;
  --color-surface: #F5F5F5;
  --color-border: #DDDDDD;
  --color-primary: #0056b3;
}

/* Tema oscuro */
.dark-theme {
  --color-text: #EEEEEE;
  --color-background: #121212;
  --color-surface: #1E1E1E;
  --color-border: #333333;
  --color-primary: #4D9FFF;
}

/* Tema de alto contraste */
.high-contrast-theme {
  --color-text: #FFFFFF;
  --color-background: #000000;
  --color-surface: #000000;
  --color-border: #FFFFFF;
  --color-primary: #FFFF00;
}

Con esta estructura, podemos cambiar todo el tema de nuestra aplicación simplemente añadiendo una clase al elemento <html> o <body>:

/* Aplicamos los estilos usando las variables */
body {
  color: var(--color-text);
  background-color: var(--color-background);
}

.card {
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
}

.button-primary {
  background-color: var(--color-primary);
  color: var(--color-text);
}

Implementando un selector de temas

Podemos implementar un selector de temas que permita a los usuarios elegir el que mejor se adapte a sus necesidades:

/* Definimos los temas como antes */
:root {
  /* Variables del tema claro */
  --color-text: #333333;
  --color-background: #FFFFFF;
  /* Más variables... */
}

.dark-theme {
  /* Variables del tema oscuro */
  --color-text: #EEEEEE;
  --color-background: #121212;
  /* Más variables... */
}

.high-contrast-theme {
  /* Variables del tema de alto contraste */
  --color-text: #FFFFFF;
  --color-background: #000000;
  /* Más variables... */
}

/* Transición suave entre temas */
body {
  color: var(--color-text);
  background-color: var(--color-background);
  transition: background-color 0.3s ease, color 0.3s ease;
}

Verificación del contraste

Es importante verificar que nuestros colores cumplen con los requisitos de contraste. Aunque existen herramientas online para esto, también podemos crear una guía visual en nuestro CSS:

/* Guía de contraste */
.contrast-guide {
  /* Nivel AA (4.5:1) para texto normal */
  --aa-normal-light-on-dark: #959595 on #000000;
  --aa-normal-dark-on-light: #707070 on #FFFFFF;
  
  /* Nivel AAA (7:1) para texto normal */
  --aaa-normal-light-on-dark: #B7B7B7 on #000000;
  --aaa-normal-dark-on-light: #595959 on #FFFFFF;
}

Variables para espaciado y tamaños accesibles

La accesibilidad no se limita solo al contraste de color. También podemos usar variables CSS para definir tamaños de texto y espaciados que favorezcan la legibilidad:

:root {
  /* Tamaños de texto accesibles */
  --font-size-base: 16px;
  --font-size-large: 1.25rem;
  --font-size-xlarge: 1.5rem;
  --font-size-small: 0.875rem;
  
  /* Espaciado para mejorar legibilidad */
  --line-height: 1.5;
  --paragraph-spacing: 1.5rem;
  --letter-spacing: 0.01em;
}

body {
  font-size: var(--font-size-base);
  line-height: var(--line-height);
  letter-spacing: var(--letter-spacing);
}

h1 {
  font-size: var(--font-size-xlarge);
  margin-bottom: var(--paragraph-spacing);
}

p {
  margin-bottom: var(--paragraph-spacing);
}

Ejemplo práctico: Sistema de colores accesible completo

Veamos un ejemplo más completo de un sistema de colores accesible usando variables CSS:

:root {
  /* Colores base */
  --color-black: #000000;
  --color-white: #FFFFFF;
  
  /* Paleta de grises */
  --color-gray-100: #F8F9FA;
  --color-gray-200: #E9ECEF;
  --color-gray-300: #DEE2E6;
  --color-gray-400: #CED4DA;
  --color-gray-500: #ADB5BD;
  --color-gray-600: #6C757D;
  --color-gray-700: #495057;
  --color-gray-800: #343A40;
  --color-gray-900: #212529;
  
  /* Colores semánticos (tema claro) */
  --color-text: var(--color-gray-900);
  --color-text-muted: var(--color-gray-600);
  --color-background: var(--color-white);
  --color-surface: var(--color-gray-100);
  --color-border: var(--color-gray-300);
  
  /* Colores de acento */
  --color-primary: #0056b3;
  --color-primary-light: #4D9FFF;
  --color-primary-dark: #003d7a;
  
  /* Colores de estado */
  --color-success: #28a745;
  --color-warning: #ffc107;
  --color-danger: #dc3545;
  --color-info: #17a2b8;
  
  /* Espaciado y tamaños */
  --font-size-base: 16px;
  --spacing-unit: 0.5rem;
}

/* Tema oscuro */
.dark-theme {
  --color-text: var(--color-gray-100);
  --color-text-muted: var(--color-gray-400);
  --color-background: var(--color-gray-900);
  --color-surface: var(--color-gray-800);
  --color-border: var(--color-gray-700);
  
  /* Ajustamos colores de acento para mantener contraste */
  --color-primary: var(--color-primary-light);
  
  /* Ajustamos colores de estado */
  --color-success: #5dd879;
  --color-warning: #ffda6a;
  --color-danger: #f77;
  --color-info: #6edff6;
}

/* Aplicamos los estilos */
body {
  color: var(--color-text);
  background-color: var(--color-background);
  font-size: var(--font-size-base);
}

.card {
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  padding: calc(var(--spacing-unit) * 2);
  margin-bottom: calc(var(--spacing-unit) * 3);
}

.text-muted {
  color: var(--color-text-muted);
}

.btn-primary {
  background-color: var(--color-primary);
  color: var(--color-white);
  padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);
}

Consideraciones finales

Al trabajar con contraste de color y variables para temas accesibles, es importante:

  • Probar con usuarios reales o herramientas de simulación de discapacidad visual
  • Mantener la consistencia en toda la interfaz
  • No confiar solo en el color para transmitir información importante
  • Documentar el sistema de variables para que otros desarrolladores puedan entenderlo y usarlo correctamente
  • Revisar periódicamente que los contrastes siguen cumpliendo con los estándares WCAG

Con estas técnicas, podemos crear interfaces que no solo sean visualmente atractivas, sino también inclusivas y accesibles para todos los usuarios.

Estilos para estados de foco y navegación por teclado

La navegación por teclado es fundamental para muchos usuarios que no pueden utilizar un ratón, incluyendo personas con discapacidades motoras, usuarios de lectores de pantalla y aquellos que prefieren el teclado por eficiencia. Diseñar estilos adecuados para los estados de foco es una parte esencial de la accesibilidad web.

Importancia del indicador de foco

El indicador de foco es una señal visual que muestra qué elemento de la página está actualmente seleccionado cuando navegamos con el teclado (usando la tecla Tab). Por defecto, los navegadores muestran un contorno (outline) alrededor del elemento enfocado, pero este estilo básico:

  1. A menudo es eliminado por desarrolladores por razones estéticas
  2. Puede tener un contraste insuficiente en algunos contextos
  3. No siempre es consistente entre navegadores

Veamos cómo mejorar estos indicadores de foco:

/* Nunca elimines el outline sin proporcionar una alternativa */
:focus {
  outline: 2px solid #4d90fe;
  outline-offset: 2px;
}

La propiedad outline-offset crea un espacio entre el elemento y su contorno, mejorando la visibilidad.

Diferenciando el foco del ratón y del teclado

En CSS moderno, podemos usar la pseudo-clase :focus-visible para aplicar estilos de foco solo cuando el usuario navega con teclado, manteniendo una experiencia limpia para usuarios de ratón:

/* Estilo básico para todos los elementos enfocados */
:focus {
  outline: none;
}

/* Estilo mejorado solo para navegación con teclado */
:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 2px;
  box-shadow: 0 0 0 6px rgba(26, 115, 232, 0.2);
}

/* Soporte para navegadores más antiguos */
@supports not selector(:focus-visible) {
  :focus {
    outline: 3px solid #1a73e8;
    outline-offset: 2px;
  }
}

Estilos de foco para diferentes componentes

Diferentes elementos de interfaz pueden beneficiarse de estilos de foco personalizados:

Enlaces y botones

a:focus-visible,
button:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 2px;
  border-radius: 4px;
  text-decoration: underline;
}

/* Botones con fondo oscuro necesitan un outline más claro */
.dark-button:focus-visible {
  outline-color: #78aeff;
}

Campos de formulario

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid #1a73e8;
  border-color: #1a73e8;
  box-shadow: 0 0 0 4px rgba(26, 115, 232, 0.25);
}

/* Checkbox y radio buttons */
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

Tarjetas y contenedores

.card:focus-visible,
.interactive-container:focus-visible {
  outline: 2px dashed #1a73e8;
  outline-offset: 4px;
}

Mejorando la visibilidad con transiciones

Las transiciones pueden hacer que el indicador de foco sea más notorio, especialmente útil para usuarios con discapacidades cognitivas o atención limitada:

.button {
  position: relative;
  transition: transform 0.2s ease;
}

.button:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  transform: scale(1.05);
}

/* Efecto de pulso para mayor visibilidad */
.button:focus-visible::after {
  content: '';
  position: absolute;
  top: -4px;
  left: -4px;
  right: -4px;
  bottom: -4px;
  border-radius: inherit;
  animation: pulse 1.5s infinite;
  z-index: -1;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(26, 115, 232, 0.4);
  }
  70% {
    box-shadow: 0 0 0 8px rgba(26, 115, 232, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(26, 115, 232, 0);
  }
}

Orden de tabulación lógico

El orden de tabulación es crucial para una navegación por teclado intuitiva. Por defecto, los elementos reciben el foco en el orden en que aparecen en el HTML. Sin embargo, a veces necesitamos modificar este comportamiento:

/* Elementos que no deben recibir foco */
.decorative-element {
  tabindex: -1;
}

/* Elementos interactivos que no son nativamente enfocables */
.custom-dropdown {
  tabindex: 0;
}

Es importante recordar que:

  • tabindex="0" incluye un elemento en el orden natural de tabulación
  • tabindex="-1" excluye un elemento del orden de tabulación pero permite enfocarlo con JavaScript
  • tabindex="1+" (valores positivos) fuerza un orden específico, pero debe evitarse ya que puede confundir a los usuarios

Los enlaces de salto (skip links) permiten a los usuarios de teclado saltar directamente al contenido principal, evitando tener que tabular a través de menús de navegación extensos:

.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #1a73e8;
  color: white;
  padding: 8px;
  z-index: 100;
  transition: top 0.2s ease;
}

.skip-link:focus {
  top: 0;
}

Este estilo mantiene el enlace oculto visualmente hasta que recibe el foco, momento en el que aparece en la parte superior de la página.

Indicadores de foco personalizados

Podemos crear indicadores de foco personalizados que se integren mejor con el diseño de nuestra interfaz:

/* Indicador de foco con subrayado animado */
.nav-link:focus-visible {
  outline: none;
}

.nav-link:focus-visible::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 2px;
  background-color: currentColor;
  transform: scaleX(0);
  transition: transform 0.3s ease;
  transform-origin: left;
  animation: expand 0.3s forwards;
}

@keyframes expand {
  to {
    transform: scaleX(1);
  }
}

Manejo de componentes complejos

Para componentes interactivos complejos como menús desplegables, carruseles o diálogos, es importante gestionar correctamente el foco:

/* Contenedor de menú desplegable */
.dropdown {
  position: relative;
}

/* Botón que activa el menú */
.dropdown-toggle:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

/* Menú desplegable */
.dropdown-menu {
  display: none;
}

/* Cuando el menú está abierto */
.dropdown.open .dropdown-menu {
  display: block;
}

/* Elementos del menú */
.dropdown-item:focus-visible {
  outline: none;
  background-color: #e8f0fe;
  color: #1a73e8;
}

Estilos para diferentes estados de interacción

Es importante diferenciar visualmente entre los distintos estados de interacción:

.button {
  background-color: #1a73e8;
  color: white;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
}

/* Estado hover (ratón) */
.button:hover {
  background-color: #1765cc;
}

/* Estado focus (teclado) */
.button:focus-visible {
  outline: 3px solid #78aeff;
  outline-offset: 2px;
}

/* Estado active (clic/pulsación) */
.button:active {
  background-color: #155db9;
  transform: translateY(1px);
}

/* Estado disabled */
.button:disabled {
  background-color: #ccc;
  color: #666;
  cursor: not-allowed;
}

Pruebas de navegación por teclado

Para verificar que nuestros estilos de foco funcionan correctamente, debemos realizar pruebas de navegación por teclado:

  1. Presionar Tab para navegar hacia adelante
  2. Shift+Tab para navegar hacia atrás
  3. Enter/Space para activar elementos
  4. Flechas para interactuar con componentes como menús o sliders

Ejemplo práctico: Menú de navegación accesible

Veamos un ejemplo completo de un menú de navegación accesible con estilos de foco mejorados:

.nav {
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav-item {
  position: relative;
}

.nav-link {
  display: block;
  padding: 12px 16px;
  color: #333;
  text-decoration: none;
  transition: color 0.2s;
}

/* Estilos para hover */
.nav-link:hover {
  color: #1a73e8;
}

/* Estilos para foco */
.nav-link:focus {
  outline: none;
}

.nav-link:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: -2px;
  border-radius: 4px;
  color: #1a73e8;
}

/* Indicador visual adicional */
.nav-link:focus-visible::before {
  content: '';
  position: absolute;
  bottom: 6px;
  left: 16px;
  right: 16px;
  height: 2px;
  background-color: #1a73e8;
}

/* Estado activo */
.nav-link.active {
  font-weight: bold;
  color: #1a73e8;
}

/* Elemento actual */
.nav-link[aria-current="page"] {
  font-weight: bold;
  color: #1a73e8;
}

Consideraciones para dispositivos táctiles

En dispositivos táctiles, el foco visual funciona de manera diferente. Es importante asegurarse de que nuestros estilos sean adecuados para todos los dispositivos:

/* Estilos base para todos los dispositivos */
.button {
  padding: 8px 16px;
  background: #1a73e8;
  color: white;
  border: none;
  border-radius: 4px;
}

/* Estilos específicos para dispositivos táctiles */
@media (hover: none) and (pointer: coarse) {
  .button {
    padding: 12px 20px; /* Área táctil más grande */
  }
  
  /* Evitamos efectos hover en dispositivos táctiles */
  .button:hover {
    background: #1a73e8; /* Mismo que el estado normal */
  }
}

Compatibilidad con navegadores antiguos

Para navegadores que no soportan :focus-visible, podemos usar un enfoque progresivo:

/* Estilo base para todos los navegadores */
:focus {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

/* Mejora para navegadores modernos */
:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(26, 115, 232, 0.2);
}

Este enfoque garantiza que todos los usuarios tengan una experiencia accesible, independientemente del navegador que utilicen.

Media queries para preferencias de usuario (reducción de movimiento, contraste)

Las media queries son una herramienta fundamental en CSS que nos permite aplicar estilos específicos según las características del dispositivo o las preferencias del usuario. Más allá de adaptar nuestros diseños a diferentes tamaños de pantalla, podemos utilizarlas para mejorar la accesibilidad respondiendo a las preferencias específicas de los usuarios.

Media queries basadas en preferencias

CSS moderno incluye media queries que detectan las preferencias configuradas por los usuarios en sus sistemas operativos o navegadores. Estas consultas nos permiten crear experiencias más inclusivas y accesibles sin requerir configuración adicional por parte del usuario.

/* Estos estilos se aplicarán según las preferencias del usuario */
@media (prefers-reduced-motion: reduce) {
  /* Estilos para usuarios que prefieren menos movimiento */
}

@media (prefers-color-scheme: dark) {
  /* Estilos para usuarios que prefieren modo oscuro */
}

@media (prefers-contrast: more) {
  /* Estilos para usuarios que prefieren mayor contraste */
}

Reducción de movimiento (prefers-reduced-motion)

La media query prefers-reduced-motion detecta si el usuario ha configurado su sistema para reducir o eliminar animaciones y movimientos. Esto es especialmente importante para personas con trastornos vestibulares, sensibilidad visual o condiciones como TDAH, para quienes las animaciones pueden causar mareos, náuseas o distracciones.

Esta media query tiene dos valores posibles:

  • reduce: El usuario prefiere menos movimiento
  • no-preference: El usuario no ha expresado preferencia

Veamos cómo implementarla:

/* Animación estándar */
.card {
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.card:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}

/* Respetamos la preferencia de reducción de movimiento */
@media (prefers-reduced-motion: reduce) {
  .card {
    transition: none;
  }
  
  .card:hover {
    transform: none;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  }
}

Para animaciones más complejas con @keyframes, también debemos adaptarlas:

/* Animación de carga giratoria */
@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.loader {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

/* Alternativa sin movimiento para usuarios que lo prefieren */
@media (prefers-reduced-motion: reduce) {
  .loader {
    animation: none;
    border: 4px solid #f3f3f3;
    border-top: 4px solid #3498db;
    border-left: 4px solid #3498db;
  }
}

Enfoque progresivo para reducción de movimiento

Una buena práctica es adoptar un enfoque progresivo donde comenzamos con animaciones mínimas o nulas y las añadimos solo para usuarios que no tienen preferencia por reducir el movimiento:

/* Por defecto, sin animaciones */
.button {
  background-color: #0056b3;
  color: white;
  border: none;
  padding: 10px 20px;
  /* Sin transiciones por defecto */
}

/* Añadimos animaciones solo si el usuario no prefiere reducirlas */
@media (prefers-reduced-motion: no-preference) {
  .button {
    transition: background-color 0.2s, transform 0.1s;
  }
  
  .button:hover {
    background-color: #003d7a;
    transform: scale(1.05);
  }
}

Preferencias de esquema de color (prefers-color-scheme)

La media query prefers-color-scheme detecta si el usuario prefiere un tema claro u oscuro en su sistema operativo. Aunque ya vimos variables CSS para implementar temas en la sección anterior, esta media query nos permite activarlos automáticamente según las preferencias del usuario:

:root {
  /* Tema claro (predeterminado) */
  --color-text: #333333;
  --color-background: #ffffff;
  --color-primary: #0056b3;
  --color-secondary: #6c757d;
}

/* Aplicamos automáticamente el tema oscuro si el usuario lo prefiere */
@media (prefers-color-scheme: dark) {
  :root {
    --color-text: #f5f5f5;
    --color-background: #121212;
    --color-primary: #4d9fff;
    --color-secondary: #a1a8ae;
  }
}

body {
  color: var(--color-text);
  background-color: var(--color-background);
}

.button-primary {
  background-color: var(--color-primary);
  color: white;
}

Preferencias de contraste (prefers-contrast)

La media query prefers-contrast detecta si el usuario ha configurado su sistema para mostrar contenido con mayor o menor contraste. Esta característica es especialmente útil para personas con baja visión o sensibilidad a ciertos contrastes.

Tiene tres valores posibles:

  • more: El usuario prefiere mayor contraste
  • less: El usuario prefiere menor contraste
  • no-preference: El usuario no ha expresado preferencia
/* Estilos base con contraste estándar */
.card {
  background-color: #f8f9fa;
  border: 1px solid #dee2e6;
  color: #212529;
}

/* Aumentamos el contraste para usuarios que lo prefieren */
@media (prefers-contrast: more) {
  .card {
    background-color: white;
    border: 2px solid black;
    color: black;
  }
  
  /* Eliminamos efectos sutiles que reducen el contraste */
  .card {
    box-shadow: none;
    text-shadow: none;
  }
  
  /* Aseguramos que los bordes sean muy visibles */
  input, button, select, textarea {
    border: 2px solid black;
    outline: 2px solid black;
  }
}

/* Reducimos el contraste para usuarios que lo prefieren */
@media (prefers-contrast: less) {
  .card {
    background-color: #fafafa;
    border-color: #eaeaea;
    color: #333333;
  }
}

Combinando media queries para mayor precisión

Podemos combinar diferentes media queries para crear experiencias aún más personalizadas:

/* Estilos para modo oscuro con alto contraste */
@media (prefers-color-scheme: dark) and (prefers-contrast: more) {
  :root {
    --color-text: white;
    --color-background: black;
    --color-primary: yellow;
    --color-border: white;
  }
  
  /* Aseguramos que los elementos interactivos sean muy visibles */
  button, a {
    border: 2px solid white;
    text-decoration: underline;
  }
}

/* Estilos para modo oscuro con reducción de movimiento */
@media (prefers-color-scheme: dark) and (prefers-reduced-motion: reduce) {
  .hero-section {
    background-image: url('static-dark-bg.jpg');
    /* En lugar de un video o animación de fondo */
  }
}

Preferencias de transparencia (prefers-reduced-transparency)

Aunque tiene menor soporte en navegadores, también existe la media query prefers-reduced-transparency para usuarios que prefieren menos efectos de transparencia:

.glass-card {
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(10px);
}

@media (prefers-reduced-transparency: reduce) {
  .glass-card {
    background-color: #ffffff;
    backdrop-filter: none;
  }
}

Implementación práctica: Sistema completo de preferencias

Veamos un ejemplo más completo que integra varias preferencias de usuario:

:root {
  /* Variables base */
  --transition-speed: 0.3s;
  --animation-duration: 1s;
  
  /* Colores - tema claro predeterminado */
  --color-text: #333333;
  --color-background: #ffffff;
  --color-surface: #f5f5f5;
  --color-primary: #0056b3;
  --color-secondary: #6c757d;
  --color-border: #dee2e6;
  
  /* Efectos */
  --shadow-small: 0 2px 4px rgba(0, 0, 0, 0.1);
  --shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.1);
  --blur-effect: blur(10px);
  --transparency-level: 0.8;
}

/* Ajustes para modo oscuro */
@media (prefers-color-scheme: dark) {
  :root {
    --color-text: #f5f5f5;
    --color-background: #121212;
    --color-surface: #1e1e1e;
    --color-primary: #4d9fff;
    --color-secondary: #a1a8ae;
    --color-border: #333333;
    
    /* Ajustamos sombras para modo oscuro */
    --shadow-small: 0 2px 4px rgba(0, 0, 0, 0.3);
    --shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.3);
  }
}

/* Ajustes para alto contraste */
@media (prefers-contrast: more) {
  :root {
    /* Maximizamos contraste */
    --color-text: black;
    --color-background: white;
    --color-surface: white;
    --color-primary: #0000ee;
    --color-secondary: #551a8b;
    --color-border: black;
    
    /* Eliminamos efectos que reducen contraste */
    --shadow-small: none;
    --shadow-medium: none;
    --blur-effect: none;
    --transparency-level: 1;
  }
  
  /* En modo oscuro con alto contraste */
  @media (prefers-color-scheme: dark) {
    :root {
      --color-text: white;
      --color-background: black;
      --color-surface: black;
      --color-primary: yellow;
      --color-secondary: #00ffff;
      --color-border: white;
    }
  }
}

/* Ajustes para reducción de movimiento */
@media (prefers-reduced-motion: reduce) {
  :root {
    --transition-speed: 0s;
    --animation-duration: 0s;
  }
}

/* Aplicamos las variables a los elementos */
body {
  color: var(--color-text);
  background-color: var(--color-background);
  transition: background-color var(--transition-speed), 
              color var(--transition-speed);
}

.card {
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-small);
  transition: transform var(--transition-speed),
              box-shadow var(--transition-speed);
}

.card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-medium);
}

.button {
  background-color: var(--color-primary);
  color: white;
  border: none;
  transition: background-color var(--transition-speed);
}

.button:hover {
  background-color: color-mix(in srgb, var(--color-primary), black 20%);
}

.glass-effect {
  background-color: rgba(255, 255, 255, var(--transparency-level));
  backdrop-filter: var(--blur-effect);
}

.loading-spinner {
  animation: spin var(--animation-duration) linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

Detección de soporte para media queries

Para asegurar la compatibilidad con navegadores más antiguos, podemos usar @supports para detectar si el navegador soporta estas media queries:

/* Enfoque por defecto */
.button {
  background-color: #0056b3;
  color: white;
  transition: none; /* Sin animación por defecto */
}

/* Comprobamos si el navegador soporta prefers-reduced-motion */
@supports ((-webkit-appearance: none) or (-moz-appearance: none)) and 
          (selector(media (prefers-reduced-motion))) {
  
  /* Si hay soporte, añadimos animaciones solo si el usuario no las ha reducido */
  @media (prefers-reduced-motion: no-preference) {
    .button {
      transition: background-color 0.2s, transform 0.1s;
    }
    
    .button:hover {
      background-color: #003d7a;
      transform: scale(1.05);
    }
  }
}

Consideraciones para implementar media queries de preferencias

Al trabajar con estas media queries, es importante tener en cuenta:

  • Prueba en diferentes sistemas operativos: Las preferencias de usuario se configuran de manera diferente en Windows, macOS, iOS, Android, etc.
  • No fuerces preferencias: Respeta siempre las preferencias del usuario y no las sobrescribas con JavaScript.
  • Proporciona controles adicionales: Además de responder a las preferencias del sistema, ofrece controles en tu interfaz para cambiar temas, contraste o animaciones.
  • Mantén la funcionalidad: Al eliminar animaciones o cambiar contrastes, asegúrate de que la funcionalidad básica siga siendo accesible.
  • Documenta las opciones: Informa a los usuarios sobre las opciones de accesibilidad disponibles en tu sitio.

Con estas media queries basadas en preferencias, podemos crear experiencias web que se adapten automáticamente a las necesidades específicas de cada usuario, mejorando significativamente la accesibilidad sin requerir configuración adicional.

Patrones de diseño accesibles con CSS

Los patrones de diseño accesibles son soluciones reutilizables que abordan problemas comunes de accesibilidad en interfaces web. Implementar estos patrones con CSS nos permite crear componentes que sean utilizables por todas las personas, independientemente de sus capacidades o dispositivos de asistencia.

Tarjetas accesibles

Las tarjetas son un componente fundamental en muchos diseños web modernos. Para hacerlas accesibles, debemos considerar varios aspectos:

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 1rem;
  background-color: #fff;
  /* Aseguramos que el borde sea visible para usuarios con baja visión */
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  /* Transición suave para estados interactivos */
  transition: transform 0.2s, box-shadow 0.2s;
}

/* Si la tarjeta es interactiva (enlace o botón) */
a.card,
button.card {
  cursor: pointer;
  text-align: left; /* Mantiene la alineación natural del texto */
  color: inherit; /* Hereda el color del texto */
  font-family: inherit; /* Hereda la fuente */
  text-decoration: none; /* Elimina el subrayado de enlaces */
}

/* Estado de foco para tarjetas interactivas */
a.card:focus-visible,
button.card:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(26, 115, 232, 0.25);
}

/* Estado hover para tarjetas interactivas */
a.card:hover,
button.card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}

Para mejorar aún más la accesibilidad, podemos añadir un indicador visual que comunique que la tarjeta es interactiva:

a.card::after,
button.card::after {
  content: "";
  position: absolute;
  top: 1rem;
  right: 1rem;
  width: 1rem;
  height: 1rem;
  background-image: url("icon-interactive.svg");
  background-size: contain;
  background-repeat: no-repeat;
}

Acordeones accesibles

Los acordeones permiten mostrar y ocultar contenido, pero deben implementarse de manera que sean utilizables con teclado y lectores de pantalla:

.accordion {
  border: 1px solid #ddd;
  border-radius: 4px;
  overflow: hidden;
}

.accordion-header {
  margin: 0;
  padding: 0;
}

.accordion-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 1rem;
  background-color: #f5f5f5;
  border: none;
  text-align: left;
  font-weight: bold;
  cursor: pointer;
}

/* Indicador visual de expansión */
.accordion-button::after {
  content: "";
  width: 0.8rem;
  height: 0.8rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s;
  margin-left: 0.5rem;
}

/* Cuando está expandido, rotamos el indicador */
.accordion-button[aria-expanded="true"]::after {
  transform: rotate(-135deg);
}

/* Estado de foco */
.accordion-button:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: -2px;
  background-color: #e8f0fe;
}

/* Panel de contenido */
.accordion-panel {
  padding: 0;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s, padding 0.3s;
}

/* Cuando está expandido */
.accordion-panel[aria-hidden="false"] {
  max-height: 500px; /* Valor arbitrario, ajustar según necesidad */
  padding: 1rem;
}

Este patrón debe complementarse con los atributos ARIA adecuados en HTML (aria-expanded, aria-controls, aria-hidden), pero el CSS proporciona las pistas visuales necesarias.

Menús desplegables accesibles

Los menús desplegables son otro componente común que requiere consideraciones de accesibilidad:

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-toggle {
  padding: 0.5rem 1rem;
  background-color: #f5f5f5;
  border: 1px solid #ddd;
  border-radius: 4px;
  cursor: pointer;
  /* Añadimos un indicador visual */
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.dropdown-toggle::after {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

/* Estado de foco */
.dropdown-toggle:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  background-color: #e8f0fe;
}

/* Menú desplegable */
.dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 10;
  min-width: 10rem;
  padding: 0.5rem 0;
  margin: 0.125rem 0 0;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
  /* Oculto por defecto */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px);
  transition: opacity 0.2s, visibility 0.2s, transform 0.2s;
}

/* Cuando está expandido */
.dropdown.open .dropdown-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Elementos del menú */
.dropdown-item {
  display: block;
  width: 100%;
  padding: 0.5rem 1rem;
  text-align: left;
  background: none;
  border: none;
  color: #333;
  text-decoration: none;
  cursor: pointer;
}

.dropdown-item:hover {
  background-color: #f5f5f5;
}

.dropdown-item:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: -2px;
  background-color: #e8f0fe;
}

Pestañas (tabs) accesibles

Las pestañas son un patrón de navegación común que debe ser accesible tanto para usuarios de ratón como de teclado:

.tabs {
  display: flex;
  flex-direction: column;
}

.tab-list {
  display: flex;
  border-bottom: 1px solid #ddd;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tab {
  margin-bottom: -1px;
}

.tab-button {
  padding: 0.75rem 1.25rem;
  background: none;
  border: 1px solid transparent;
  border-top-left-radius: 4px;
  border-top-right-radius: 4px;
  cursor: pointer;
  font-weight: 500;
  color: #555;
}

/* Pestaña activa */
.tab-button[aria-selected="true"] {
  background-color: #fff;
  border-color: #ddd;
  border-bottom-color: #fff;
  color: #1a73e8;
}

/* Estado de foco */
.tab-button:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: -2px;
  z-index: 1;
}

/* Estado hover */
.tab-button:hover:not([aria-selected="true"]) {
  background-color: #f5f5f5;
  border-bottom-color: #ddd;
}

/* Paneles de contenido */
.tab-panel {
  padding: 1rem;
  border: 1px solid #ddd;
  border-top: none;
  background-color: #fff;
}

/* Ocultar paneles inactivos */
.tab-panel[hidden] {
  display: none;
}

Tooltips accesibles

Los tooltips proporcionan información adicional, pero deben ser accesibles para todos los usuarios:

.tooltip-container {
  position: relative;
  display: inline-block;
}

.tooltip-trigger {
  /* Estilos para el elemento que activa el tooltip */
  border-bottom: 1px dotted #555;
  cursor: help;
}

.tooltip {
  position: absolute;
  bottom: 125%;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.5rem;
  background-color: #333;
  color: #fff;
  border-radius: 4px;
  font-size: 0.875rem;
  white-space: nowrap;
  z-index: 10;
  /* Oculto por defecto */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s, visibility 0.2s;
  /* Aseguramos suficiente contraste */
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

/* Flecha del tooltip */
.tooltip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #333 transparent transparent transparent;
}

/* Mostrar tooltip al hacer hover o al enfocar */
.tooltip-container:hover .tooltip,
.tooltip-trigger:focus + .tooltip,
.tooltip-trigger:focus-visible + .tooltip {
  opacity: 1;
  visibility: visible;
}

/* Aseguramos que el tooltip sea visible cuando se enfoca el trigger */
.tooltip-trigger:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

Carruseles accesibles

Los carruseles son componentes complejos que requieren consideraciones especiales para ser accesibles:

.carousel {
  position: relative;
  overflow: hidden;
}

.carousel-track {
  display: flex;
  transition: transform 0.5s ease;
}

.carousel-slide {
  flex: 0 0 100%;
  /* Aseguramos que cada slide tenga la misma anchura */
  width: 100%;
}

/* Controles de navegación */
.carousel-controls {
  display: flex;
  justify-content: space-between;
  margin-top: 1rem;
}

.carousel-button {
  background-color: #f5f5f5;
  border: 1px solid #ddd;
  border-radius: 50%;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* Estado de foco */
.carousel-button:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  background-color: #e8f0fe;
}

/* Indicadores de slide */
.carousel-indicators {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1rem;
}

.carousel-indicator {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background-color: #ddd;
  border: none;
  padding: 0;
  cursor: pointer;
}

.carousel-indicator[aria-current="true"] {
  background-color: #1a73e8;
}

.carousel-indicator:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

/* Pausa automática al hacer hover o enfocar */
.carousel:hover .carousel-track,
.carousel:focus-within .carousel-track {
  animation-play-state: paused;
}

Modales accesibles

Los diálogos modales deben ser accesibles y permitir una navegación adecuada:

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  /* Oculto por defecto */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s, visibility 0.3s;
}

.modal-overlay.open {
  opacity: 1;
  visibility: visible;
}

.modal {
  background-color: #fff;
  border-radius: 4px;
  max-width: 90%;
  width: 500px;
  max-height: 90vh;
  overflow-y: auto;
  padding: 1.5rem;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  /* Animación de entrada */
  transform: scale(0.9);
  transition: transform 0.3s;
}

.modal-overlay.open .modal {
  transform: scale(1);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.modal-title {
  margin: 0;
  font-size: 1.25rem;
}

.modal-close {
  background: none;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
  padding: 0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

.modal-close:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  background-color: #e8f0fe;
}

/* Aseguramos que el contenido detrás del modal no sea navegable */
body.modal-open {
  overflow: hidden;
}

Formularios accesibles

Los formularios son elementos críticos que deben ser accesibles para todos los usuarios:

.form-group {
  margin-bottom: 1.5rem;
}

.form-label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: 500;
}

/* Campos de texto */
.form-input {
  display: block;
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: #333;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.form-input:focus {
  border-color: #1a73e8;
  box-shadow: 0 0 0 3px rgba(26, 115, 232, 0.25);
  outline: none;
}

/* Campos con error */
.form-input.error {
  border-color: #dc3545;
}

.form-input.error:focus {
  box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.25);
}

/* Mensaje de error */
.form-error {
  display: block;
  color: #dc3545;
  margin-top: 0.25rem;
  font-size: 0.875rem;
}

/* Campos obligatorios */
.required-field .form-label::after {
  content: "*";
  color: #dc3545;
  margin-left: 0.25rem;
}

/* Checkbox y radio buttons */
.form-check {
  display: flex;
  align-items: center;
  margin-bottom: 0.5rem;
}

.form-check-input {
  margin-right: 0.5rem;
  /* Aumentamos el tamaño para facilitar la interacción */
  min-width: 1.25rem;
  min-height: 1.25rem;
}

/* Botones de formulario */
.form-button {
  padding: 0.5rem 1rem;
  font-size: 1rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s, box-shadow 0.2s;
}

.form-button:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
}

.form-button-primary {
  background-color: #1a73e8;
  color: white;
  border: none;
}

.form-button-primary:hover {
  background-color: #1557b0;
}

Las migas de pan ayudan a los usuarios a entender su ubicación en un sitio web:

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  padding: 0.75rem 0;
  margin: 0;
  list-style: none;
}

.breadcrumb-item {
  display: flex;
  align-items: center;
}

/* Separador entre elementos */
.breadcrumb-item:not(:first-child)::before {
  content: "/";
  display: inline-block;
  padding: 0 0.5rem;
  color: #6c757d;
}

.breadcrumb-link {
  color: #1a73e8;
  text-decoration: none;
}

.breadcrumb-link:hover {
  text-decoration: underline;
}

.breadcrumb-link:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  border-radius: 2px;
}

/* Elemento actual */
.breadcrumb-item.active {
  color: #6c757d;
}

Paginación accesible

La paginación debe ser navegable con teclado y comprensible para lectores de pantalla:

.pagination {
  display: flex;
  padding: 0;
  margin: 1rem 0;
  list-style: none;
}

.pagination-item {
  margin: 0 0.25rem;
}

.pagination-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.5rem;
  border: 1px solid #ddd;
  border-radius: 4px;
  color: #1a73e8;
  text-decoration: none;
}

.pagination-link:hover {
  background-color: #f5f5f5;
}

.pagination-link:focus-visible {
  outline: 2px solid #1a73e8;
  outline-offset: 2px;
  background-color: #e8f0fe;
}

/* Página actual */
.pagination-item.active .pagination-link {
  background-color: #1a73e8;
  border-color: #1a73e8;
  color: white;
  font-weight: bold;
}

/* Botones de navegación */
.pagination-prev .pagination-link,
.pagination-next .pagination-link {
  font-size: 1.25rem;
}

/* Elemento deshabilitado */
.pagination-item.disabled .pagination-link {
  color: #6c757d;
  pointer-events: none;
  background-color: #f5f5f5;
  border-color: #ddd;
}

Barras de progreso accesibles

Las barras de progreso deben comunicar claramente su estado a todos los usuarios:

.progress {
  display: flex;
  height: 1rem;
  overflow: hidden;
  background-color: #e9ecef;
  border-radius: 0.25rem;
}

.progress-bar {
  display: flex;
  flex-direction: column;
  justify-content: center;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  background-color: #1a73e8;
  transition: width 0.6s ease;
}

/* Variantes de color */
.progress-bar-success {
  background-color: #28a745;
}

.progress-bar-warning {
  background-color: #ffc107;
  color: #212529; /* Mejor contraste */
}

.progress-bar-danger {
  background-color: #dc3545;
}

/* Barra de progreso con etiqueta */
.progress-with-label {
  position: relative;
}

.progress-label {
  position: absolute;
  right: 0.5rem;
  color: #212529;
  font-weight: bold;
}

/* Barra de progreso indeterminada */
.progress-indeterminate .progress-bar {
  width: 100%;
  background-image: linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.15) 25%,
    transparent 25%,
    transparent 50%,
    rgba(255, 255, 255, 0.15) 50%,
    rgba(255, 255, 255, 0.15) 75%,
    transparent 75%,
    transparent
  );
  background-size: 1rem 1rem;
  animation: progress-bar-stripes 1s linear infinite;
}

@keyframes progress-bar-stripes {
  from { background-position: 1rem 0; }
  to { background-position: 0 0; }
}

Mensajes de alerta accesibles

Los mensajes de alerta deben ser claramente visibles y comprensibles:

.alert {
  position: relative;
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-radius: 4px;
}

.alert-info {
  color: #0c5460;
  background-color: #d1ecf1;
  border-color: #bee5eb;
}

.alert-success {
  color: #155724;
  background-color: #d4edda;
  border-color: #c3e6cb;
}

.alert-warning {
  color: #856404;
  background-color: #fff3cd;
  border-color: #ffeeba;
}

.alert-danger {
  color: #721c24;
  background-color: #f8d7da;
  border-color: #f5c6cb;
}

/* Icono de alerta */
.alert::before {
  content: "";
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  margin-right: 0.5rem;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  vertical-align: text-bottom;
}

.alert-info::before {
  background-image: url("icon-info.svg");
}

.alert-success::before {
  background-image: url("icon-success.svg");
}

.alert-warning::before {
  background-image: url("icon-warning.svg");
}

.alert-danger::before {
  background-image: url("icon-danger.svg");
}

/* Botón para cerrar la alerta */
.alert-close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  padding: 0.25rem;
  background: none;
  border: none;
  font-size: 1.25rem;
  cursor: pointer;
  color: inherit;
}

.alert-close:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

Consideraciones generales para patrones accesibles

Al implementar estos patrones de diseño, es importante seguir estas prácticas:

  • Mantén la semántica HTML: El CSS debe complementar un HTML semánticamente correcto.
  • Asegura suficiente contraste: Todos los elementos deben tener una relación de contraste adecuada.
  • Proporciona estados visibles: Los estados de hover, focus, active y disabled deben ser claramente distinguibles.
  • Usa transiciones con moderación: Las transiciones deben ser sutiles y respetar las preferencias de reducción de movimiento.
  • Prueba con tecnologías asistivas: Verifica que los componentes funcionen correctamente con lectores de pantalla y navegación por teclado.
  • Mantén la consistencia: Utiliza patrones coherentes en toda la interfaz para facilitar el aprendizaje y uso.

Estos patrones de diseño accesibles con CSS te proporcionan una base sólida para crear interfaces inclusivas que puedan ser utilizadas por todas las personas, independientemente de sus capacidades o dispositivos.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende CSS online

Ejercicios de esta lección Accesibilidad web con CSS

Evalúa tus conocimientos de esta lección Accesibilidad web con CSS con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de CSS

Accede a todas las lecciones de CSS y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Css

CSS

Introducción Y Entorno

Entorno Para Desarrollar Css

CSS

Introducción Y Entorno

Sintaxis

CSS

Sintaxis De Selectores Y Propiedades

Selectores Básicos

CSS

Sintaxis De Selectores Y Propiedades

Herencia Y Cascada

CSS

Sintaxis De Selectores Y Propiedades

Pseudo-clases Y Pseudo-elementos

CSS

Sintaxis De Selectores Y Propiedades

Colores En Css

CSS

Sintaxis De Selectores Y Propiedades

Unidades De Medida

CSS

Sintaxis De Selectores Y Propiedades

Especificidad

CSS

Sintaxis De Selectores Y Propiedades

Estilos De Fuente

CSS

Estilización De Texto Y Fondo

Propiedades De Texto

CSS

Estilización De Texto Y Fondo

Sombras En Texto Y Cajas

CSS

Estilización De Texto Y Fondo

Propiedades De Fondo

CSS

Estilización De Texto Y Fondo

Fuentes Web

CSS

Estilización De Texto Y Fondo

Efectos De Texto: Gradientes, Recortes

CSS

Estilización De Texto Y Fondo

Tipografía Avanzada

CSS

Estilización De Texto Y Fondo

Modelo De Caja

CSS

Modelo Caja

Propiedades De Posicionamiento

CSS

Modelo Caja

Propiedad 'Display'

CSS

Modelo Caja

Elementos 'Float' Y 'Clear'

CSS

Modelo Caja

Rellenos Y Márgenes

CSS

Modelo Caja

Bordes Y Contornos

CSS

Modelo Caja

Absolute, Fixed, Sticky Y Z-index

CSS

Posicionamiento

Flexbox Para Crear Layouts Y Estructuras

CSS

Flexbox

Css Grid Para Crear Layouts Y Estructuras

CSS

Flexbox

Propiedades Del Contenedor Flex

CSS

Flexbox

Propiedades De Los Items Flex

CSS

Flexbox

Columnas Y Filas En Grid

CSS

Css Grid

Espaciado Y Alineación

CSS

Css Grid

Tipografía Responsive

CSS

Diseño Responsive

Fundamentos Del Diseño Responsive

CSS

Diseño Responsive

Imágenes Responsive

CSS

Diseño Responsive

Funciones Matemáticas

CSS

Variables Y Funciones Css

Transformaciones 2d

CSS

Transformación, Transición, Animación

Transformaciones 3d

CSS

Transformación, Transición, Animación

Animaciones

CSS

Transformación, Transición, Animación

Transiciones

CSS

Transformación, Transición, Animación

Css Para Formularios

CSS

Css Avanzado

Accesibilidad Web Con Css

CSS

Css Avanzado

Container Queries

CSS

Css Avanzado

Selectores Avanzados

CSS

Css Avanzado

Animaciones Y Transiciones

CSS

Técnicas Modernas Y Metodologías

Variables En Css

CSS

Técnicas Modernas Y Metodologías

Diseño Responsive Con Media Queries

CSS

Técnicas Modernas Y Metodologías

Metodologías De Escritura En Css

CSS

Técnicas Modernas Y Metodologías

Accede GRATIS a CSS y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender la importancia del contraste de color y cómo aplicarlo según las pautas WCAG.
  • Aprender a utilizar variables CSS para crear temas accesibles y alternativos.
  • Diseñar estilos de foco claros y diferenciados para la navegación por teclado.
  • Implementar media queries que respeten las preferencias de usuario como reducción de movimiento o modo oscuro.
  • Aplicar patrones de diseño accesibles en componentes comunes como tarjetas, menús, formularios y modales.