# Visuales e interactividad HTML5

Aplicar estos patrones a materiales HTML autónomos. Mantener el CSS y JavaScript dentro del mismo documento y no cargar recursos remotos.

## Disponibilidad y nombre de uso

Esta es una **referencia interna** de la skill `fp-didactic-generator`, no una segunda skill. Cuando la skill esté instalada, consultarla automáticamente al solicitar **«recursos visuales interactivos HTML5»**, diagramas SVG, iconos accesibles, pasos interactivos, comparadores o autoevaluaciones.

Si se trabaja con un Proyecto o un chat basado en documentos adjuntos, subir este archivo junto con `SKILL.md` y conservar su nombre y ruta: `references/visuales-interactivos-html5.md`. No hace falta adjuntarlo por separado en cada petición mientras permanezca en los recursos del Proyecto.

## Selección rápida

| Necesidad | Patrón |
|---|---|
| Mostrar componentes y relaciones | Diagrama SVG inline |
| Explicar una secuencia | Pasos seleccionables o línea temporal |
| Contrastar alternativas | Comparador con botones o tabla accesible |
| Revelar detalle secundario | `<details>` y `<summary>` |
| Comprobar comprensión | Autoevaluación local con feedback |

Cada visual debe tener una finalidad explícita en el texto: «El diagrama muestra…». Mantener la alternativa textual próxima, no solo en atributos ARIA.

## SVG semántico

Usar `viewBox` para que el SVG escale, evitar texto convertido en trazado y mantener contraste suficiente. Los conectores deben incluir marcadores o etiquetas; no depender solo de color.

```html
<figure class="concept-map">
  <svg viewBox="0 0 720 220" role="img" aria-labelledby="diagram-title diagram-desc">
    <title id="diagram-title">Flujo de una petición web</title>
    <desc id="diagram-desc">El navegador envía una petición al servidor, que consulta la base de datos y devuelve una respuesta.</desc>
    <defs>
      <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
        <path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor"></path>
      </marker>
    </defs>
    <g class="node"><rect x="20" y="70" width="170" height="80" rx="10"></rect><text x="105" y="115" text-anchor="middle">Navegador</text></g>
    <path class="connector" d="M190 110H270" marker-end="url(#arrow)"></path>
    <g class="node"><rect x="280" y="70" width="170" height="80" rx="10"></rect><text x="365" y="115" text-anchor="middle">Servidor</text></g>
    <path class="connector" d="M450 110H530" marker-end="url(#arrow)"></path>
    <g class="node"><rect x="540" y="70" width="160" height="80" rx="10"></rect><text x="620" y="115" text-anchor="middle">Base de datos</text></g>
  </svg>
  <figcaption>Flujo simplificado: navegador → servidor → base de datos.</figcaption>
</figure>
```

```css
.concept-map svg { display:block; width:100%; height:auto; color:var(--primary); }
.concept-map .node rect { fill:#fff; stroke:currentColor; stroke-width:2; }
.concept-map text { fill:var(--text-main); font:600 16px system-ui,sans-serif; }
.concept-map .connector { fill:none; stroke:currentColor; stroke-width:2.5; }
@media print { .concept-map { break-inside:avoid; } }
```

Para un icono decorativo, usar `aria-hidden="true" focusable="false"`; para uno informativo, usar `<svg role="img" aria-label="…">`. No reutilizar IDs SVG entre componentes sin prefijarlos.

## Revelado de información

Preferir este patrón cuando la información no sea imprescindible en la primera lectura. La solución debe estar en el DOM y visible al imprimir.

```html
<details class="didactic-details">
  <summary>Ver razonamiento paso a paso</summary>
  <p>Primero se valida la entrada; después se procesa y finalmente se devuelve un resultado.</p>
</details>
```

```css
.didactic-details { border-left:4px solid var(--primary-light); padding:.75rem 1rem; background:#fff; }
.didactic-details summary { cursor:pointer; font-weight:700; }
.didactic-details summary:focus-visible { outline:3px solid var(--warning); outline-offset:3px; }
@media print { .didactic-details { border:1px solid #999; } .didactic-details:not([open]) > *:not(summary) { display:block; } }
```

## Autoevaluación formativa

No usar una autoevaluación para calificación ni guardar respuestas. El feedback explica por qué, no solo «correcto» o «incorrecto».

```html
<section class="check-yourself" data-answer="b" aria-labelledby="check-title">
  <h3 id="check-title">Comprueba tu comprensión</h3>
  <p>¿Qué componente responde a la petición HTTP?</p>
  <div role="group" aria-label="Opciones">
    <button type="button" data-choice="a">La base de datos</button>
    <button type="button" data-choice="b">El servidor web</button>
    <button type="button" data-choice="c">El navegador</button>
  </div>
  <p class="feedback" aria-live="polite"></p>
  <noscript><p><strong>Respuesta:</strong> El servidor web procesa y responde a la petición HTTP.</p></noscript>
</section>
```

```js
document.querySelectorAll('.check-yourself').forEach((quiz) => {
  const feedback = quiz.querySelector('.feedback');
  quiz.querySelectorAll('[data-choice]').forEach((button) => {
    button.addEventListener('click', () => {
      const correct = button.dataset.choice === quiz.dataset.answer;
      feedback.textContent = correct
        ? 'Correcto: el servidor web procesa la petición y prepara la respuesta.'
        : 'Revisa el flujo: la base de datos almacena datos, pero el servidor web responde a HTTP.';
      quiz.querySelectorAll('[data-choice]').forEach((item) => item.setAttribute('aria-pressed', String(item === button)));
    });
  });
});
```

En impresión, incluir una respuesta explicada debajo del componente mediante CSS o contenido visible. Comprobar con teclado: Tab llega a cada control, Enter/Espacio lo activa y el foco se percibe.
