Matthew Bibby
Matthew Bibby

How to Reposition Closed Captions in Storyline 360

In this tutorial, we will look at how to reposition the closed captions in Storyline 360. While this isn't currently possible to control via Storyline, you'd be amazed at what you can get the HTML5 output to do if you ask it nicely!

Matthew BibbyMatthew Bibby

Have you ever wanted to move the closed captions in Storyline 360, only to find that it isn't possible? Maybe you've got a custom skin that has a bottom navigation bar that clashes with the captions? Or maybe you are designing for small screens and the captions are blocking the content on your slide?

In this tutorial, we will write some code that will reposition Storyline's closed captions in the HTML5 output. Unfortunately, this doesn't work in the Flash output, but it is 2018! So unless you're dealing with weird Internet Explorer compatibility mode crap, you should be publishing to HTML5 first anyway!

Then, if you want to know how to make other changes to the closed captions, such as changing the background colour, the font size (independently on the player font size), making them take up the full width of the container or making them sparkle, then we can dig into that later.

Except for the sparkles. I'm kidding about that.

I think...

Why We Shouldn't Mess With This

There is a reason why Articulate hasn't given people the ability to reposition and redesign the closed captions:

"This is on purpose – as captions are primarily about accessibility, we have formatted them to ensure they meet the standard legibility guidelines for contrast, size, line length etc. and are able to adapt to e.g. mobile devices appropriately. We aren't opposed to adding more flexibility in a future update, but generally the further you customize your captions, the less compliant they will be, and the harder it will become for us to adapt them dynamically to different playback environments while respecting the choices you make as an author." - Simon Taghioff, Director of User Experience at Articulate.

Simon's a good bloke. And he knows what he's talking about. So if you proceed with this tutorial, please note that any changes you make to the positioning of the captions will not be supported by Simon or the rest of the team at Articulate.

But I'll help out where I can! And worse case scenario, it's easy to revert back to the default option if you run into issues. But keep in mind that by making these changes, we may break things for some users. So it would be a good idea to test this solution in all of the devices and browsers that you need to support to make sure things work as intended.

I've been making changes to the closed captions for a while and haven't run into any issues with the testing I've done so far. Oh, except for that one time a course kept crashing after a few slides were viewed, but that's a story for another day! And no, I wasn't trying to add sparkles when this happened!

From what I can see, there is no one right way to format captions so that they adhere to the requirements set out in WCAG 2.0.
What About Section 508?

I haven't forgotten about those of you who live in America and your desire to hang on to old stuff like the imperial system. Thankfully, in early 2017, Section 508 was updated. This means that rather than using a rigid set of outdated static rules, we will all now be using the principle-based approach of WCAG (which is flexible enough to cover existing and not-yet-existing technologies).

So when making changes to the captions, it's a good idea to keep in mind the impact that things like placement, font choice (protip: sans-serif) and colour have on accessibility.

Note that WCAG 2.0 makes no mention of sparkles.

Okay, enough of all that, let's move some things around... and I won't mention sparkles again. Unless I do.

Fire Up Your Code Editor

Because we are going to be doing stuff with code, you need a code editor.

Please don't go typing code in Microsoft Word... that isn't how we roll.

Using Word (or any word processor) will likely mean that your code will never work because of silly things like curly quotes. So grab yourself a code editor if you don't have one installed already.

In the past, I've used Sublime Text, but a while back I switched to using Atom and I recommend you do as well. Because it's awesome.

You can download Atom here.

Quick Discussion of Alternative Approaches

In short, we will be using JavaScript to create a new style sheet so that we can dynamically change the styling that is applied to our captions.

We could achieve the same result by editing the main.min.css file after publishing or by providing an alternative style sheet that overrides the defaults set by Storyline. However, both of those options involve post-publish surgery, which I try and avoid as it's easy to overlook when republishing. Also, I'm not a doctor, so I shouldn't be allowed to perform surgery.

If this doesn't make any sense to you at all, that's okay, it is gobbledygook.

I really like that word.


Try saying it 10 times fast after a few drinks. It's fun.

Enough Jokes - Let's Do This Thing

Okay, let's get down to business.

Open up your code editor and we'll write some JavaScript.

By default, Atom will open a plain text file. You should save the file and call it something like Sparkles.js so that Atom will apply the appropriate syntax highlighting. Or I guess you could call it something more logical like MoveCloseCaptionScript.js, but where is the fun in that!

First, we need to check if the learner is viewing the HTML5 output because we only want to make these changes if they are. There is no point running this code if the Flash output is being viewed.

So let's start with an if statement:

if ( /*the html5 output is being viewed*/ ){
  // do this thing

As you can probably guess, this isn't real code.

I'm using comments (wrapped between /* */ or prepended by //) to write in plain English what we need our code to do.

We will come back to this in a minute and write actual code.

Then, nested inside that if statement, we are going to check if we have already made this change. There is no reason to make it more than once.

So now our code structure will look something like this:

if ( /*the html5 output is being viewed*/ ){
  if ( /* we haven't already done this thing */ ){
    // do this thing
    // tell the browser that we have done this thing

Does that make sense?

Now we will go back and replace our comments with some JavaScript that'll actually work and stuff.

As you probably know (or will after reading this paragraph), when the HTML5 output is being viewed, the URL will look a little something like this:

As opposed to this:

So we can use this fact to determine what output is being viewed by getting our code to have a look at the URL and see if it contains _html5.html.

We will be using a regular expression to specify what we are looking for and the JavaScript test method to see if the string that we grab using the window.location.href contains the text we are looking for.

I know... more gobbledygook.

You don't need to understand any of this stuff, but I'm including these links for those who want to learn more JavaScript.

So what does this look like?

 if (/_html5.html/.test(window.location.href)) {

This now becomes the first line of our code:

if (/_html5.html/.test(window.location.href)) {
  if ( /* we haven't already done this thing */ ){
    // do this thing
    // tell the browser that we have done this thing

Next, we need to tell the browser that we have made this change and also figure out a way to check if the change has been made or not.

Let's add a variable to the global namespace (i.e. tell the browser what's up).

Technically, this isn't the best solution, as it contributes to the pollution of the global namespace. But given how we are using this script, that's okay.

You should plant more trees though... because it's good for the environment.

The code looks like this:

window.movedCaptions = true;

And it belongs here:

if (/_html5.html/.test(window.location.href)) {
  if ( /* we haven't already done this thing */ ){
    // do this thing
    window.movedCaptions = true;

So after we have moved the captions, the browser will know that we have done so and it will remember that as long as the browser window is open.

So how do we test if this has happened already?

That's easy.

We just need a unary negation operator. (You got it, more gobbledygook). Specificially, we'll be using the logical not operator, which is an !.

Essentially, by adding !window.movedCaptions into our script, we are checking if the movedCaptions variable is false or if it doesn't exist at all.

This bit of code goes here:

if (/_html5.html/.test(window.location.href)) {
  if (!window.movedCaptions){
    // do this thing
    window.movedCaptions = true;

Finally, we just need to do the thing. You know, the thing that we are here to do. Move those captions. Like a boss.

Here is the code we need:

var sheet = document.createElement('style');
sheet.innerHTML = ".caption{margin-bottom:40px;}";

In short, we are creating a new style element using the HTML DOM createElement method, adding some CSS that'll move our captions up 40px from the bottom margin, and appending all of this to the HTML file using the HTML DOM appendChild method.

So now our code looks like this:

if (/_html5.html/.test(window.location.href)) {
  if (!window.movedCaptions){
    var sheet = document.createElement('style');
    sheet.innerHTML = ".caption{margin-bottom:40px;}";
    window.movedCaptions = true;

You can change the 40px value to whatever value you need to get the captions exactly where you want them.

For example, in the demo below, I've moved the captions up 180px.

Adding This to Storyline

This is the easy part.

Add an Execute JavaScript trigger to whatever button you are using to play your video or audio. And if your video or audio runs when the timeline starts, just make sure your Execute JavaScript trigger has a chance to do its thing before that happens.

Alternatively, if you have a lot of video or audio files in your course, you could add it to the Slide Master and set it to run when the timeline starts.

Please don't just add the script to the first slide of your course, as it won't work if the user partially completes the course and then resumes it later (because the first slide won't be viewed).

And that's it, you now know how to move the closed captions in Storyline!

If you'd like to know how to manipulate the closed captions in other ways, such as making them transparent, changing the background colour, changing the font size (independently on the player font size), or making them sparkle, then let me know in the comments below and I'll do my best to help you out.


Here is a little demo that shows how our captions move script works:

Files You Might Need:

Here is the .story file that was used in this example.

Here is a SCORM package that you can use to test this in your LMS.

Feel Like Cheating?

Here is a cheat sheet you can print out and stick up in your little cubicle.

That is, if you have a little cubicle. Maybe you have a expansive office with views of Gotham city? Maybe you work from a hammock? A home office? A smart fridge? A tent? A casino?

I really don't know! Just stick this somewhere...

Frequently Asked Questions:

Q. When will you write the tutorial about changing the captions font size?
A. Already have. See here.

Q. What if I name my course course_html5.html, wouldn't this fail if the user was viewing course_html5.html_flash.html?
A. You're clever, I'd like to play chess with you. That is after you've figured out how to include a full stop in your file name!

Q. What version of Storyline did you use to create this demo?
A. Storyline 360, build 3.13.15006.0.

Q. Can you provide a SL2 version of this?
A. No, SL2 does not support closed captions.

Q. How about a SL1 version?
A. Really? *shakes head*

Q. Will this work in Articulate Mobile Player?
A. Please stop asking me that. You shouldn't be using AMP.

Q. Why not?
A. Because it's 2018.

Q. What about a SL4 version?
A. Oh my goodness, you're more annoying than my pet Indian Ringneck.

Q. You have a pet Indian Ringneck?
A. Yes. If you call me, you'll hear him screeching in the background.

Q. You should get a silencer for him.
A. That is not a question. And it's not even a funny joke.

Q. How can you say that? You're not funny.
A. Please click here to unsubscribe from my newsletter.

Q. When I preview my course, this doesn't work. What's up with that?
A. JavaScript doesn't work when previewing. You need to publish your course and open the HTML5 output in a modern browser. Alternatively, you can upload the course to your server or LMS and test it there.

Q. Can I move the captions to a different position part way through a course?
A. Yes. Just execute this JavaScript and it'll move:

var sheet = document.createElement('style');
sheet.innerHTML = ".caption{margin-bottom:40px;}";

Q. I don't have a server. Where can I get one?
A. Ask Tom.

Q. I don't have an LMS. Where can I get one?
A. From the LMS shop. But for now, just test your course in SCORM Cloud.

Q. Will this work in Articulate Review?
A. Yes. However, not all custom JavaScript works as expected in Review. So it would be a good idea to check before you send stuff to the Queen to review.

Q. Do you know the Queen?
A. Not personally, but she seems like a cool lady. She likes cows.

Q. Where do you find this stuff?
A. The internet.

Q. Does this work in HTML5?
A. Yes. I think I mentioned HTML5 a few times in the tutorial...

Q. Does this work in the Flash output?
A. No.

Q. Why not?
A. Because it doesn't.

Q. Can you make it work in the Flash output?
A. No.

Q. Do Articulate support this approach?
A. No, they don't provide support for this stuff. So if you run into any issues leave a comment below (or contact me privately) and I'll help you.

Q. My question isn't listed here, what should I do?
A. Go listen to some more philosophy. Or... you know, leave a comment.

If you found this tutorial helpful and think others in your network will also, please share using the share buttons below. Thanks!

Matthew Bibby

Matthew Bibby

I'm Matt. I'm an eLearning Consultant. I help people like you develop memorable, engaging and profitable training programs. What do you need a hand with?