I tried using videojs for playing encrypted HLS video in all common browsers. It didn’t go well. I had a lot of trouble to get it working in Safari browser on MacOS (seeking). The best thing I did was writing my own video player. Here is an example of it.
Example of index.html:
<html> <head> <title></title> <meta charset="utf-8" /> <link rel="stylesheet" type="text/css" href="test.css" /> <script src="Static/js/hls.js"></script> <script src="Static/js/test.js"></script> </head> <body> <div id ="video-container"> <video id ="video" autoplay> <source src ="hls/master.m3u8" type="application/x-mpegURL" /> Your browser does not support the HLS video or the video tag. </video> </div> </body> </html>
Example of test.js file:
var INIT_VOLUME = 0.3; function isFullscreen() { if (document.fullscreenElement || document.webkitCurrentFullScreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) { return true; } return false; } function requestFullscreen(el) { if (el.requestFullscreen) { el.requestFullscreen(); } else if (el.mozRequestFullScreen) { el.mozRequestFullScreen(); } else if (el.webkitRequestFullScreen) { el.webkitRequestFullScreen(); } else if (el.webkitRequestFullscreen) { el.webkitRequestFullscreen(); } else if (el.msRequestFullscreen) { el.msRequestFullscreen(); } } function cancelFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } } function fromSeconds(value) { var hours = Math.floor(value / 3600); value = value - hours * 3600; var minutes = Math.floor(value / 60); value = value - minutes * 60; var hoursStr = ("0" + hours).slice(-2); var minutesStr = ("0" + minutes).slice(-2); var secondsStr = ("0" + Math.round(value)).slice(-2); if (hours > 0) return hoursStr + ":" + minutesStr + ":" + secondsStr; return minutesStr + ":" + secondsStr; } function createControls() { $('#video-container').append('< div id="video-controls">' + '<button id="play"><i class="icon icon-play"></i></button>' + '<button id="volume-btn"><i class="icon icon-volume"></i></button>' + '<span id="current-time">00:00</span>' + '< div id="progress">' + '< div id="progress-buf"></div>' + '< div id="progress-bar"></div>' + '</div>' + '<span id="total-time"></span>' + '<button id="fullscreen"><i class="icon icon-fullscreen"></i></button>' + '<button id="levels">auto</button>' + '</div>' + '< div class="loader"></div>'); var volumeBar = $('< div id="volume" style="display:none">< div id="volume-bar">< div id="volume-value" style="height: ' + INIT_VOLUME * 100 + '%"></div></div></div>'); $('#video-controls').append(volumeBar); $('#volume-btn').click(function () { if (volumeBar.is(":visible")) { $(this).removeClass('active'); volumeBar.hide(); } else { $(this).addClass('active'); volumeBar.show(); } }); } function createLevelButtons(hls) { var levels = hls.levelController._levels; var list = $('<ul id="video-levels" style="display:none">'); for (var i = 0; i < levels.length; i++) { list.append('<li level="' + i + '">' + levels[i].height + 'p</li>'); } list.append('<li level="-1" style="display:none">auto</li>'); $('#video-controls').append(list); $("body").on("click", "#video-levels li", function () { var level = parseInt($(this).attr("level")); hls.currentLevel = level; //immediate (nextLevel for later change) $('#levels').text($(this).text()); list.hide(); $("#video-levels li").show(); $(this).hide(); $('#levels').removeClass('active'); $(".loader").show(); $('#progress-buf').width(0); }); $('#levels').click(function () { if (list.is(":visible")) { $(this).removeClass('active'); list.hide(); } else { $(this).addClass('active'); list.show(); } }); } $(document).ready(function () { var video = document.getElementById('video'); if (Hls.isSupported()) { createControls(); var vid = $("#video"); var getLoadedPercentage = function () { try { var range = 0; var bf = video.buffered; var time = video.currentTime; while (!(bf.start(range) <= time && time <= bf.end(range))) { range += 1; } return bf.end(range) / video.duration; } catch (e) { return 0; } }; $(window).resize(function () { $('#video-controls').width(vid.width()); }); vid.bind('webkitfullscreenchange mozfullscreenchange msfullscreenchange fullscreenchange resize orientationchange', function () { $('#video-controls').width(vid.width()); }); var hls = new Hls(); hls.loadSource('hls/master.m3u8'); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function () { createLevelButtons(hls); video.volume = INIT_VOLUME; video.play(); }); hls.on(Hls.Events.BUFFER_APPENDED, function () { var loadEndPercentage = getLoadedPercentage(); $('#progress-buf').width((loadEndPercentage * 100) + "%"); }); $('#play').click(function () { if (video.paused) video.play(); else video.pause(); }); $('#volume-bar').click(function (e) { var y = e.pageY - this.offsetTop - $(this).parent()[0].offsetTop - $(this).parent().parent()[0].offsetTop; var position = 1 - (y / $('#volume-bar').height()); video.volume = position; $('#volume-value').css('height', (position * 100) + '%'); }); $('#progress').click(function (e) { var x = e.pageX - this.offsetLeft - $(this).parent()[0].offsetLeft; var position = x / $('#progress').width(); video.currentTime = position * video.duration; $('#progress-bar').css('width', (position * 100) + '%'); }); $('#fullscreen').click(function () { if (isFullscreen()) { cancelFullscreen(); $('body').removeClass("fullscreen"); $(this).removeClass('active'); } else { var videoContainerEl = videoContainer[0]; requestFullscreen(videoContainerEl); $('body').addClass("fullscreen"); $(this).addClass('active'); } }); vid.on('timeupdate', function () { var percentage = video.currentTime / video.duration; $('#progress-bar').css('width', (100 * percentage) + '%'); $('#current-time').text(fromSeconds(video.currentTime)); }); vid.on('loadedmetadata', function () { $('#total-time').text(fromSeconds(video.duration)); $('#video-controls').width(vid.width()); }); vid.on('playing', function () { $('#play').find('i').removeClass('icon-play').addClass('icon-pause'); $(".loader").hide(); }); vid.on('seeking', function () { $(".loader").show(); }); vid.on('seeked', function () { $(".loader").hide(); }); vid.on('pause', function () { $('#play').find('i').removeClass('icon-pause').addClass('icon-play'); }); vid.on('loadstart', function (event) { $(".loader").show(); }); vid.on('canplay', function (event) { $(".loader").hide(); }); vid.on('waiting', function (event) { $(".loader").show(); }); } else { video.setAttribute("controls", "controls"); } });
Example of test.css file:
.icon-fullscreen { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDQ0IDQ0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA0NCA0NCIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij4KICA8cGF0aCBkPSJtMjIsMGMtMTIuMiwwLTIyLDkuOC0yMiwyMnM5LjgsMjIgMjIsMjIgMjItOS44IDIyLTIyLTkuOC0yMi0yMi0yMnptLTQsMzBoMWMwLjYsMCAxLDAuNCAxLDF2MmMwLDAuNi0wLjQsMS0xLDFoLThjLTAuNiwwLTEtMC40LTEtMXYtOGMwLTAuNiAwLjQtMSAxLTFoMmMwLjYsMCAxLDAuNCAxLDF2MWMwLDAuNCAwLjUsMC43IDAuOSwwLjRsMi0yYzAuNC0wLjQgMS0wLjQgMS40LDBsMS40LDEuNGMwLjQsMC40IDAuNCwxIDAsMS40bC0yLDJjLTAuMywwLjMtMC4xLDAuOCAwLjMsMC44em0yLTE3YzAsMC42LTAuNCwxLTEsMWgtMWMtMC40LDAtMC43LDAuNS0wLjQsMC45bDIsMmMwLjQsMC40IDAuNCwxIDAsMS40bC0xLjQsMS40Yy0wLjQsMC40LTEsMC40LTEuNCwwbC0yLTJjLTAuMy0wLjMtMC45LTAuMS0wLjksMC40djFjMCwwLjYtMC40LDEtMSwxaC0yYy0wLjYsMC0xLTAuNC0xLTF2LThjMC0wLjYgMC40LTEgMS0xaDhjMC42LDAgMSwwLjQgMSwxdjEuOWgwLjF6bTE0LDIwYzAsMC42LTAuNCwxLTEsMWgtOGMtMC42LDAtMS0wLjQtMS0xdi0yYzAtMC42IDAuNC0xIDEtMWgxYzAuNCwwIDAuNy0wLjUgMC40LTAuOWwtMi0yYy0wLjQtMC40LTAuNC0xIDAtMS40bDEuNC0xLjRjMC40LTAuNCAxLTAuNCAxLjQsMGwyLDJjMC4zLDAuMyAwLjksMC4xIDAuOS0wLjR2LTFjMC0wLjYgMC40LTEgMS0xaDJjMC42LDAgMSwwLjQgMSwxdjguMWgtMC4xem0wLTE0YzAsMC42LTAuNCwxLTEsMWgtMmMtMC42LDAtMS0wLjQtMS0xdi0xYzAtMC40LTAuNS0wLjctMC45LTAuNGwtMiwyYy0wLjQsMC40LTEsMC40LTEuNCwwbC0xLjQtMS40Yy0wLjQtMC40LTAuNC0xIDAtMS40bDItMmMwLjMtMC4zIDAuMS0wLjktMC40LTAuOWgtMWMtMC42LDAtMS0wLjQtMS0xdi0yYzAtMC42IDAuNC0xIDEtMWg4YzAuNiwwIDEsMC40IDEsMXY4LjFoMC4xeiIgZmlsbD0iI0ZGRkZGRiIvPgo8L3N2Zz4K'); } .icon-play { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAzMDAgMzAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAzMDAgMzAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij4KPGc+Cgk8Zz4KCQk8cGF0aCBkPSJNMTUwLDBDNjcuMTU3LDAsMCw2Ny4xNjIsMCwxNTBjMCw4Mi44NDEsNjcuMTU3LDE1MCwxNTAsMTUwczE1MC02Ny4xNTksMTUwLTE1MEMzMDAsNjcuMTYyLDIzMi44NDMsMCwxNTAsMHogICAgIE0yMDUuODQ2LDE1OC4yNjZsLTg2LjU1Nyw0OS45NzFjLTEuMzIsMC43NjUtMi43OTksMS4xNDQtNC4yNzIsMS4xNDRjLTEuNDczLDAtMi45NDktMC4zNzktNC4yNzQtMS4xNDQgICAgYy0yLjY0LTEuNTI1LTQuMjY5LTQuMzQ3LTQuMjY5LTcuNDAyVjEwMC44OWMwLTMuMDUzLDEuNjMxLTUuODgsNC4yNjktNy40MDJjMi42NDgtMS41MjgsNS45MDYtMS41MjgsOC41NTEsMGw4Ni41NTcsNDkuOTc0ICAgIGMyLjY0NSwxLjUzLDQuMjc0LDQuMzUyLDQuMjY5LDcuNDAyQzIxMC4xMiwxNTMuOTE2LDIwOC40OTQsMTU2Ljc0MSwyMDUuODQ2LDE1OC4yNjZ6IiBmaWxsPSIjRkZGRkZGIi8+Cgk8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg=='); } .icon-pause { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAzMDAuMDAzIDMwMC4wMDMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMwMC4wMDMgMzAwLjAwMzsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+CjxnPgoJPGc+CgkJPHBhdGggZD0iTTE1MC4wMDEsMGMtODIuODM4LDAtMTUwLDY3LjE1OS0xNTAsMTUwYzAsODIuODM4LDY3LjE2MiwxNTAuMDAzLDE1MCwxNTAuMDAzYzgyLjg0MywwLDE1MC02Ny4xNjUsMTUwLTE1MC4wMDMgICAgQzMwMC4wMDEsNjcuMTU5LDIzMi44NDYsMCwxNTAuMDAxLDB6IE0xMzQuNDEsMTk0LjUzOGMwLDkuNDk4LTcuNywxNy4xOTgtMTcuMTk4LDE3LjE5OHMtMTcuMTk4LTcuNy0xNy4xOTgtMTcuMTk4VjEwNS40NiAgICBjMC05LjQ5OCw3LjctMTcuMTk4LDE3LjE5OC0xNy4xOThzMTcuMTk4LDcuNywxNy4xOTgsMTcuMTk4VjE5NC41Mzh6IE0xOTguOTU1LDE5NC41MzhjMCw5LjQ5OC03LjcwMSwxNy4xOTgtMTcuMTk4LDE3LjE5OCAgICBjLTkuNDk4LDAtMTcuMTk4LTcuNy0xNy4xOTgtMTcuMTk4VjEwNS40NmMwLTkuNDk4LDcuNy0xNy4xOTgsMTcuMTk4LTE3LjE5OHMxNy4xOTgsNy43LDE3LjE5OCwxNy4xOThWMTk0LjUzOHoiIGZpbGw9IiNGRkZGRkYiLz4KCTwvZz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K'); } .icon-volume { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAzMDAuMDAzIDMwMC4wMDMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMwMC4wMDMgMzAwLjAwMzsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+CjxnPgoJPGc+CgkJPHBhdGggZD0iTTE1MC4wMDUsMEM2Ny4xNjQsMCwwLjAwMSw2Ny4xNTksMC4wMDEsMTUwYzAsODIuODM4LDY3LjE2MiwxNTAuMDAzLDE1MC4wMDMsMTUwLjAwM1MzMDAuMDAyLDIzMi44MzgsMzAwLjAwMiwxNTAgICAgQzMwMC4wMDIsNjcuMTU5LDIzMi44NDQsMCwxNTAuMDA1LDB6IE0xOTcuMjQ1LDEwMC41MDZsMjcuMzU4LTE1Ljc5M2MzLjA4MS0xLjc3OSw3LjAxNi0wLjcyNCw4Ljc5NSwyLjM1NSAgICBjMS43NzcsMy4wODEsMC43MjQsNy4wMTgtMi4zNTUsOC43OTVsLTI3LjM1OCwxNS43OTVjLTMuMDc5LDEuNzc5LTcuMDE2LDAuNzI0LTguNzk1LTIuMzU1ICAgIEMxOTMuMTE0LDEwNi4yMjIsMTk0LjE2NywxMDIuMjg4LDE5Ny4yNDUsMTAwLjUwNnogTTE2NS44NjUsMjI0LjYyNGMtMS40MDMsMC42ODUtMi45MTgsMS4wMjItNC40MjUsMS4wMjIgICAgYy0yLjIxOCwwLTQuNDItMC43MzEtNi4yMzUtMi4xNTNMMTIyLjA0LDE5Ny41MWMtMS41MzUsMC4zNzktMy4xMzYsMC42MDctNC43OTYsMC42MDdIODQuMDEgICAgYy0xMC44OTgsMC0xOS43MzUtOC44MzYtMTkuNzM1LTE5LjczMnYtNTcuNTZjMC0xMC44OTYsOC44MzctMTkuNzM1LDE5LjczNS0xOS43MzVoMzMuMjM1YzEuOTMyLDAsMy43OTIsMC4yOSw1LjU2MSwwLjgwOSAgICBsMzIuMzk3LTI1LjM4OWMzLjA0Mi0yLjM4NCw3LjE4Ny0yLjgyNCwxMC42Ni0xLjEzMWMzLjQ3NSwxLjY5MSw1LjY4Myw1LjIxOCw1LjY4Myw5LjA4OHYxMzEuMDY5aDAuMDAyICAgIEMxNzEuNTQ3LDIxOS40MDYsMTY5LjMzNywyMjIuOTMzLDE2NS44NjUsMjI0LjYyNHogTTIzNC4yMzcsMjEzLjM4M2MtMS43NzksMy4wODEtNS43MTQsNC4xMzQtOC43OTUsMi4zNTVsLTI3LjM1OC0xNS43OTMgICAgYy0zLjA3OS0xLjc4Mi00LjEzMi01LjcxNi0yLjM1NS04Ljc5OGMxLjc3OS0zLjA4MSw1LjcxNi00LjEzNCw4Ljc5NS0yLjM1NWwyNy4zNTgsMTUuNzk1ICAgIEMyMzQuOTYxLDIwNi4zNjIsMjM2LjAxMSwyMTAuMjk5LDIzNC4yMzcsMjEzLjM4M3ogTTIzMS4xMzMsMTU2Ljc5NUgxOTkuNTVjLTMuNTU2LDAtNi40MzctMi44NzktNi40MzctNi40MzcgICAgYzAtMy41NTYsMi44ODItNi40MzcsNi40MzctNi40MzdoMzEuNTg1YzMuNTU2LDAsNi40MzcsMi44ODIsNi40MzcsNi40MzdDMjM3LjU3MywxNTMuOTE2LDIzNC42ODgsMTU2Ljc5NSwyMzEuMTMzLDE1Ni43OTV6IiBmaWxsPSIjRkZGRkZGIi8+Cgk8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg=='); } .icon { background-size: 30px; width: 30px; height: 30px; } #video-wrapper { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 2147483646; max-width: 100%; margin: auto; } #video { height: 50%; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 2147483645; max-width: 100%; margin: auto; background-color: black; } #video-controls { position: absolute; top: 75%; left: 0; right: 0; bottom: 0; z-index: 2147483647; max-width: 100%; margin: auto; height: 40px; margin-top: 0; background-color: #1d35e4; color: white; } body { text-align: center; } html, body, body.fullcreen > main { height: 100%; } #video-container { height: calc(100% - 4px); margin: 0; padding: 0; } main { height: calc(100% - 64px); } #progress { height: 10px; width: calc(100% - 301px); background-color: white; display: inline-block; margin-left: 5px; cursor: pointer; } #progress > #progress-bar { height: 100%; background-color: #366ac7; width: 0; margin-top: -10px; } #progress > #progress-buf { height: 100%; background-color: #d8d4d4; width: 0; } #video-controls > span { width: 60px; display: inline-block; height: 40px; padding-top: 10px; } #video-controls > span > p{ margin:0; } #video-controls > span#total-time { margin-left: 5px; } #video-controls > button { width: 40px; height: 40px; border: none; padding: 0; background-color: transparent; float: left; } #video-controls > button.active { background-color: #19abd0; } #video-controls > button:hover { background-color: #19abd0; } #video-controls > button#levels { float: right; width: 50px; } #video-controls > button#fullscreen { float: right; } body.fullcreen > header, body.fullcreen > main > .progress { display: none; } body.fullscreen #video, body.fullscreen #video-wrapper { height: calc(100% - 40px); bottom: 40px; } body.fullscreen #video-controls { width: 100% !important; top: calc(100% - 40px); } #video-levels { position: absolute; right: 40px; bottom: 25px; background-color: #19abd0; padding: 5px; width: 50px; z-index: 2147483647; } #video-levels > li { cursor: pointer; } #video-levels > li:hover { background-color: #1d35e4; } #volume { position: absolute; width: 40px; height: 100px; background-color: #19abd0; bottom: 40px; left: 41px; } #volume-bar { background-color: white; width: calc(100% - 20px); height: calc(100% - 20px); margin: 10px; position: relative; cursor: pointer; } #volume-value { background-color: #366ac7; bottom: 0; position: absolute; width: 100%; } .loader { border: 16px solid #f3f3f3; /* Light grey */ border-top: 16px solid #1d35e4; /* Blue */ border-radius: 50%; width: 120px; height: 120px; animation: spin 2s linear infinite; position: absolute; top: calc(50% - 60px); left: calc(50% - 60px); z-index: 2147483647; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
You can use it. There can be minor problems, because I parsed this code from my working solution and I don’t want to share everything. Please replace “< div” with “<div”. The wordpress formatting is shit.