๋์์ ํ๋ ์ด์ด์ ๋ค์ํ ๊ธฐ๋ฅ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํ.
์ด๊ธฐ์ฝ๋
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML Video Player</title>
<link rel="stylesheet" href="style_JuneHyung.css">
</head>
<body>
<div class="player">
<video class="player__video viewer" src="652333414.mp4"></video>
<div class="player__controls">
<div class="progress">
<div class="progress__filled"></div>
</div>
<button class="player__button toggle" title="Toggle Play">โบ</button>
<input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1">
<input type="range" name="playbackRate" class="player__slider" min="0.5" max="2" step="0.1" value="1">
<button data-skip="-10" class="player__button">ยซ 10s</button>
<button data-skip="25" class="player__button">25s ยป</button>
</div>
</div>
<script src="scripts_JuneHyung.js"></script>
</body>
</html>
@charset "utf-8";
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
display: flex;
background: #7a419b;
min-height: 100vh;
background: linear-gradient(135deg, #7c1599 0%, #921099 48%, #7e4ae8 100%);
background-size: cover;
align-items: center;
justify-content: center;
}
.player {
max-width: 750px;
border: 5px solid rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
position: relative;
font-size: 0;
overflow: hidden;
}
/* This css is only applied when fullscreen is active. */
.player:fullscreen {
max-width: none;
width: 100%;
}
.player:-webkit-full-screen {
max-width: none;
width: 100%;
}
.player__video {
width: 100%;
}
.player__button {
background: none;
border: 0;
line-height: 1;
color: white;
text-align: center;
outline: 0;
padding: 0;
cursor: pointer;
max-width: 50px;
}
.player__button:focus {
border-color: #ffc600;
}
.player__slider {
width: 10px;
height: 30px;
}
.player__controls {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%) translateY(-5px);
transition: all 0.3s;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.1);
}
.player:hover .player__controls {
transform: translateY(0);
}
.player:hover .progress {
height: 15px;
}
.player__controls > * {
flex: 1;
}
.progress {
flex: 10;
position: relative;
display: flex;
flex-basis: 100%;
height: 5px;
transition: height 0.3s;
background: rgba(0, 0, 0, 0.5);
cursor: ew-resize;
}
.progress__filled {
width: 50%;
background: #ffc600;
flex: 0;
flex-basis: 50%;
}
/* unholy css to style input type="range" */
input[type='range'] {
-webkit-appearance: none;
background: transparent;
width: 100%;
margin: 0 5px;
}
input[type='range']:focus {
outline: none;
}
input[type='range']::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
background: rgba(255, 255, 255, 0.8);
border-radius: 1.3px;
border: 0.2px solid rgba(1, 1, 1, 0);
}
input[type='range']::-webkit-slider-thumb {
height: 15px;
width: 15px;
border-radius: 50px;
background: #ffc600;
cursor: pointer;
-webkit-appearance: none;
margin-top: -3.5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
input[type='range']:focus::-webkit-slider-runnable-track {
background: #bada55;
}
input[type='range']::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0);
background: #ffffff;
border-radius: 1.3px;
border: 0.2px solid rgba(1, 1, 1, 0);
}
input[type='range']::-moz-range-thumb {
box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0);
height: 15px;
width: 15px;
border-radius: 50px;
background: #ffc600;
cursor: pointer;
}
์ด๊ธฐํ๋ฉด
videoํ๊ทธ์ play, puase์ด๋ฒคํธ.
๊ฐ๊ฐ ์ฌ์ํ๊ณ , ์ผ์์ ์งํ๋ ์ด๋ฒคํธ๋ก, ์ด๋ฒคํธ๋ฅผ ์ง์ ๊ฑด๋๋ฆด ์ ์๋ ์ง ์๊ฒ๋จ.
์ฐธ๊ณ : https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play_event
style.flexBasis
ํ๋ ์ค ์์ดํ ์ ์ด๊ธฐ ํฌ๊ธฐ๋ฅผ ์ง์ ํจ.
box-sizing์ ๋ฐ๋ก ์ง์ ํ์ง ์๋๋ค๋ฉด ์ฝํ ์ธ ๋ฐ์ค์ ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํจ.
์ด๋ฒ ์์ ์์๋ flexBasis๋ฅผ ๊ณ์ฐํ %๋ก ์ง์ ํ๋ฉด์ ๋์์์ด ์งํ๋ ์ ๋๋ฅผ ๋ํ๋ด๋๋ฐ ์ฌ์ฉ.
์ฐธ๊ณ : https://developer.mozilla.org/ko/docs/Web/CSS/flex-basis
const player = document.querySelector('.player');
const video = player.querySelector('.viewer'); // player์์ ์๋ viewer๋ฅผ ์ฐพ๊ธฐ๋๋ฌธ์ player.querySelector
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
๋ฉ์๋ ์์ฑ
function togglePlay() {
// .play() or .pause()
const method = video.paused ? 'play' : 'pause';
video[method]();
// if (video.paused) {
// video.play();
// } else {
// video.pause();
// }
}
video.addEventListener('click', togglePlay); // videoํ๋ฉด ํด๋ฆญ
video๋ฅผ ํด๋ฆญํ์ ๋ play๋ฉด pause, pause๋ฉด play๋ก ๋ณ๊ฒฝ
if (video.paused) {
video.play();
} else {
video.pause();
}
๋ฅผ ์ผํญ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ค๋ก ์์ฑ.
video.paused ? 'play' : 'pause';
function updateButton() {
const icon = this.paused ? 'โบ' : 'โ โ';
toggle.textContent = icon; // ํ ๊ธ ๋ฒํผ
// console.log('Update the button');
}
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
๋น๋์ค์ ์ฌ์์ํ์ ๋ฐ๋ผ ์์ด์ฝ ๋ณ๊ฒฝ.
์ ์ง ์ํ๋ฉด 'โบ', ์ฌ์์ํ๋ฉด 'โ โ'
<button data-skip="-10" class="player__button">ยซ 10s</button>
<button data-skip="25" class="player__button">25s ยป</button>
function skip() {
// console.log('skipping!');
console.timeLog(this.dataset.skip);
video.currentTime += parseFloat(this.dataset.skip); // ํ์ฌ์๊ฐ์ ์ถ๊ฐํ๊ฑฐ๋ ๋บ.
}
skipButtons.forEach(button => button.addEventListener('click', skip));
skipButtons๋ค์ clickํ์ ๋ ํ์ฌ์๊ฐ์์ ์ง์ ํด๋์ skip๊ฐ์ ๋ํด์ค๋ค.
function handleRangeUpdate() {
video[this.name] = this.value;
}
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
๋ณผ๋ฅจ๊ณผ ์ฌ์์๋๋ฅผ ์กฐ์ ํจ.
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
video.addEventListener('timeupdate', handleProgress);
ํ์ฌ ์ฌ์ ์๊ฐ์ ๋ฐ๋ผ ์ฌ์๋ฐ์ ์์น๋ฅผ ์ค์ ํด ์ฃผ๋ ํจ์.
video์ ํ์ฌ์งํ๋ ์๊ฐ์ ์ ์ฒด์๊ฐ์ ๋๋๊ณ *100์ ํ์ฌ ํผ์ผํ ์ด์ง๋ฅผ ๊ตฌํจ.
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;}
let mousedown = false;
progress.addEventListener('click', scrub);
// progress.addEventListener('mousemove', scrub);
// true๋ฉด scrub false๋ฉด scurb X
progress.addEventListener('mousemove', (e)=>mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
๋์์์์ ๋๋๊ทธํ๋ ๋์ ๋ฐ๋ก๋ฐ๋ก ํด๋น ์ฅ๋ฉด์ผ๋ก ์ด๋ํ๊ฒ๋จ.