Core · Multimedia
Reproductor multimedia
Reproduce un vídeo, un sonido o un archivo MIDI en la página, con los mismos controles para los tres.
Ejemplo
Un vídeo y un archivo de audio con los mismos controles.
Video, MP4, 15 seconds, with English captions shown by default and Spanish subtitles. It has no sound: both tracks describe the picture.
Video: NASA, Earth Views from the ISS, in the public domain.
Audio, MP3, 25 seconds.
Nothing is downloaded until you press play. Recording: NASA, Apollo 11 launch countdown and lift-off, in the public domain.
MIDI playback needs JavaScript.
MIDI, parsed and played with Web Audio by midi.js, which loads only when a MIDI player is on the page.
Problemas conocidos
Los subtítulos, las transcripciones y la audiodescripción dependen del contenido multimedia que proporciones. Los colores de los subtítulos son una sugerencia: prevalecen los ajustes propios de quien lee, y puede que el navegador los dibuje a su manera, por ejemplo en su propio reproductor a pantalla completa.
Un archivo MIDI no tiene reproductor sin JavaScript: ofrece un enlace de descarga en el texto alternativo.
Código
Copiar el marcado
Un reproductor de audio. El de vídeo añade un .luz-player-media-wrap alrededor de <video>, además de un botón de silencio y un control deslizante de volumen: cópialo del ejemplo anterior.
<div class="luz-player" data-type="audio" role="group" aria-label="Episode 12 player">
<audio class="luz-player-audio" preload="none" controls>
<source src="episode-12.mp3" type="audio/mpeg">
</audio>
<div class="luz-player-controls luz-player-controls--audio">
<button class="luz-player-btn luz-player-playpause" type="button" aria-label="Play">
<svg class="icon-play" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 4.5v15l12-7.5L7 4.5Z"/></g></svg>
<svg class="icon-pause" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" style="display:none"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="5" width="4" height="14" rx="1"/></g></svg>
</button>
<div class="luz-player-progress-row luz-player-progress-row--audio">
<span class="luz-player-time luz-player-current">0:00</span>
<input class="luz-player-seekbar" type="range" min="0" max="1000" step="1" value="0" aria-label="Seek audio">
<span class="luz-player-time luz-player-duration">0:00</span>
</div>
</div>
</div>
Subtítulos: un elemento <track> por archivo dentro de <video> y un control en .luz-player-btns. Usa un botón para una pista y un selector para varias; el script rellena el selector.
<video class="luz-player-video" preload="metadata" controls playsinline>
<source src="interview.mp4" type="video/mp4">
<track kind="captions" srclang="en" label="English" src="interview-en.vtt" default>
<track kind="subtitles" srclang="es" label="Español" src="interview-es.vtt">
</video>
<!-- One track: a button that turns it on and off -->
<button class="luz-player-btn luz-player-captions" type="button" aria-pressed="false" aria-label="Captions">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M6 11h12M6 15h7"/></svg>
</button>
<!-- Several tracks: a select, filled by the script -->
<select class="luz-input luz-player-tracks" aria-label="Captions"></select>
import { initPlayers } from "@luz-ds/core/player";
initPlayers();
Variantes y opciones
| Clase o atributo | Efecto |
|---|---|
data-type="video" | Un <video class="luz-player-video">; al pulsar en la imagen, se reproduce o se pausa |
data-type="audio" | Un <audio class="luz-player-audio"> con una fila compacta de controles (.luz-player-controls) |
data-type="midi" y data-src | Un archivo MIDI reproducido con Web Audio mediante midi.js, que solo se carga cuando hace falta |
.luz-player-mute, .luz-player-volbar | Un botón de silencio y un control deslizante de volumen |
.luz-player-fullscreen, .luz-player-pip | Botones opcionales de pantalla completa e imagen en imagen para vídeo |
<track kind="captions">, kind="subtitles" | Un archivo WebVTT con srclang y label; default lo muestra desde el principio |
.luz-player-captions | Un botón para activar y desactivar los subtítulos: usa la pista predeterminada o, si no hay, la primera |
.luz-player-tracks | Un selector con .luz-input para elegir una pista o ninguna |
.luz-player-fallback | Texto que solo se muestra cuando el script no se ejecuta |
Cómo funciona
El elemento multimedia nativo reproduce el archivo; player.js controla los controles de LUZ, con estilos de components/player.css.
initPlayers()monta todos los elementos.luz-playerde la página o del elemento que le pases.luz.jslo ejecuta. Si un reproductor ya está montado, lo deja como está, así que se puede volver a ejecutar sin riesgo.- Al montarlo, el script quita
controlsnativo y conecta los controles de LUZ: reproducir y pausar, tiempo, búsqueda y volumen. Se inicializan según el estado del propio contenido: un vídeomutedaparece silenciado y la duración conocida por el navegador se muestra de inmediato. - La búsqueda y el volumen usan controles deslizantes nativos
<input type="range">. Cuando se conoce la duración, el de búsqueda tiene un paso por segundo, independientemente del valor demaxen el marcado. - Los botones de pantalla completa e imagen en imagen se ocultan cuando el navegador no ofrece esas funciones.
- Los subtítulos son los del navegador: cada elemento
<track>es una pista de texto cuyos indicadores dibuja el navegador. Los controles de LUZ solo eligen qué pista se muestra, así que también reflejan las selecciones del menú propio del navegador.::cuemuestra texto claro sobre la superficie multimedia. No se guarda ninguna opción. Se oculta cualquier control que no tenga una pista que mostrar. mountPlayer(root)ymountMidiPlayer(root)montan un único reproductor.- El reproductor es un contenedor de consulta de tamaño: por debajo de 480 px de ancho propio, los controles de audio se apilan y se oculta la barra de volumen, esté donde esté. Si un elemento superior ajusta su tamaño al contenido (un elemento flex en línea o flotante), necesita un ancho propio.
- En texto de derecha a izquierda, la línea de tiempo sigue la dirección de lectura: la barra de búsqueda empieza a la derecha y se rellena hacia la izquierda, la fila de controles se invierte y las teclas del control deslizante son las del navegador. Los iconos de reproducción, pausa y volumen no se invierten: no apuntan a ninguna parte.
Sin JavaScript
El audio y el vídeo muestran los controles propios del navegador y los de LUZ permanecen ocultos. Los controles del navegador ofrecen subtítulos; una pista con default se muestra desde el principio.
El reproductor MIDI muestra el texto alternativo.
Teclado y ARIA
Usa Tab para moverte por los controles; cada uno conserva sus teclas nativas.
- Botones: Enter o Espacio. Sus nombres cambian según el estado: «Reproducir» o «Pausar», «Silenciar» o «Activar sonido». El botón de subtítulos conserva el nombre «Subtítulos» e indica si está pulsado (
aria-pressed). - Selector de pistas: usa las teclas propias del navegador; cada opción aparece en el idioma de su pista.
- Controles deslizantes: teclas de dirección, Home, End, Page Up y Page Down. Una tecla de dirección mueve el control de búsqueda un segundo y el de volumen un paso (5 % en el ejemplo). El de búsqueda indica el tiempo con texto.
- Cuando el reproductor tiene el foco, pero no uno de sus controles (por ejemplo, después de pulsar el vídeo): Espacio o K reproduce y pausa, y M silencia. F activa la pantalla completa y C activa o desactiva los subtítulos si el reproductor tiene esos botones. Si mantienes Ctrl, Alt o Cmd, estas teclas no hacen nada.
- El reproductor tiene
role="group"y su nombre procede dearia-label.
El contraste y el foco están en la pestaña Diseño.
Diseño
Cuándo usarlo
Usa un reproductor para reproducir un vídeo, un sonido o un archivo MIDI dentro de la página cuando quien lee lo inicie.
Cuándo no usarlo
No uses un reproductor para contenido multimedia que se inicia solo o se reproduce en segundo plano.
- No actives nunca la reproducción automática.
- Para una ilustración animada breve y sin sonido, usa una imagen o una figura.
Qué hacer y qué no
<div class="luz-player" data-type="audio" role="group" aria-label="Episode 12 player">
<audio class="luz-player-audio" preload="metadata" controls src="episode-12.mp3"></audio>
</div>
<video autoplay loop src="intro.mp4"></video>
Cómo escribir el contenido
Nombra cada reproductor según lo que reproduce: «Reproductor del episodio 12», no «Reproductor de audio».
- Añade subtítulos (
<track kind="captions">) y una transcripción a los vídeos con voz. Los subtítulos incluyen los sonidos además de las palabras; los subtítulos traducidos (kind="subtitles") solo traducen las palabras. - Etiqueta cada pista en su propio idioma: «English», «Español».
- Describe los vídeos sin sonido con
aria-labelo con texto junto al vídeo. - Si el archivo es grande, indica su duración y formato junto al reproductor.
Contraste y foco
Los controles aparecen sobre la superficie intensa. El control deslizante y la parte reproducida de la barra de búsqueda usan el color de marca; la barra tiene un borde del color del borde del campo, para que se vea toda su longitud.
| Parte | Color sobre el fondo | Claro | Oscuro | Alto contraste | Requisitos |
|---|---|---|---|---|---|
Tiempo y estado | --luz-text-secondary on --luz-surface-strong | 5.3:1 | 5.4:1 | 16.5:1 | 4.5:1 |
Icono del botón | --luz-text-primary on --luz-surface-strong | 13.5:1 | 10.9:1 | 18.0:1 | 3:1 |
Icono del botón al pasar el puntero | --luz-brand-primary on --luz-surface-hover | 5.1:1 | 6.4:1 | 13.5:1 | 3:1 |
Botón de subtítulos activado: icono y subrayado | --luz-brand-primary on --luz-surface-strong | 4.8:1 | 5.6:1 | 12.1:1 | 3:1 |
Control deslizante de la barra de búsqueda | --luz-brand-primary on --luz-surface-strong | 4.8:1 | 5.6:1 | 12.1:1 | 3:1 |
Parte reproducida frente a la cargada | --luz-brand-primary on --luz-surface-pressed | 4.6:1 | 5.6:1 | 12.1:1 | 3:1 |
Parte reproducida frente a la que aún no se ha cargado | --luz-brand-primary on --luz-surface-muted | 5.6:1 | 7.7:1 | 13.5:1 | 3:1 |
Borde de la barra de búsqueda | --luz-input-border on --luz-surface-strong | 3.2:1 | 3.0:1 | 18.0:1 | 3:1 |
Texto de los subtítulos | --luz-text-on-fill on --luz-surface-media | 21.0:1 | 21.0:1 | 21.0:1 | 4.5:1 |
Anillo de foco | --luz-focus-ring on --luz-surface-strong | 4.8:1 | 5.6:1 | 18.0:1 | 3:1 |
Medido a partir de los valores de los tokens de cada modo, redondeado hacia abajo. Los requisitos son los mínimos de WCAG 2.2 AA: 4,5:1 para el texto y 3:1 para los anillos de foco, los bordes y los iconos.
- Foco: los botones, los controles deslizantes y el selector de pistas tienen un contorno de 2 px
--luz-focus-ring, a 2 px de distancia, como todos los controles de LUZ. - No solo color: los iconos y nombres de reproducir y pausar cambian; el control deslizante indica la posición; cuando se activa el botón de subtítulos, además del color de marca, aparece un subrayado.
- Selector de pistas: usa los colores del campo del formulario, de Formulario.
- Área interactiva: los botones miden 32 px cuadrados.
Tokens que usa
Los 25 tokens que lee components/player.css, agrupados por familia. Cada familia enlaza a su página, con los valores de cada modo. En Figma son variables con los mismos nombres: consulta Tokens en Figma.
- Color
--luz-brand-primary,--luz-divider,--luz-focus-ring,--luz-input-border,--luz-surface-hover,--luz-surface-media,--luz-surface-muted,--luz-surface-pressed,--luz-surface-strong,--luz-text-on-fill,--luz-text-primary,--luz-text-secondary- Spacing and sizing
--luz-control-md,--luz-space-2xs,--luz-space-3xs,--luz-space-md,--luz-space-sm,--luz-space-xs- Typography
--luz-font-mono,--luz-text-sm,--luz-text-xs- Radius
--luz-radius-md,--luz-radius-sm- Shadows
--luz-shadow-icon- Motion
--luz-duration-fast
El teclado y ARIA están en la pestaña Código.