HTML5 video background color not matching background color of website -- in some browsers, sometimes
Asked Answered
H

7

39

I have a video that the client wants to sit "seamlessly" in the website. The background HEX color of the video matches the HEX background color of the website, and renders as such in some browsers, some versions, some of the time?

What is most curious is Chrome renders the background of the video differently, until you open the color picker. Then they suddenly match. To be clear, it only fixes it once I open the color picker, not the debugger (read: this not a repainting issue).

Firefox renders differently when I first navigate to the site, but if I hit cmd+r, it becomes perfectly seamless.

Take a look at the screenshots - they say more than I can with words.

I'm in the process of convincing the client to change to white background for the video as that will certainly "fix" it, but I'm super curious as to what /why this is happening.

Any insights from you wizards out there?


Codepen: http://codepen.io/anon/pen/zrJVpX

<div class="background" style="background-color: #e1dcd8; width: 100%; height: 100%;">
<div class="video-container">
    <video id="video" poster="" width="90%" height="auto" preload="" controls style="margin-left: 5%; margin-top: 5%;">
      <source id="mp4" src="http://bigtomorrowdev.wpengine.com/wp-content/themes/bigtomorrow/images/videos/bt-process.mp4" type="video/mp4">
      <source id="webm" src="http://bigtomorrowdev.wpengine.com/wp-content/themes/bigtomorrow/images/videos/bt-process.webm" type="video/webm">
      <source id="ogg" src="http://bigtomorrowdev.wpengine.com/wp-content/themes/bigtomorrow/images/videos/bt-process.ogv" type="video/ogg">
      We're sorry. This video is unable to be played on your browser.
      </video>
    </div>
</div>

Screenshots of the different browsers.

Hop answered 5/2, 2016 at 1:44 Comment(6)
Your pen is asking for authing. I made a new one: codepen.io/anon/pen/gPdVme but can't seem to replicate your issue. Have you tried setting all the backgrounds to transparent rather than coloring them?Helms
@Helms Fixed the codepen with a diff (pub) serverHop
Hey, I wasn't able to figure it out, but have you tried using the "poster" attribute: developer.mozilla.org/en-US/docs/Web/HTML/Element/… to fill the frame with a consistent color?Helms
@Helms -- Yes I have the poster attribute on the real site -- it makes no difference. I left it out of the codepen on purpose because it confused me when I forget to play the video and end up comparing the PNG to the background instead of the video to the background.Hop
Perhaps encoding your test video in either bt.709 or bt.601 colour spaces would help. One of those is generic enough to be rendered in all browsers surely (but I'm not sure which one is most used, eg: no Safari to test etc).Pellikka
Maybe this help you css-tricks.com/color-rendering-difference-firefox-vs-safariEmbolectomy
B
12

It seems like it might be fundamental to how the browsers render video, and not an easy CSS/HTML fix. Your question sounds similar to this question. I am betting the answer lies in some combination of rendering engines and colorspace differences, which may mean there is no good way to fix it across browsers.

On firefox, you could try fiddling with color management settings to see if that changes the behavior. This won't fix the problem, but it could help explain it. In the URL/search bar, enter "about:config". It should take you to an options page. Another search bar will appear rendered in the page, enter "gfx.color_management.mode". That option can take values 0,1,2. Try switching them up and reloading the page (may need to restart firefox) to see if you can get a consistent difference. It's possible it won't make any difference if the color is not being managed in the first place though.

Similarly, you could try disabling hardware-accelerated video decode in chrome. Enter "chrome://flags" in the chrome URL/search bar, then find the flag "Disable hardware-accelerated video decode". Change whatever value it is, restart chrome, and check the colors again.

Neither of these are solutions I realize, this may have been better served as a comment, but I don't have the rep for that yet.

Beutler answered 10/2, 2016 at 12:42 Comment(1)
Why is this the selected answer? Although explaining why the problem exists, it certainly does not solve it.Bishop
G
16

The issue is not solely browser dependent but render dependent. As soon as the browser renders the video with hardware acceleration the GPU preferences affect the color.

For instance, if you are using an Nvidia graphics card, you can change the color preferences in the Nvidia Control Panel. Desktop monitors usually use the full RGB range from 0 to 255, but you can also configure the limited RGB range from 16 to 235. The limited range is generally used by TVs.

On the one hand graphic card drivers sometimes default the color range of desktop monitors to the limited RGB range. On the other hand users may change this value themselves. Since you can't influence the user's browser settings nor the graphic card driver settings, there will always be differences for distinct users.

How are the colors affected:

Full RGB range -> limited RGB range
#000000 becomes #161616
#081F3C becomes #172A43
#FFFFFF becomes #EBEBEB

Here is my approach to solve this issue:

I've tested it with Chrome, Chrome on Smartphone, Edge, Firefox and Internet Explorer 11. Edit: the tests are from 2017, but as mentioned in the comments by Jomal Johny, it doesn't work in IE11 anymore. After a test, I can confirm, that it doesn't work in IE11 in 2021.

As soon as the video is ready to be played or played back, check the first pixel of the video and change the background color of the surrounding container accordingly. This will work regardless of browser settings and rendering configuration.

This is the code:

<!doctype html>

<html>
<head>
    <title>Video</title>
    <script>
        function isColorInRange(expectedColor, givenColor) {
            const THRESHOLD = 40;
            for (var i = 0; i < 3; i++) {
                if (((expectedColor[i] - THRESHOLD) > givenColor[i]) 
                 || ((expectedColor[i] + THRESHOLD) < givenColor[i])) {
                    return false;
                }
            }
            return true;
        }

        function setVideoBgColor(vid, nativeColor) {
            if (vid) {
                var vidBg = vid.parentElement;
                if (vidBg) {
                    // draw first pixel of video to a canvas
                    // then get pixel color from that canvas
                    var canvas = document.createElement("canvas");
                    canvas.width = 1;
                    canvas.height = 1;
                    var ctx = canvas.getContext("2d");
                    ctx.drawImage(vid, 0, 0, 1, 1);
                    
                    var p = ctx.getImageData(0, 0, 1, 1).data;
                    //console.log("rgb(" + p[0] + "," + p[1] + "," + p[2] + ")");
                    if (isColorInRange(nativeColor, p)) {        
                        vidBg.style.backgroundColor = "rgb(" + p[0] + "," + p[1] + "," + p[2] + ")";
                    }
                }
            }
        }
        
        function setVideoBgColorDelayed(vid, nativeColor) {
            setTimeout(setVideoBgColor, 100, vid, nativeColor);
        }
    </script>
    <style>
    body {
        margin: 0;
    }
    
    #my-video-bg {
        height: 100vh;
        display: flex;
        align-items: center;
        background-color: rgb(8,31,60);
    }

    #my-video {
        max-width: 100%;
        margin: 0 auto;
    }
    </style>
</head>
<body>
    <div id="my-video-bg">
        <video id="my-video" preload="metadata" onplay="setVideoBgColorDelayed(this,[8,31,60])" oncanplay="setVideoBgColorDelayed(this,[8,31,60])" controls>
            <source src="video.mp4" type="video/mp4">
        </video>
    </div>
</body>
</html>

The play event and setVideoBgColorDelayed function are for browsers like Internet Explorer, which sometimes already fire the canplay event, although the video data is not yet available to the drawImage function of the canvas.

The function isColorInRange prevents harsh background changes, if the canplay or play events are fired before the canvas can get the pixel.

It is important, that the functions are defined before the video element. If you load up the javascript at the end of the document, as it is often suggested because of page loading performance, then the approach won't work.

Greenroom answered 13/6, 2017 at 13:55 Comment(4)
I wrote an article with an example. Thanks to @Greenroom for the base! sansho.studio/blog/html-videos-correct-background-colorHonourable
Great answer, but when tested across several devices (iPad, windows laptop with Radeon videocard and laptop with GTX videocard) it gives a few units difference in the HEX values of the color so I guess it almost solves the problem.Hohenzollern
The code is not working in IE11 the video background black not removingKluge
Code works (I had to hide the original video), but I cannot get the canvas to be properly responsive? Have tried like this 'window.onresize{canvas.width=vid.offsetWidth;ctx.drawImage(vid,0,0,vidWidth,vidHeight,0,0,canvas.width,canvas.height)'. Is there another responsive similar canvas solution that works with this?Fiddlefaddle
B
12

It seems like it might be fundamental to how the browsers render video, and not an easy CSS/HTML fix. Your question sounds similar to this question. I am betting the answer lies in some combination of rendering engines and colorspace differences, which may mean there is no good way to fix it across browsers.

On firefox, you could try fiddling with color management settings to see if that changes the behavior. This won't fix the problem, but it could help explain it. In the URL/search bar, enter "about:config". It should take you to an options page. Another search bar will appear rendered in the page, enter "gfx.color_management.mode". That option can take values 0,1,2. Try switching them up and reloading the page (may need to restart firefox) to see if you can get a consistent difference. It's possible it won't make any difference if the color is not being managed in the first place though.

Similarly, you could try disabling hardware-accelerated video decode in chrome. Enter "chrome://flags" in the chrome URL/search bar, then find the flag "Disable hardware-accelerated video decode". Change whatever value it is, restart chrome, and check the colors again.

Neither of these are solutions I realize, this may have been better served as a comment, but I don't have the rep for that yet.

Beutler answered 10/2, 2016 at 12:42 Comment(1)
Why is this the selected answer? Although explaining why the problem exists, it certainly does not solve it.Bishop
B
5

If your background is pure black or white you can simply increase the contrast slightly in your css and the issue will be fully solved:

filter: contrast(101%);

Original idea from Jack.

Born answered 10/5, 2018 at 17:48 Comment(0)
G
3

Exporting videos and images in sRGB or Adobe RGB should resolve this problem. We had a video with collor profile HD (1-1-1), and that was causing video background to be slightly lighten in Safari than in Chrome. Tested on macOS

Guzzle answered 28/2, 2017 at 10:25 Comment(0)
B
2

I feel the proper solution here is to film using a green screen (which you probably already did) and use

  1. Transparant webm video or
  2. Replace green pixels with transparant ones using javascript canvas

An example of transparant video can be found here: https://jakearchibald.com/scratch/alphavid/

Billingsley answered 14/6, 2017 at 10:53 Comment(1)
Worth noting for anybody that might stumble across this in the future: alpha channels are supported by WebM (Chrome, Firefox, et al) and HEVC (Safari, including iOS Safari). Using a single <video> tag with a source for each format above gives you cross-browser transparent video backgrounds natively.Hagai
S
2

Export a second video but limit it only to the background color you have on your main video. So now you have your original video, and a second video which is 1 second in length and is just a flat color only.

That video tag should have the following css:

#bg-video {
    position: fixed;
    width: 100vw;
    z-index: -1;
}

and the video tag can be at the top of your document.

<body>
    <video id="bg-video" src="assets/bg.mp4" muted></video>
    <div>your main site html here</div>
</body> 

Since both videos are exported the same way, the colors should also be rendered the same on multiple browsers and/or operating systems.

*Note that your 'background video' should be more or less a square/rectangle so that when it scales, it will cover the browsers width and height.

Staid answered 29/11, 2018 at 13:16 Comment(0)
F
-2

Check this working demo.

Define background color for video container as #e1dcd8;

or replace your existing css with the following:

 body, html {
  height: 100%;
  margin: 0;
  padding: 0;
}
.background {
    background-color: #e1dcd8;
  width: 100%;
  height: 100%;
}

.video-container{
  background:  #e1dcd8;
}

video {
  margin-left: 5%;
  margin-top: 5%;
}
Fissure answered 8/2, 2016 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.