Search code examples
firefoxhtml5-videochromiumsubtitlewebvtt

How do I color cues on webvtt?


HTML

<!DOCTYPE HTML>
<html>
  <head>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <video controls autoplay>
      <source src="./test.mp4" type="video/mp4"/>
      <track default kind="captions" srclang="en" label="English" src="./test.vtt"/>
    </video>
  </body>
</html>

CSS

.yellowish {
  background-color: blue;
  color: yellow;
}
.redcolor {
  background-color: white;
  color: red;
}

VTT

WEBVTT

00:00:00.000 --> 00:00:03.000
<c.yellowish>This text should be yellow.</c> This text will be the default color.

00:00:03.000 --> 00:00:06.000
<c.redcolor>This text should be red.</c> This text will be the default color.

I hosted them on a simple http server with node.js and tried it on chromium and Firefox. They did not show colors. I tried including styles in the vtt file, it did not work either. Size and colors seems to be not working in Firefox and chromium. Alignment doesn't work in chromium. All other webvtt features work perfectly. Am I supposed to use any front-end frameworks for this? It works on YouTube perfectly.(1:30 to 1:40)


Solution

  • Changing the CSS as below will work.

    /* .yellowish { */
    video::cue(.yellowish) {
      background-color: blue;
      color: yellow;
    }
    /* .redcolor { */
    video::cue(.redcolor ) {
      background-color: white;
      color: red;
    }
    

    Example

    <style>
      video::cue(.yellowish) {
        background-color: blue;
        color: yellow;
      }
      video::cue(.redcolor ) {
        background-color: white;
        color: red;
      }
    </style>
    
    <script>
      const vttTxt = `WEBVTT
    00:00:00.000 --> 00:00:03.000
    <c.yellowish>This text should be yellow.</c> This text will be the default color.
    
    00:00:03.000 --> 00:09:56.000
    <c.redcolor>This text should be red.</c> This text will be the default color.
    `
      const blobVTT = new Blob([vttTxt], {"type": "text/plain"})
      const trackUrl = URL.createObjectURL(blobVTT)
      const frag = document.createRange().createContextualFragment(`
              <video width="400" height="200" controls>
      <source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
      <track src="${trackUrl}" kind="captions" srclang="en" label="English" default >
      </video>
              `)
      document.body.append(frag)
    </script>


    The following content is a suggestion, I do not recommend putting foreground and background colors together. According to the documentation.#default-classes, you can define attributes for individual colors separately, which will provide more flexibility when using them. Here is an example:

    <style>
      /* color */
      video::cue(.yellow) {
        color: yellow;
      }
      video::cue(.bg_yellow) {
        background-color: yellow;
      }
      video::cue(.red) {
        color: red;
      }
      video::cue(.bg_red) {
        background-color: red;
      }
    
      /* font-size */
      video::cue(.big) {
        font-size: 2rem;
      }
    </style>
    
    00:00:00.000 --> 00:00:03.000
    <c.yellow.bg_red>This text should be yellow.</c> This text will be the default color.
    
    00:00:03.000 --> 00:09:56.000
    <c.big.red.bg_yello>This text should be red.</c> This text will be the default color.
    

    Example2

    <style>
      video::cue(.yellow) {
        color: yellow;
      }
      video::cue(.bg_yellow) {
        background-color: yellow;
      }
      video::cue(.red) {
        color: red;
      }
      video::cue(.bg_red) {
        background-color: red;
      }
      video::cue(.big) {
        font-size: 2rem;
      }
    </style>
    
    <script>
    const vttTxt = `WEBVTT
    00:00:00.000 --> 00:00:03.000
    <c.yellow.bg_red>This text should be yellow.</c> This text will be the default color.
    
    00:00:03.000 --> 00:09:56.000
    <c.big.red.bg_yellow>This text should be red.</c> This text will be the default color.
    `
    const blobVTT = new Blob([vttTxt], {"type": "text/plain"})
    const trackUrl = URL.createObjectURL(blobVTT)
    const frag = document.createRange().createContextualFragment(`
              <video width="400" height="200" controls>
      <source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4">
      <track src="${trackUrl}" kind="captions" srclang="en" label="English" default >
      </video>
              `)
    document.body.append(frag)
    </script>