Ver contenido
Introducción
Las áreas táctiles son las zonas interactivas que los usuarios pueden tocar, hacer clic o presionar para activar controles como botones, enlaces y campos de formulario. WCAG 2.5.5 (Tamaño del Objetivo Mejorado) y 2.5.8 (Tamaño del Objetivo Mínimo) establecen requisitos de tamaño mínimo para asegurar que los usuarios puedan activar controles con precisión sin activar accidentalmente elementos adyacentes.
Para usuarios con discapacidades motoras, temblores o control motor fino limitado, las áreas táctiles pequeñas crean barreras significativas. Incluso los usuarios sin discapacidades se benefician de objetivos más grandes—especialmente en dispositivos móviles, bajo luz solar intensa o mientras realizan múltiples tareas.
¿Qué Son las Áreas Táctiles?
El Concepto Básico
Un área táctil es la zona clicable/tocable de un elemento interactivo:
<!-- El área táctil del botón es su área visible más el padding -->
<button class="action-btn">
Enviar Formulario
</button>
<style>
.action-btn {
/* Tamaño visual */
min-width: 44px;
min-height: 44px;
padding: 12px 24px;
}
</style>
El área táctil incluye:
- El elemento visible (botón, enlace, icono)
- Cualquier padding que expanda el área clicable
- El área total que responde a eventos de puntero
Quién Se Beneficia
| Tipo de Usuario | Desafío | Solución |
|---|---|---|
| Discapacidades motoras | Dificultad con movimientos precisos | Objetivos más grandes reducen la precisión necesaria |
| Temblores (Parkinson) | Movimientos involuntarios de mano | Más espacio previene toques erróneos |
| Artritis | Destreza limitada en dedos | Áreas más grandes son más fáciles de alcanzar |
| Baja visión | Dificultad para ver controles pequeños | Objetivos más grandes son más fáciles de localizar |
| Usuarios mayores | Control motor reducido | Tamaños generosos mejoran la precisión |
| Usuarios móviles | Desafíos de entrada táctil | Objetivos adecuados para toques con dedos |
Requisitos WCAG
2.5.8 Tamaño del Objetivo (Mínimo) - Nivel AA
Nuevo en WCAG 2.2, este criterio requiere:
El tamaño del objetivo para entradas de puntero es al menos 24 por 24 píxeles CSS, excepto cuando:
- Espaciado: Los objetivos de menor tamaño tienen suficiente espaciado para que un círculo de 24×24 pueda colocarse en cada objetivo sin superposición
- Equivalente: Otro objetivo para la misma función tiene 24×24 o más
- En línea: El objetivo está en una oración o bloque de texto
- Control del Agente de Usuario: El tamaño del objetivo es determinado por el navegador
- Esencial: La presentación específica es legalmente requerida o esencial
2.5.5 Tamaño del Objetivo (Mejorado) - Nivel AAA
Para accesibilidad mejorada:
El tamaño del objetivo para entradas de puntero es al menos 44 por 44 píxeles CSS, excepto por las mismas excepciones que 2.5.8.
¿Por Qué Estos Tamaños?
| Tamaño | Nivel | Justificación |
|---|---|---|
| 24×24 px | AA | Mínimo para accesibilidad básica |
| 44×44 px | AAA | Basado en recomendaciones de Apple/iOS |
| 48×48 dp | Recomendación de Material Design |
Problemas Comunes de Áreas Táctiles
1. Objetivos Demasiado Pequeños
<!-- MAL: Botón de icono sin padding -->
<button class="icon-btn">
<svg width="16" height="16"><!-- icono --></svg>
</button>
<style>
.icon-btn {
padding: 0;
/* Tamaño total: 16×16 - ¡muy pequeño! */
}
</style>
2. Objetivos Demasiado Cercanos
<!-- MAL: Botones sin espaciado adecuado -->
<div class="button-group">
<button>Guardar</button>
<button>Cancelar</button>
<button>Eliminar</button>
</div>
<style>
.button-group button {
margin: 2px; /* ¡No hay suficiente espaciado! */
}
</style>
3. Área Clicable Más Pequeña que la Visual
<!-- MAL: Visual grande pero área clicable pequeña -->
<div class="card" onclick="handleClick()">
<img src="thumbnail.jpg" alt="Producto">
<a href="/producto" class="tiny-link">Ver Detalles</a>
</div>
<style>
.tiny-link {
font-size: 10px;
/* El enlace es diminuto a pesar de la tarjeta grande */
}
</style>
4. Áreas Táctiles Ocultas
/* MAL: El padding no cuenta si overflow está oculto */
.container {
overflow: hidden;
}
.container button {
padding: 20px;
margin: -10px; /* ¡El padding se corta! */
}
Tamaño Adecuado de Áreas Táctiles
Tamaño Mínimo (Nivel AA)
/* Cumple el requisito mínimo de 24×24 */
.interactive-element {
min-width: 24px;
min-height: 24px;
}
/* Mejor: Agregar padding a elementos pequeños */
.icon-button {
padding: 8px;
/* Si el icono es 16×16, el total se convierte en 32×32 */
}
Tamaño Mejorado (Nivel AAA)
/* Cumple el requisito mejorado de 44×44 */
.touch-target {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
Usando la Excepción de Espaciado
/* Objetivos pequeños con espaciado adecuado */
.nav-link {
padding: 4px 8px;
margin: 12px; /* Crea 24px de separación entre objetivos */
}
Midiendo Áreas Táctiles
Qué Cuenta Como Tamaño del Objetivo
- Área clicable - El área que responde a clics/toques
- Límites visuales - Lo que los usuarios ven y apuntan
- Área de detección - Zona de detección de puntero del navegador
Píxeles CSS vs Píxeles Físicos
Los requisitos de área táctil usan píxeles CSS, no píxeles de dispositivo:
/* 44 píxeles CSS = 44px en tu hoja de estilos */
/* En pantalla Retina 2x = 88 píxeles físicos */
/* En pantalla 3x = 132 píxeles físicos */
.button {
min-width: 44px; /* píxeles CSS */
min-height: 44px; /* píxeles CSS */
}
Probando Áreas Táctiles
Prueba Manual Rápida
- Usar DevTools del navegador para medir dimensiones del elemento
- Verificar estilos computados para ancho/alto
- Verificar que el área clicable coincide con el área visual
- Probar el espaciado entre objetivos adyacentes
Qué Verificar
- [ ] Todos los elementos interactivos son al menos 24×24 píxeles CSS
- [ ] Las áreas táctiles tienen espaciado adecuado (sin áreas de detección superpuestas)
- [ ] Los botones de icono tienen padding suficiente
- [ ] El texto de enlace tiene área clicable adecuada
- [ ] Los campos de formulario cumplen los requisitos de tamaño
Herramientas para Pruebas
- DevTools del navegador - Medir dimensiones de elementos
- axe DevTools - Reporta problemas de tamaño de objetivo
- WAVE - Resaltado visual de objetivos pequeños
- Pruebas en dispositivo móvil - Pruebas táctiles del mundo real
Recomendaciones de Diseño
Más Allá de los Requisitos Mínimos
| Contexto | Tamaño Recomendado |
|---|---|
| Acciones primarias | 48×48 px o más |
| Elementos de navegación | 44×44 px mínimo |
| Campos de formulario | 44×44 px área táctil |
| Acciones secundarias | 36×36 px mínimo |
| Interfaces densas | 24×24 px con espaciado |
Guías de Espaciado
/* Asegurar espaciado mínimo de 24px */
.button-group {
gap: 24px;
}
/* O usar margen */
.action-button {
margin: 12px; /* 12px × 2 = 24px entre botones */
}
Resumen de Mejores Prácticas
| Hacer | No Hacer |
|---|---|
| Usar min-width/min-height para dimensionado | Depender solo del contenido para dimensionar objetivos |
| Agregar padding a iconos pequeños | Usar áreas clicables diminutas |
| Proporcionar espaciado entre objetivos | Agrupar elementos interactivos |
| Probar en dispositivos táctiles reales | Solo probar con ratón |
| Considerar todos los métodos de entrada | Diseñar solo para escritorio |
Implementación
Técnicas de Dimensionamiento CSS
Dimensionamiento Mínimo Básico
/* Nivel AA: 24×24 píxeles CSS mínimo */
.target-aa {
min-width: 24px;
min-height: 24px;
}
/* Nivel AAA: 44×44 píxeles CSS mínimo */
.target-aaa {
min-width: 44px;
min-height: 44px;
}
/* Recomendación Google/Material: 48×48 dp */
.target-material {
min-width: 48px;
min-height: 48px;
}
Expandiendo Elementos Pequeños con Padding
Cuando el contenido es menor que el tamaño de objetivo requerido, usa padding:
/* El icono es 16×16, necesitamos objetivo de 44×44 */
.icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 14px; /* (44 - 16) / 2 = 14px */
border: none;
background: transparent;
cursor: pointer;
}
.icon-button svg {
width: 16px;
height: 16px;
}
/* Para mínimo 24×24 con icono 16×16 */
.icon-button-aa {
padding: 4px; /* (24 - 16) / 2 = 4px */
}
Expandiendo Enlaces Sin Cambio Visual
Usa pseudo-elementos para expandir el área clicable sin cambiar el layout:
/* El texto del enlace permanece visualmente pequeño, pero el objetivo es más grande */
.expanded-link {
position: relative;
/* Estilos visuales sin cambios */
}
.expanded-link::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 44px;
min-height: 44px;
}
Usando Bordes Transparentes
Expande el área clicable mientras mantienes el diseño visual:
.button-with-expanded-target {
/* Apariencia visual */
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
/* Borde invisible expande el objetivo */
border: 10px solid transparent;
background-clip: padding-box;
margin: -10px; /* Compensar el borde */
}
Patrones de Componentes
Botones de Icono
<!-- Estructura correcta de botón de icono -->
<button
type="button"
class="icon-button"
aria-label="Cerrar diálogo"
>
<svg class="icon" aria-hidden="true" viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
</svg>
</button>
<style>
.icon-button {
/* Asegurar tamaño mínimo de objetivo */
min-width: 44px;
min-height: 44px;
/* Centrar icono */
display: inline-flex;
align-items: center;
justify-content: center;
/* Resetear estilos de botón */
padding: 0;
border: none;
background: transparent;
cursor: pointer;
/* Estados de foco y hover */
border-radius: 50%;
transition: background-color 0.2s;
}
.icon-button:hover {
background-color: rgba(0, 0, 0, 0.04);
}
.icon-button:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
.icon {
width: 24px;
height: 24px;
}
</style>
Enlaces de Navegación
<nav class="main-nav" aria-label="Navegación principal">
<ul class="nav-list">
<li><a href="/" class="nav-link">Inicio</a></li>
<li><a href="/nosotros" class="nav-link">Nosotros</a></li>
<li><a href="/servicios" class="nav-link">Servicios</a></li>
<li><a href="/contacto" class="nav-link">Contacto</a></li>
</ul>
</nav>
<style>
.nav-list {
display: flex;
gap: 8px;
list-style: none;
padding: 0;
margin: 0;
}
.nav-link {
/* Tamaño mínimo de objetivo */
display: flex;
align-items: center;
min-height: 44px;
padding: 0 16px;
/* Estilos visuales */
text-decoration: none;
color: #333;
border-radius: 4px;
transition: background-color 0.2s;
}
.nav-link:hover {
background-color: #f5f5f5;
}
.nav-link:focus-visible {
outline: 2px solid #007bff;
outline-offset: -2px;
}
</style>
Campos de Formulario
<div class="form-field">
<label for="email">Correo electrónico</label>
<input
type="email"
id="email"
class="form-input"
autocomplete="email"
>
</div>
<style>
.form-input {
/* Altura mínima del objetivo */
min-height: 44px;
/* Ancho completo para facilitar apuntado */
width: 100%;
/* Padding para contenido y tamaño de objetivo */
padding: 12px 16px;
/* Estilos visuales */
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px; /* Previene zoom en iOS */
}
.form-input:focus {
outline: 2px solid #007bff;
outline-offset: -2px;
border-color: #007bff;
}
</style>
Checkboxes y Radio Buttons
<div class="checkbox-field">
<input type="checkbox" id="agree" class="checkbox-input">
<label for="agree" class="checkbox-label">
Acepto los términos y condiciones
</label>
</div>
<style>
.checkbox-field {
display: flex;
align-items: flex-start;
gap: 12px;
}
/* Ocultar checkbox nativo, pero mantener accesible */
.checkbox-input {
/* Dimensionar el checkbox */
width: 24px;
height: 24px;
margin: 0;
/* O ocultar y usar estilos personalizados */
appearance: none;
border: 2px solid #666;
border-radius: 4px;
cursor: pointer;
}
.checkbox-input:checked {
background-color: #007bff;
border-color: #007bff;
}
.checkbox-input:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
.checkbox-label {
/* Hacer toda la etiqueta clicable */
min-height: 24px;
cursor: pointer;
line-height: 24px;
}
</style>
Implementación de la Excepción de Espaciado
Entendiendo la Excepción de Espaciado
WCAG 2.5.8 permite objetivos menores de 24×24 si hay suficiente espaciado:
/* Objetivos pequeños (16×16) con espaciado adecuado */
.small-target-with-spacing {
width: 16px;
height: 16px;
/* 8px de margen en todos los lados = 16px de separación */
/* Combinado con tamaño del elemento: 16 + 8 + 8 = 32px de centro a centro */
margin: 8px;
}
/* Alternativamente, usar gap en flex/grid */
.target-group {
display: flex;
gap: 24px; /* Asegura que círculos de 24×24 no se superpongan */
}
.target-group .small-target {
width: 16px;
height: 16px;
}
Explicación Visual
Objetivo A (16×16) Objetivo B (16×16)
████ ████
████ ████
◯ ← círculo 24×24 ◯ ← círculo 24×24
Con gap de 24px, los círculos no se superponen = PASA
Patrón Práctico de Espaciado
/* Paginación con indicadores pequeños */
.pagination {
display: flex;
align-items: center;
gap: 24px;
}
.pagination-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: #ccc;
border: none;
cursor: pointer;
/* No necesita min-width/height debido al espaciado */
}
.pagination-dot.active {
background: #007bff;
}
/* Pero asegurar que botones prev/next cumplan requisitos de tamaño */
.pagination-button {
min-width: 44px;
min-height: 44px;
}
Implementaciones en Frameworks
Componente React
// TouchTarget.tsx
import React, { forwardRef } from 'react';
import clsx from 'clsx';
import styles from './TouchTarget.module.css';
interface TouchTargetProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
size?: 'aa' | 'aaa' | 'material';
variant?: 'icon' | 'text' | 'contained';
children: React.ReactNode;
}
export const TouchTarget = forwardRef<HTMLButtonElement, TouchTargetProps>(
({ size = 'aaa', variant = 'text', children, className, ...props }, ref) => {
return (
<button
ref={ref}
className={clsx(
styles.touchTarget,
styles[size],
styles[variant],
className
)}
{...props}
>
{children}
</button>
);
}
);
// TouchTarget.module.css
.touchTarget {
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
cursor: pointer;
transition: background-color 0.2s;
}
.aa { min-width: 24px; min-height: 24px; }
.aaa { min-width: 44px; min-height: 44px; }
.material { min-width: 48px; min-height: 48px; }
.icon { padding: 8px; border-radius: 50%; }
.text { padding: 8px 16px; border-radius: 4px; }
.contained {
padding: 12px 24px;
background-color: #007bff;
color: white;
border-radius: 4px;
}
.touchTarget:hover { background-color: rgba(0, 0, 0, 0.04); }
.touchTarget:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
Componente Vue 3
<!-- TouchTarget.vue -->
<script setup lang="ts">
interface Props {
size?: 'aa' | 'aaa' | 'material'
variant?: 'icon' | 'text' | 'contained'
as?: 'button' | 'a'
}
const props = withDefaults(defineProps<Props>(), {
size: 'aaa',
variant: 'text',
as: 'button'
})
</script>
<template>
<component
:is="as"
:class="[
'touch-target',
`touch-target--${size}`,
`touch-target--${variant}`
]"
>
<slot />
</component>
</template>
<style scoped>
.touch-target {
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
cursor: pointer;
text-decoration: none;
transition: background-color 0.2s;
}
.touch-target--aa { min-width: 24px; min-height: 24px; }
.touch-target--aaa { min-width: 44px; min-height: 44px; }
.touch-target--material { min-width: 48px; min-height: 48px; }
.touch-target--icon { padding: 8px; border-radius: 50%; }
.touch-target--text { padding: 8px 16px; border-radius: 4px; }
.touch-target--contained {
padding: 12px 24px;
background-color: #007bff;
color: white;
border-radius: 4px;
}
.touch-target:hover { background-color: rgba(0, 0, 0, 0.04); }
.touch-target--contained:hover { background-color: #0056b3; }
.touch-target:focus-visible {
outline: 2px solid #007bff;
outline-offset: 2px;
}
</style>
Utilidades Tailwind CSS
/* tailwind.config.js */
module.exports = {
theme: {
extend: {
minWidth: {
'target-aa': '24px',
'target-aaa': '44px',
'target-material': '48px',
},
minHeight: {
'target-aa': '24px',
'target-aaa': '44px',
'target-material': '48px',
},
},
},
}
/* Uso en HTML */
<button class="min-w-target-aaa min-h-target-aaa flex items-center justify-center">
<svg class="w-6 h-6"><!-- icono --></svg>
</button>
Áreas Táctiles Responsivas
Enfoque Mobile-First
/* Objetivos más grandes en dispositivos táctiles */
.interactive-element {
/* Móvil: objetivos más grandes */
min-width: 48px;
min-height: 48px;
padding: 12px;
}
/* Escritorio: puede usar objetivos más pequeños con puntero */
@media (pointer: fine) {
.interactive-element {
min-width: 32px;
min-height: 32px;
padding: 6px;
}
}
/* Dispositivos táctiles siempre obtienen objetivos más grandes */
@media (pointer: coarse) {
.interactive-element {
min-width: 48px;
min-height: 48px;
padding: 12px;
}
}
Patrón Agnóstico de Dispositivo
/* Propiedades personalizadas CSS para dimensionamiento flexible */
:root {
--target-size-min: 44px;
--target-padding: 10px;
}
@media (pointer: fine) {
:root {
--target-size-min: 32px;
--target-padding: 6px;
}
}
.touch-target {
min-width: var(--target-size-min);
min-height: var(--target-size-min);
padding: var(--target-padding);
}
Probando Áreas Táctiles
Pruebas Automatizadas
// Test de Playwright para áreas táctiles
import { test, expect } from '@playwright/test';
test.describe('Cumplimiento de Áreas Táctiles', () => {
test('todos los botones cumplen requisitos mínimos de tamaño', async ({ page }) => {
await page.goto('/');
const buttons = await page.locator('button').all();
for (const button of buttons) {
const box = await button.boundingBox();
// Verificar mínimo 24×24 (Nivel AA)
expect(box.width).toBeGreaterThanOrEqual(24);
expect(box.height).toBeGreaterThanOrEqual(24);
}
});
test('elementos interactivos tienen espaciado adecuado', async ({ page }) => {
await page.goto('/');
const interactiveElements = await page.locator(
'button, a, input, select, textarea, [role="button"]'
).all();
// Verificar espaciado entre elementos adyacentes
for (let i = 0; i < interactiveElements.length - 1; i++) {
const box1 = await interactiveElements[i].boundingBox();
const box2 = await interactiveElements[i + 1].boundingBox();
// Calcular distancia entre centros
const center1 = { x: box1.x + box1.width / 2, y: box1.y + box1.height / 2 };
const center2 = { x: box2.x + box2.width / 2, y: box2.y + box2.height / 2 };
const distance = Math.sqrt(
Math.pow(center2.x - center1.x, 2) +
Math.pow(center2.y - center1.y, 2)
);
// Si los elementos están cerca, deben ser lo suficientemente grandes o tener espaciado
if (distance < 48) {
expect(box1.width).toBeGreaterThanOrEqual(24);
expect(box1.height).toBeGreaterThanOrEqual(24);
}
}
});
});
Checklist de Pruebas Manuales
-
Medición con DevTools:
- Abrir DevTools del navegador
- Seleccionar elemento interactivo
- Verificar ancho y alto computado
- Verificar que cumple mínimo de 24×24
-
Verificación Visual de Espaciado:
- Buscar elementos interactivos agrupados
- Asegurar espaciado visual adecuado
- Probar con toque en dispositivo móvil
-
Verificación de Área de Clic:
- Hacer clic en los bordes de los elementos
- Verificar que el clic se registra
- Comprobar que el padding contribuye al objetivo
Errores Comunes y Soluciones
Error 1: Depender del Tamaño del Contenido
/* INCORRECTO: El tamaño del objetivo depende de la longitud del texto */
.button {
padding: 4px 8px;
/* Texto corto = botón diminuto */
}
/* CORRECTO: Aplicar tamaño mínimo */
.button {
min-width: 44px;
min-height: 44px;
padding: 8px 16px;
}
Error 2: Overflow Cortando Área del Objetivo
/* INCORRECTO: Overflow hidden corta el padding */
.container {
overflow: hidden;
}
.container .button {
padding: 20px;
margin: -10px; /* ¡El padding se corta! */
}
/* CORRECTO: Usar espaciado apropiado */
.container {
padding: 10px;
}
.container .button {
padding: 20px;
}
Error 3: Transform Afectando Área de Detección
/* INCORRECTO: Scale no aumenta el área de detección */
.icon-button {
transform: scale(2);
/* Visual es más grande, pero área de detección sin cambios */
}
/* CORRECTO: Usar dimensionamiento real */
.icon-button {
min-width: 44px;
min-height: 44px;
}
Checklist de Resumen
- [ ] Todos los elementos interactivos son al menos 24×24 píxeles CSS (Nivel AA)
- [ ] Las acciones primarias son 44×44 píxeles CSS o más (Nivel AAA)
- [ ] Los botones de icono tienen padding adecuado alrededor de los iconos
- [ ] Los objetivos adyacentes tienen espaciado mínimo de 24px (o tamaño mayor)
- [ ] Los campos de formulario tienen altura táctil mínima de 44px
- [ ] Checkboxes y radio buttons tienen tamaño de objetivo adecuado
- [ ] Los enlaces de navegación tienen área clicable suficiente
- [ ] Probado en dispositivos táctiles reales
- [ ] Dimensionamiento responsivo para diferentes métodos de entrada
- [ ] Estados de foco visibles en todos los objetivos
Artículos Relacionados
- Guía de Accesibilidad de Formularios - Tamaño de campos de formulario
- Hub de Cumplimiento WCAG - Todos los evaluadores de accesibilidad