본문 바로가기
프론트엔드/JavaScript

[ javascript ] HTML, CSS, JS로 음악 플레이어 만들기

by CODESIGN 2024. 9. 9.

 

 

HTML, CSS, JavaScript를 사용해 음악 플레이어를 만들어보았습니다.

 

 

이 플레이어는

노래 정보 표시, 재생/일시정지, 이전/다음 곡으로 넘어가기, 진행 바 등

기본적인 음악 플레이어 기능을 구현합니다.

 

 

 

 

1. HTML 구조


우선, HTML 파일을 작성합니다. 음악 플레이어의 기본 구조는 다음과 같습니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <title>Music Player | Codesign</title>
</head>
<body>
  <div class="container">
    <div class="song-info">
      <div class="song-name">Song</div>
      <div class="artist-name">Artist</div>
      <div class="progress-bar">
        <div class="fill-bar"></div>
      </div>
      <div class="song-time">
        <div class="start-time">0:00</div>
        <div class="end-time">0:00</div>
      </div>
    </div>
    <div class="disk">
      <div class="circle"></div>
      <div id="cover" class="cover"></div>
    </div>
    <div class="controls">
      <img width="20" height="20" src="https://img.icons8.com/material-outlined/48/repeat.png" alt="repeat"/>
      <img width="20" height="20" id="prev" src="https://img.icons8.com/ios-glyphs/90/rewind.png" alt="rewind"/>
      <img width="20" height="20" id="play" src="https://img.icons8.com/ios-glyphs/90/play--v1.png" alt="play--v1"/>
      <img width="20" height="20" id="next" src="https://img.icons8.com/ios-glyphs/90/fast-forward.png" alt="fast-forward"/>
      <img width="20" height="20" src="https://img.icons8.com/fluency-systems-regular/48/video-playlist.png" alt="video-playlist"/>
    </div>
  </div>
  <script src="script.js"></script>
</body>
</html>

 

 

  • container: 전체 플레이어를 감싸는 컨테이너입니다.
  • song-info: 노래 이름, 아티스트 이름, 진행 바 및 시간을 표시합니다.
  • disk: 앨범 커버 이미지를 표시합니다.
  • controls: 재생, 이전, 다음, 반복 버튼이 위치해 있습니다.

 

 

2. CSS 스타일링


style.css 파일을 통해 플레이어의 스타일을 지정합니다.

* {
  margin: 0;
  padding: 0;
}

body {
  background-color: #F4F6FF;
  box-sizing: border-box;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.container {
  position: relative;
  width: 400px;
  background: linear-gradient(#FEA3A3, #BFD1FF);
  padding: 60px 20px;
  border-radius: 30px;
}

.container .song-info {
  margin: 0 15px;
  padding: 220px 15px 45px;
}

.container .song-info .song-name {
  display: flex;
  justify-content: center;
  font-size: 15px;
}

.container .song-info .artist-name {
  display: flex;
  justify-content: center;
  font-size: 12px;
  margin: 10px 0 30px;
}

.container .song-info .progress-bar {
  background: linear-gradient(to right, #FFA8A8, #C48EFF);
  border-radius: 20px;
  cursor: pointer;
}

.container .song-info .progress-bar .fill-bar {
  width: 0;
  height: 6px;
  border-radius: 20px;
  background-color: #fff;
}

.container .song-info .song-time {
  display: flex;
  justify-content: space-between;
}

.container .song-info .start-time,
.container .song-info .end-time {
  font-size: 12px;
  color: #828282;
  margin: 10px 0;
}

.container .disk {
  max-width: 120px;
}

.container .disk .active {
  animation: rotate 3s linear 0s infinite forwards;
}

.container .disk .cover {
  width: 200px;
  height: 200px;
  position: absolute;
  top: 37px;
  left: 113px;
  background: url("assets/1.jpg");
  background-repeat: no-repeat;
  background-position: bottom center;
  background-size: cover;
  border: 5px solid #fff;
  border-radius: 50%;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  transition: all 0.2s ease-in-out;
}

.container .disk .circle {
  position: absolute;
  width: 22px;
  height: 22px;
  left: 47%;
  top: 23%;
  background-color: #fff;
  z-index: 1;
  border-radius: 50%;
}

.container .controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 40px;
}

.container .controls #play {
  background-color: hsl(239, 100%, 80%);
  padding: 15px;
  border-radius: 50%;
  transition: all 0.3s ease;
}

.container .controls #play:hover {
  background: #7375ff;
}

.controls img {
  cursor: pointer;
}

@keyframes rotate {
  0% {
    transform: rotateX(0deg);
  }
  100% {
    transform: rotateZ(360deg);
  }
}

 

 

  • container: 전체 레이아웃을 구성하며, 그림자 효과와 둥근 모서리를 부여했습니다.
  • progress-bar 및 fill-bar: 진행 바와 채워지는 부분을 스타일링했습니다.

 

3. JavaScript로 기능 구현


다음으로, script.js 파일을 통해 플레이어의 기능을 구현합니다.

 

const songsList = [
  {
    name: "Lost in Your Eyes",
    artist: "TFLM",
    src: "assets/1.mp3",
    cover: "assets/1.jpg"
  },
  {
    name: "All Night",
    artist: "Ikson",
    src: "assets/2.mp3",
    cover: "assets/2.jpg"
  },
  {
    name: "Lie 2 You",
    artist: "Leonell Cassio",
    src: "assets/3.mp3",
    cover: "assets/3.jpg"
  }
]

const artistName = document.querySelector('.artist-name');
const musicName = document.querySelector('.song-name');
const fillBar = document.querySelector('.fill-bar');
const startTime = document.querySelector('.start-time');
const endTime = document.querySelector('.end-time');
const prog = document.querySelector('.progress-bar');
const cover = document.getElementById('cover');
const playBtn = document.getElementById('play');
const prevBtn = document.getElementById('prev');
const nextBtn = document.getElementById('next');

const playIcon = "https://img.icons8.com/ios-glyphs/90/play--v1.png";
const pauseIcon = "https://img.icons8.com/ios-filled/50/pause--v1.png";

let song = new Audio();
let currentSong = 0;
let playing = false;

document.addEventListener('DOMContentLoaded', () => {
  loadSong(currentSong);
  song.addEventListener('timeupdate', updateProgress);
  song.addEventListener('ended', nextSong);
  prevBtn.addEventListener('click',prevSong);
  nextBtn.addEventListener('click', nextSong);
  playBtn.addEventListener('click',togglePlayPause);
  prog.addEventListener('click',seek);
})

function loadSong(index) {
  const { name, artist, src, cover: thumb } = songsList[index];
  artistName.innerText = artist;
  musicName.innerText = name;
  song.src = src;
  cover.style.backgroundImage = `url(${thumb})`;
}

function updateProgress() {
  if (song.duration) {
    const pos = (song.currentTime / song.duration) * 100;
    fillBar.style.width = `${pos}%`;

    startTime.innerText = formatTime(song.currentTime);
    endTime.innerText = formatTime(song.duration);
  }
}

function formatTime(seconds) {
  const minutes = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${minutes}:${secs < 10 ? '0' : ''}${secs}`
}

function updatePlayButton() {
  playBtn.src = playing ? pauseIcon : playIcon;
  playBtn.alt = playing ? "pause--v1" : "play--v1";
  playBtn.id = "play";
}

function togglePlayPause() {
  playing ? song.pause() : song.play();

  playing = !playing;
  updatePlayButton();
  cover.classList.toggle('active', playing);
}

function nextSong() {
  currentSong = (currentSong + 1) % songsList.length;
  playMusic();
}

function prevSong() {
  currentSong = (currentSong -1 + songsList.length) % songsList.length;
  playMusic(); 
}

function playMusic() {
  loadSong(currentSong);
  song.play();

  playing = true;
  updatePlayButton();
  cover.classList.add('active');
}

function seek(e) {
  const pos = (e.offsetX / prog.clientWidth) * song.duration;
  song.currentTime = pos;
}

 

 

 

30분 만에 영상 보며 따라만들기

 

 

 

댓글