如何使线性渐变跟随 html 中范围滑块的拇指
How can I make a linear gradient follow the thumb of a range slider in html
所以我正在制作一个 Netflix 主题的 HTML 视频播放器并且我在 javascript 中使用了线性渐变所以我的搜索栏(这是一个自定义的范围滑块)在拇指后面会有不同的颜色.手动滑动时效果很好,但是当拇指自动滑动跟随视频时,渐变保持不变
代码如下:
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);
问题是您将函数直接绑定到 oninput handler,这 不会 被触发以编程方式更改 input
的值。
您可以通过在 oninput
之外声明您的函数来解决它,然后稍后将您的函数分配给它 并且 在您的 timeupdate
中调用它听众。只要您使用 function
关键字来声明函数,在将函数分配给 oninput
之前或之后声明它并不重要,因为它得到 hoisted.
工作片段
我还在 JSFiddle 中上传了以下片段,您可以在其中更清楚地看到它。
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>
所以我正在制作一个 Netflix 主题的 HTML 视频播放器并且我在 javascript 中使用了线性渐变所以我的搜索栏(这是一个自定义的范围滑块)在拇指后面会有不同的颜色.手动滑动时效果很好,但是当拇指自动滑动跟随视频时,渐变保持不变
代码如下:
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);
问题是您将函数直接绑定到 oninput handler,这 不会 被触发以编程方式更改 input
的值。
您可以通过在 oninput
之外声明您的函数来解决它,然后稍后将您的函数分配给它 并且 在您的 timeupdate
中调用它听众。只要您使用 function
关键字来声明函数,在将函数分配给 oninput
之前或之后声明它并不重要,因为它得到 hoisted.
工作片段
我还在 JSFiddle 中上传了以下片段,您可以在其中更清楚地看到它。
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>