Can HTML5 subtitles be positioned with css?
Asked Answered
E

5

8

I am using a custom HTML5 app for streaming videos on a local network, and now I am adding subtitles support.

I have around 500 .vtt subtitles converted from .srt. After I converted them from .srt, I noticed they display right at the bottom of the screen, and I'd like them to have a little margin-bottom.

I am able to style the subtitles with css pseudo element ::cue, but only for font size, color, background. Doesn't seem to support any margin, padding or positioning rules.

Before coding a script to modify all the .vtt files to add line:XX% to the cues (that's the only way I found so far to move them), I was wondering if there's a way to position the subtitles without having to modify all the .vtt files.

If I disable my custom controls and tried the default controls instead. When a subtitle is displayed and I put the mouse over the video to show the controls, the subtitle do move up, and when the controls get auto hidden after a few seconds that line of subtitles stay at that place. But the next line move back down. This is the reason I am wondering if they can be moved without editing the .vtt files, since showing the controls move them up, maybe there's a way I can do it programmatically.

So the question is, can .vtt subtitles be positioned using CSS or any other method other than modifying the .vtt files?

This is the basic code I am using for testing:

<video controls autoplay>
    <source src="http://192.168.0.1/video.mp4" type="video/mp4" />
    <track src="http://192.168.0.1/subtitles.vtt" kind="subtitles" srclang="en" label="English" default />
</video>
<style>
    video::cue {
        font-size:100%;
        color:white;
    }
</style>
Eleni answered 6/7, 2017 at 5:23 Comment(2)
reading documentation seems you can't do it with CSS at leastIncidental
Have a look on this W3C webvtt-cue-lineCongregate
F
9

This isn't css, but incase new visitors want a solution with JS:

const track = document.getElementsByTagName('track')[0].track;

// Position the cue at the top
track.activeCues[0].line = 0;

// Position the cue at the bottom (default)
track.activeCues[0].line = -1;

// Move the cue up 3 lines to make room for video controls
track.activeCues[0].line = -4;
Faucher answered 5/12, 2019 at 8:10 Comment(0)
S
4

The best solution I could think of (in React+Typescript, principle should work anywhere. hacky but works). The main idea is:

  1. Wait for load event to fire on track element
  2. Get VTT cues of track
  3. Set line property of each cue
trackRef = (node: HTMLTrackElement) => {
    if (node == null) return

    node.addEventListener('load', () => {
        if (node.track.cues == null) return
        Array.from(node.track.cues).forEach((c) => {
            (c as VTTCue).line = -4
        })
    })
}

//...

<video>
    <source
        src="..."
    />
    <track
        default
        src="..."
        ref={this.trackRef}
    />
</video>
Smithery answered 4/4, 2022 at 19:44 Comment(0)
H
2

you can extract text from individual cues using textTrack.activeCues[0].text and display them in div and set position of div.

Heliotype answered 26/3, 2019 at 11:26 Comment(0)
C
1

You can give the line-height to the ::cue, but the problem with it is if subtitle goes into multiple lines then the gap between the lines increases.

Casmey answered 6/7, 2017 at 5:39 Comment(0)
S
1

You can customize the appearance of .vtt subtitles with CSS styling defined either in the embedding HTML page or embedded directly in the .vtt files.

The VTT spec has some built-in options for alighment as shown below (taken from https://www.delphiki.com/webvtt/#cue-settings):

WEBVTT FILE

1
01:23:45.678 --> 01:23:46.789 D:vertical
Hello world!

2
01:23:48.910 --> 01:23:49.101 S:50%
Hello
world!

The approach shown above is meant for specific subtitle frames that you want to style differently from other frames. If you need the styling to apply to all the subtitles then see below on how to set styles from the containing page.

Styling inside a VTT file

WEBVTT

STYLE
::cue {
    background-color:rgba(0, 0, 0, 0.8);
    color: rgb(255, 200, 0);
    padding-bottom: 2em;
}
::cue(b) {
  color: red;
}
::cue(.myclass) {
    color: red;
}

1
00:00:00.000 --> 00:00:11.040
<b>bold</b>
<i>italic</i>
<u>underscored</u>
<c.myclass>Styled</c>

❗️ Make sure to read the mozilla vtt docs as there are strict rules about empty lines in VTT. The vtt validator will help detect errors.

Styling in the HTML container page

If the native alignment options are not enough then you can apply your own custom styling.

/* in the HTML file embedding the video */
video::cue {
    background-color: rgba(0, 0, 0, 0.8);
    color: #ffc800;
    padding-bottom: 2em;
}

video::cue(b) {
    color: rgb(51, 216, 18);
}


video::cue(.myclass) {
    color: red;
}

See also

Sheila answered 29/1, 2023 at 20:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.