javascriptvideowebvttvideo-subtitlesvtt

Styling VTT cues - ::cue(#id) selector does not work


I'm trying to style dynamically added VTT cues by trying to target the cue id:

track = video.addTextTrack('captions', 'Captions', 'en');
track.mode = 'showing';

const cue = new VTTCue(0, 10, "Hello world");
cue.id = 'test';
track.addCue(cue);

console.log("ID:", track.cues[0].id)
/* This selector does not work */

::cue(#test) {
  color: red;
}


/* The generic selector works */

::cue {
  background-color: orange;
}
<video id="video" muted autoplay controls width="400px">
  <source type="video/mp4"
          src="https://upload.wikimedia.org/wikipedia/commons/4/46/Panorama_of_the_valley_from_Leh_Palace.webm">     </source>
</video>

I extremely simplified the example, but it shows the problem. I'm not sure what I'm doing wrong, I tried to follow the W3C specs: https://w3c.github.io/webvtt/#introduction-other-features

In this example, the cues have an identifier:

WEBVTT

test

00:00.000 --> 00:02.000 This is a test.

123 00:00.000 --> 00:02.000 That’s an, an, that’s an L!

crédit de transcription 00:04.000 --> 00:05.000 Transcrit par Célestes™ This allows a style sheet to specifically target the cues.

/* style for cue: test */ ::cue(#test) { color: lime; } Due to the syntax rules of CSS, some characters need to be escaped with CSS character escape sequences. For example, an ID that starts with a number 0-9 needs to be escaped. The ID 123 can be represented as "\31 23" (31 refers to the Unicode code point for "1"). See Using character escapes in markup and CSS for more information on CSS escapes.

/* style for cue: 123 / ::cue(#\31 23) { color: lime; } / style for cue: crédit de transcription */ ::cue(#crédit\ de\ transcription) { color: red; }

I don't know if the id selectors work only with .vtt files and not with cues generated via JS. There still are not many info on VTT, since it's still a work in progress technology, I tried different approaches, even using vtt.js to parse a VTT string containing inline ::cue styling, but that doesn't work either.


Solution

  • You could use a class object inside the VTT text.

    But it requires to modify the text attribute for each VTT object.

    Then your css rule will be applied.

    track = video.addTextTrack('captions', 'Captions', 'en');
    track.mode = 'showing';
    
    // wrap text in <c> txt </c>
    const cue = new VTTCue(0, 10, "<c>Hello world</c>");
    cue.id = "test";
    track.addCue(cue);
    ::cue(#test) {
      color: red;
    }
    ::cue {
      background-color: orange;
    }
    <video id="video" muted autoplay controls width="400px">
      <source type="video/mp4"
              src="https://upload.wikimedia.org/wikipedia/commons/4/46/Panorama_of_the_valley_from_Leh_Palace.webm">     </source>
    </video>