简体   繁体   中英

How can I make a linear gradient follow the thumb of a range slider in html

So I am making a Netflix themed HTML video player and I used linear gradient in javascript so my seek bar (which is a customized range slider) would have a different color behind the thumb. it works perfectly when manually sliding it, but when the thumb automatically slides on it own to follow the video the gradient stays the same

here is the code:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Netflix video player</title>

    <link rel="stylesheet" href="https://cdnjs.cloudlflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">


</head>

<body>
    <div class="container">
        <div class="c-video">
            <video class="video" src="video.mp4" ></video>
            <div class="controls">
                <div class="red-bar">
                    <input class="red-juice" type="range" min="1" max="100" step="1" value="1"></input>

                </div>

            </div>
            <div class="buttons">
                <button id="play-pause"></button>
            </div>
            <div class="title"></div>
        </div>
    </div>
    <script src="script.js"></script>

</body>

</html>

css:

.container {
    display: flex;
    background-color: #000000;
    justify-content: center;
    align-items: center;
    height: 100vh;


}

.video {
    width: 100%;

}

.c-video {
    width: 100%;
    max-width: 800px;
    position: relative;
    overflow: hidden;
}

.c-video:hover .title {
    transform: translateY(0);
}

.c-video:hover .controls {
    transform: translateY(0);

}

.c-video:hover .buttons {
    top: 50%;
    left: 50%;
transform: translate(240%,-50%);
}

.title {
    display: flex;
    position: absolute;
    top: 0;
    height: 120px;
    width: 100%;
    flex-wrap: wrap;
    background-image: linear-gradient(rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.01));
    transform: translateY(-100%);
    transition: all .2s;
}

.controls {
    display: flex;
    position: absolute;
    bottom: 0;
    height: 70px;
    width: 100%;
    flex-wrap: wrap;
    background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.9));
transform: translateY(100%);
transition: all .2s;
}

.buttons {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-999%,-50%);
}

.buttons button {

    background:none;
   height: 45px; 
    border: none;
    outline: 0;
    cursor: pointer;
    transform: translate(-300%, 0px);
}

.buttons button:before {
    content: "\f144";
    font-family: "Font Awesome 5 Free";
    display: inline-block;
    font-size: 300%;
    color: #ffff;
    -webkit-font-smoothing: antialiased;

}

.buttons button.play:before {
    content: "\f144";
    font-family: 'Font Awesome 5 Free';
}

.buttons button.pause:before {
    content: "\f28b";
    font-family: 'Font Awesome 5 Free';
}

/* Progress bar container */
.red-bar {
    height: 2px;
    margin-top:15px ;
    margin-bottom: -15px;
    background-color:rgba(0, 0, 0, 0.4);
    margin-left: 10px;
    margin-right: 10px;
    width: 100%;

}

/* This represents the progress bar */
.red-juice {
    position: relative;
    width: 100%;
    height: 2px; /* thumbHeight + (2 x thumbBorderWidth)*/
    background-image: linear-gradient(to right, red 1%, rgba(0, 0, 0, 0.4) 1%);

    -webkit-appearance: none; /*remove the line*/
    outline: none;
    top: -12px;
    margin-left: 1px;
    margin-right: 100px;

}

.red-juice::-webkit-slider-runnable-track {
    -webkit-appearance: none;
    height: 20px;
  }

    .red-juice::-webkit-slider-thumb {
        -webkit-appearance: none;
        background: red; /*thumbColor*/
        width: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/
        height: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/
        border-radius: 100%;
        margin-top: 1px; /* -[thumbHeight + (2 x thumbBorderWidth) - trackHeight]/2*/
        cursor: pointer;
        border: 0px solid #fff; /*border-width should be equal to thumbBorderWidth if you want same border width across all browsers and border-color should match the background*/
        transition: 0.3s;            
    }

javascript:

var video = document.querySelector(".video");
var juice = document.querySelector(".red-juice");
var btn = document.getElementById("play-pause");

function togglePlayPause() {
    if(video.paused) {
        btn.className = 'pause';
        video.play();
    } else {
        btn.className = 'play';
        video.pause();
    }
}

btn.onclick = function (params) {
    //video.fastSeek(570); // 9:30
    // video.currentTime = 570; //test
    togglePlayPause();
}

video.addEventListener('timeupdate', function() {

    if(video.ended) {
        btn.className = "play";
      // At the end of the movie, reset the position to the start and pause the playback.
        video.currentTime = 0;
        togglePlayPause();
    }
});

video.addEventListener('timeupdate', () => {
    juice.value = video.currentTime / video.duration * juice.max
  })

  juice.addEventListener('change', () => {
    video.currentTime = video.duration * juice.value / juice.max
  })

  juice.oninput = function slidingProgress() {
    juice.style.background = 'linear-gradient(to right, red ' + juice.value * 100 / juice.max + '%, rgba(0, 0, 0, 0.4) ' + this.value + '%, rgba(0, 0, 0, 0.4) 100%)'
  };

juice.addEventListener(slidingProgress);

The problem is you're binding your function directly to the oninput handler , which does not get triggered just by changing the input 's value programmatically.

You can solve it just by declaring your function outside the oninput , and then assign your function to it later and calling it inside your timeupdate listener. It doesn't really matter if you declare your function before or after assigning it to oninput as long as you're using the function keyword to declare it, since it gets hoisted .

Working snippet

I also uploaded the following snippet in JSFiddle in which you'll be able to see it more clearly.

 var video = document.querySelector(".video"); var juice = document.querySelector(".red-juice"); var btn = document.getElementById("play-pause"); function togglePlayPause() { if (video.paused) { btn.className = 'pause'; video.play(); } else { btn.className = 'play'; video.pause(); } } btn.onclick = function(params) { //video.fastSeek(570); // 9:30 // video.currentTime = 570; //test togglePlayPause(); } video.addEventListener('timeupdate', function() { if (video.ended) { btn.className = "play"; // At the end of the movie, reset the position to the start and pause the playback. video.currentTime = 0; togglePlayPause(); } }); function slidingProgress() { // this.value will not work here, since it points to the global window obj // so I'm using juice.value instead // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Function_context juice.style.background = 'linear-gradient(to right, red ' + juice.value * 100 / juice.max + '%, rgba(0, 0, 0, 0.4) ' + juice.value + '%, rgba(0, 0, 0, 0.4) 100%)' } video.addEventListener('timeupdate', () => { juice.value = video.currentTime / video.duration * juice.max slidingProgress() // Call your function here to update.red-juice }) juice.addEventListener('change', () => { video.currentTime = video.duration * juice.value / juice.max }) // And finally assign it to juice.oninput juice.oninput = slidingProgress; // you're not specifying any events to listen to here, so it wouldn't work // juice.addEventListener(slidingProgress);
 .container { display: flex; background-color: #000000; justify-content: center; align-items: center; height: 100vh; }.video { width: 100%; }.c-video { width: 100%; max-width: 800px; position: relative; overflow: hidden; }.c-video:hover.title { transform: translateY(0); }.c-video:hover.controls { transform: translateY(0); }.c-video:hover.buttons { top: 50%; left: 50%; transform: translate(240%, -50%); }.title { display: flex; position: absolute; top: 0; height: 120px; width: 100%; flex-wrap: wrap; background-image: linear-gradient(rgba(0, 0, 0, 0.9), rgba(0, 0, 0, 0.01)); transform: translateY(-100%); transition: all.2s; }.controls { display: flex; position: absolute; bottom: 0; height: 70px; width: 100%; flex-wrap: wrap; background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 0.9)); transform: translateY(100%); transition: all.2s; }.buttons { position: absolute; top: 50%; left: 50%; transform: translate(-999%, -50%); }.buttons button { background: none; height: 45px; border: none; outline: 0; cursor: pointer; transform: translate(-300%, 0px); }.buttons button:before { content: "\f144"; font-family: "Font Awesome 5 Free"; display: inline-block; font-size: 300%; color: #ffff; -webkit-font-smoothing: antialiased; }.buttons button.play:before { content: "\f144"; font-family: 'Font Awesome 5 Free'; }.buttons button.pause:before { content: "\f28b"; font-family: 'Font Awesome 5 Free'; } /* Progress bar container */.red-bar { height: 2px; margin-top: 15px; margin-bottom: -15px; background-color: rgba(0, 0, 0, 0.4); margin-left: 10px; margin-right: 10px; width: 100%; } /* This represents the progress bar */.red-juice { position: relative; width: 100%; height: 2px; /* thumbHeight + (2 x thumbBorderWidth)*/ background-image: linear-gradient(to right, red 1%, rgba(0, 0, 0, 0.4) 1%); -webkit-appearance: none; /*remove the line*/ outline: none; top: -12px; margin-left: 1px; margin-right: 100px; }.red-juice::-webkit-slider-runnable-track { -webkit-appearance: none; height: 20px; }.red-juice::-webkit-slider-thumb { -webkit-appearance: none; background: red; /*thumbColor*/ width: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/ height: 15px; /* thumbHeight + (2 x thumbBorderWidth)*/ border-radius: 100%; margin-top: 1px; /* -[thumbHeight + (2 x thumbBorderWidth) - trackHeight]/2*/ cursor: pointer; border: 0px solid #fff; /*border-width should be equal to thumbBorderWidth if you want same border width across all browsers and border-color should match the background*/ transition: 0.3s; }
 <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. initial-scale=1:0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Netflix video player</title> <link rel="stylesheet" href="https.//cdnjs.cloudlflare.com/ajax/libs/meyer-reset/2.0/reset.min:css"> <link rel="stylesheet" href="https.//use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> <link rel="stylesheet" href="style:css"> </head> <body> <div class="container"> <div class="c-video"> <video class="video" src="https.//www.w3schools.com/html/mov_bbb.mp4"></video> <div class="controls"> <div class="red-bar"> <,-- inputs are self-closing tags: You don't need a closing tag for it. Self-closing tags are single tagged elements - you only need to add a slash before '>', like so: <input /> --> <input class="red-juice" type="range" min="1" max="100" step="1" value="1" /> </div> </div> <div class="buttons"> <button id="play-pause"></button> </div> <div class="title"></div> </div> </div> <script src="script.js"></script> </body> </html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM