Designed by: Mauricio Bucardo Original image: https://dribbble.com/shots/6957353-Music-Player-Widget
If the songs do not play or the photos do not load, please refresh the page once
A Pen by MinoaBaccus on CodePen.
<div class="player"> | |
<div class="player__header"> | |
<div class="player__img player__img--absolute slider"> | |
<button class="player__button player__button--absolute--nw playlist"> | |
<img src="http://physical-authority.surge.sh/imgs/icon/playlist.svg" alt="playlist-icon"> | |
</button> | |
<button class="player__button player__button--absolute--center play"> | |
<img src="http://physical-authority.surge.sh/imgs/icon/play.svg" alt="play-icon"> | |
<img src="http://physical-authority.surge.sh/imgs/icon/pause.svg" alt="pause-icon"> | |
</button> | |
<div class="slider__content"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/1.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/2.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/3.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/4.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/5.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/6.jpg" alt="cover"> | |
<img class="img slider__img" src="http://physical-authority.surge.sh/imgs/7.jpg" alt="cover"> | |
</div> | |
</div> | |
<div class="player__controls"> | |
<button class="player__button back"> | |
<img class="img" src="http://physical-authority.surge.sh/imgs/icon/back.svg" alt="back-icon"> | |
</button> | |
<p class="player__context slider__context"> | |
<strong class="slider__name"></strong> | |
<span class="player__title slider__title"></span> | |
</p> | |
<button class="player__button next"> | |
<img class="img" src="http://physical-authority.surge.sh/imgs/icon/next.svg" alt="next-icon"> | |
</button> | |
<div class="progres"> | |
<div class="progres__filled"></div> | |
</div> | |
</div> | |
</div> | |
<ul class="player__playlist list"> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/1.jpg" alt="cover"> | |
<p class="player__context"> | |
<b class="player__song-name">no time</b> | |
<span class="flex"> | |
<span class="player__title">lastlings</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/1.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/2.jpg" alt="cover"> | |
<p class="player__context"> | |
<b class="player__song-name">blinding lights</b> | |
<span class="flex"> | |
<span class="player__title">the weeknd</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/2.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/3.jpg" alt="cover"> | |
<p class="player__context"> | |
<b class="player__song-name">джованна</b> | |
<span class="flex"> | |
<span class="player__title">enrasta</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/3.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/4.jpg" alt="cover"> | |
<p class="player__context"> | |
<b class="player__song-name">a man</b> | |
<span class="flex"> | |
<span class="player__title">travis scott</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/4.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/5.jpg" alt="cover"> | |
<p class="player__context "> | |
<b class="player__song-name">unforgetting</b> | |
<span class="flex"> | |
<span class="player__title">zaxx</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/5.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/6.jpg" alt="cover"> | |
<p class="player__context"> | |
<b class="player__song-name">waharan</b> | |
<span class="flex"> | |
<span class="player__title">Randall</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/6.mp3"></audio> | |
</li> | |
<li class="player__song"> | |
<img class="player__img img" src="http://physical-authority.surge.sh/imgs/7.jpg" alt="cover"> | |
<p class="player__context "> | |
<b class="player__song-name">starlight feat mr gabriel <span class="uppercase">4am</span> remix</b> | |
<span class="flex"> | |
<span class="player__title">jai wolf</span> | |
<span class="player__song-time"></span> | |
</span> | |
</p> | |
<audio class="audio" src="http://physical-authority.surge.sh/music/7.mp3"></audio> | |
</li> | |
</ul> | |
</div> |
Designed by: Mauricio Bucardo Original image: https://dribbble.com/shots/6957353-Music-Player-Widget
If the songs do not play or the photos do not load, please refresh the page once
A Pen by MinoaBaccus on CodePen.
// Designed by: Mauricio Bucardo | |
// Original image: https://dribbble.com/shots/6957353-Music-Player-Widget | |
"use strict"; | |
// add elemnts | |
const bgBody = ["#e5e7e9", "#ff4545", "#f8ded3", "#ffc382", "#f5eda6", "#ffcbdc", "#dcf3f3"]; | |
const body = document.body; | |
const player = document.querySelector(".player"); | |
const playerHeader = player.querySelector(".player__header"); | |
const playerControls = player.querySelector(".player__controls"); | |
const playerPlayList = player.querySelectorAll(".player__song"); | |
const playerSongs = player.querySelectorAll(".audio"); | |
const playButton = player.querySelector(".play"); | |
const nextButton = player.querySelector(".next"); | |
const backButton = player.querySelector(".back"); | |
const playlistButton = player.querySelector(".playlist"); | |
const slider = player.querySelector(".slider"); | |
const sliderContext = player.querySelector(".slider__context"); | |
const sliderName = sliderContext.querySelector(".slider__name"); | |
const sliderTitle = sliderContext.querySelector(".slider__title"); | |
const sliderContent = slider.querySelector(".slider__content"); | |
const sliderContentLength = playerPlayList.length - 1; | |
const sliderWidth = 100; | |
let left = 0; | |
let count = 0; | |
let song = playerSongs[count]; | |
let isPlay = false; | |
const pauseIcon = playButton.querySelector("img[alt = 'pause-icon']"); | |
const playIcon = playButton.querySelector("img[alt = 'play-icon']"); | |
const progres = player.querySelector(".progres"); | |
const progresFilled = progres.querySelector(".progres__filled"); | |
let isMove = false; | |
// creat functions | |
function openPlayer() { | |
playerHeader.classList.add("open-header"); | |
playerControls.classList.add("move"); | |
slider.classList.add("open-slider"); | |
} | |
function closePlayer() { | |
playerHeader.classList.remove("open-header"); | |
playerControls.classList.remove("move"); | |
slider.classList.remove("open-slider"); | |
} | |
function next(index) { | |
count = index || count; | |
if (count == sliderContentLength) { | |
count = count; | |
return; | |
} | |
left = (count + 1) * sliderWidth; | |
left = Math.min(left, (sliderContentLength) * sliderWidth); | |
sliderContent.style.transform = `translate3d(-${left}%, 0, 0)`; | |
count++; | |
run(); | |
} | |
function back(index) { | |
count = index || count; | |
if (count == 0) { | |
count = count; | |
return; | |
} | |
left = (count - 1) * sliderWidth; | |
left = Math.max(0, left); | |
sliderContent.style.transform = `translate3d(-${left}%, 0, 0)`; | |
count--; | |
run(); | |
} | |
function changeSliderContext() { | |
sliderContext.style.animationName = "opacity"; | |
sliderName.textContent = playerPlayList[count].querySelector(".player__title").textContent; | |
sliderTitle.textContent = playerPlayList[count].querySelector(".player__song-name").textContent; | |
if (sliderName.textContent.length > 16) { | |
const textWrap = document.createElement("span"); | |
textWrap.className = "text-wrap"; | |
textWrap.innerHTML = sliderName.textContent + " " + sliderName.textContent; | |
sliderName.innerHTML = ""; | |
sliderName.append(textWrap); | |
} | |
if (sliderTitle.textContent.length >= 18) { | |
const textWrap = document.createElement("span"); | |
textWrap.className = "text-wrap"; | |
textWrap.innerHTML = sliderTitle.textContent + " " + sliderTitle.textContent; | |
sliderTitle.innerHTML = ""; | |
sliderTitle.append(textWrap); | |
} | |
} | |
function changeBgBody() { | |
body.style.backgroundColor = bgBody[count]; | |
} | |
function selectSong() { | |
song = playerSongs[count]; | |
for (const item of playerSongs) { | |
if (item != song) { | |
item.pause(); | |
item.currentTime = 0; | |
} | |
} | |
if (isPlay) song.play(); | |
} | |
function run() { | |
changeSliderContext(); | |
changeBgBody(); | |
selectSong(); | |
} | |
function playSong() { | |
if (song.paused) { | |
song.play(); | |
playIcon.style.display = "none"; | |
pauseIcon.style.display = "block"; | |
}else{ | |
song.pause(); | |
isPlay = false; | |
playIcon.style.display = ""; | |
pauseIcon.style.display = ""; | |
} | |
} | |
function progresUpdate() { | |
const progresFilledWidth = (this.currentTime / this.duration) * 100 + "%"; | |
progresFilled.style.width = progresFilledWidth; | |
if (isPlay && this.duration == this.currentTime) { | |
next(); | |
} | |
if (count == sliderContentLength && song.currentTime == song.duration) { | |
playIcon.style.display = "block"; | |
pauseIcon.style.display = ""; | |
isPlay = false; | |
} | |
} | |
function scurb(e) { | |
// If we use e.offsetX, we have trouble setting the song time, when the mousemove is running | |
const currentTime = ( (e.clientX - progres.getBoundingClientRect().left) / progres.offsetWidth ) * song.duration; | |
song.currentTime = currentTime; | |
} | |
function durationSongs() { | |
let min = parseInt(this.duration / 60); | |
if (min < 10) min = "0" + min; | |
let sec = parseInt(this.duration % 60); | |
if (sec < 10) sec = "0" + sec; | |
const playerSongTime = `${min}:${sec}`; | |
this.closest(".player__song").querySelector(".player__song-time").append(playerSongTime); | |
} | |
changeSliderContext(); | |
// add events | |
sliderContext.addEventListener("click", openPlayer); | |
sliderContext.addEventListener("animationend", () => sliderContext.style.animationName =''); | |
playlistButton.addEventListener("click", closePlayer); | |
nextButton.addEventListener("click", () => { | |
next(0) | |
}); | |
backButton.addEventListener("click", () => { | |
back(0) | |
}); | |
playButton.addEventListener("click", () => { | |
isPlay = true; | |
playSong(); | |
}); | |
playerSongs.forEach(song => { | |
song.addEventListener("loadeddata" , durationSongs); | |
song.addEventListener("timeupdate" , progresUpdate); | |
}); | |
progres.addEventListener("pointerdown", (e) => { | |
scurb(e); | |
isMove = true; | |
}); | |
document.addEventListener("pointermove", (e) => { | |
if (isMove) { | |
scurb(e); | |
song.muted = true; | |
} | |
}); | |
document.addEventListener("pointerup", () => { | |
isMove = false; | |
song.muted = false; | |
}); | |
playerPlayList.forEach((item, index) => { | |
item.addEventListener("click", function() { | |
if (index > count) { | |
next(index - 1); | |
return; | |
} | |
if (index < count) { | |
back(index + 1); | |
return; | |
} | |
}); | |
}); |
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@700&display=swap'); | |
html { | |
box-sizing: border-box ; | |
--parent-height : 20em ; | |
--duration: 1s ; | |
--duration-text-wrap: 12s 1.5s cubic-bezier(0.82, 0.82, 1, 1.01) ; | |
--cubic-header: var(--duration) cubic-bezier(0.71, 0.21, 0.3, 0.95) ; | |
--cubic-slider : var(--duration) cubic-bezier(0.4, 0, 0.2, 1) ; | |
--cubic-play-list : .35s var(--duration) cubic-bezier(0, 0.85, 0.11, 1.64) ; | |
--cubic-slider-context : cubic-bezier(1, -0.01, 1, 1.01) ; | |
} | |
html *, | |
html *::before, | |
html *::after { | |
box-sizing: inherit ; | |
scrollbar-width: none ; | |
} | |
body{ | |
margin: 0 ; | |
height: 100vh ; | |
display: flex ; | |
user-select: none ; | |
align-items: center ; | |
justify-content: center ; | |
background-color: #e5e7e9 ; | |
font-family: 'Quicksand', sans-serif ; | |
-webkit-tap-highlight-color: transparent ; | |
transition: background-color var(--cubic-slider) ; | |
} | |
.img { | |
width: 100% ; | |
flex-shrink: 0; | |
display: block ; | |
object-fit: cover ; | |
} | |
.list { | |
margin: 0 ; | |
padding: 0 ; | |
list-style-type: none ; | |
} | |
.flex { | |
display: flex ; | |
align-items: center ; | |
justify-content: space-between ; | |
} | |
.uppercase{ | |
text-transform: uppercase ; | |
} | |
.player { | |
width: 17.15em ; | |
display: flex ; | |
overflow: hidden ; | |
font-size: 1.22em ; | |
border-radius: 1.35em ; | |
flex-direction: column ; | |
background-color: white ; | |
height: var(--parent-height) ; | |
} | |
.player__header { | |
z-index: 1 ; | |
gap: 0 .4em ; | |
width: 100% ; | |
display: flex; | |
height: 5.85em ; | |
flex-shrink: 0 ; | |
position: relative; | |
align-items: flex-start ; | |
border-radius: inherit ; | |
justify-content: flex-end ; | |
background-color: white ; | |
padding: .95em 0.6em 0 1.2em ; | |
box-shadow: 0 2px 6px 1px #0000001f ; | |
transition: height var(--cubic-header), box-shadow var(--duration), padding var(--duration) ease-in-out ; | |
} | |
.player__header.open-header { | |
height: 100% ; | |
padding-left: 0 ; | |
padding-right: 0 ; | |
box-shadow: unset ; | |
} | |
.player__img { | |
width: 3.22em ; | |
height: 3.22em ; | |
border-radius: 1.32em ; | |
} | |
.player__img--absolute { | |
top: 1.4em ; | |
left: 1.2em ; | |
position: absolute ; | |
} | |
.slider { | |
flex-shrink: 0 ; | |
overflow: hidden ; | |
transition: width var(--cubic-header), height var(--cubic-header), top var(--cubic-header), left var(--cubic-header); | |
} | |
.slider.open-slider{ | |
top: 0 ; | |
left: 0 ; | |
width: 100% ; | |
height: 14.6em ; | |
} | |
.slider__content { | |
display: flex ; | |
height: 100% ; | |
will-change : transform ; | |
transition: transform var(--cubic-slider); | |
} | |
.slider__img { | |
filter: brightness(75%) ; | |
} | |
.slider__name, | |
.slider__title { | |
overflow: hidden ; | |
white-space: nowrap ; | |
} | |
.text-wrap { | |
display: block ; | |
white-space: pre ; | |
width: fit-content ; | |
animation: text-wrap var(--duration-text-wrap) infinite ; | |
} | |
@keyframes text-wrap { | |
75%{ | |
transform: translate3d(-51.5%, 0, 0) ; | |
} | |
100%{ | |
transform: translate3d(-51.5%, 0, 0) ; | |
} | |
} | |
.player__button { | |
all: unset ; | |
z-index: 100 ; | |
width: 2.5em ; | |
height: 2.5em ; | |
cursor: pointer ; | |
} | |
.playlist { | |
transform: scale(0) ; | |
transition: transform calc(var(--duration) / 2) ; | |
} | |
.slider.open-slider .playlist { | |
transform: scale(1) ; | |
transition: transform var(--cubic-play-list) ; | |
} | |
.player__button--absolute--nw { | |
top: 5.5% ; | |
left: 5.5% ; | |
position: absolute ; | |
} | |
.player__button--absolute--center { | |
top: 0 ; | |
left: 0 ; | |
right: 0 ; | |
bottom: 0 ; | |
margin: auto ; | |
position: absolute ; | |
} | |
img[alt ="pause-icon"] { | |
display: none ; | |
} | |
.player__controls { | |
width: 77% ; | |
gap: .5em 0 ; | |
display: flex ; | |
flex-wrap: wrap ; | |
align-items: center ; | |
will-change: contents ; | |
align-content: center ; | |
justify-content: center ; | |
transition: transform var(--cubic-header) , width var(--cubic-header) ; | |
} | |
.player__controls.move { | |
width: 88% ; | |
transform: translate3d(-1.1em , calc(var(--parent-height) - 153%) , 0) ; | |
} | |
.player__context { | |
margin: 0 ; | |
width: 100% ; | |
display: flex ; | |
line-height: 1.8 ; | |
flex-direction: column ; | |
justify-content: center ; | |
text-transform: capitalize ; | |
} | |
.slider__context { | |
width: 56.28% ; | |
cursor: pointer ; | |
text-align: center ; | |
padding-bottom: .2em ; | |
will-change: contents ; | |
transition: width var(--cubic-header) ; | |
animation: calc(var(--duration) / 2) var(--cubic-slider-context) ; | |
} | |
@keyframes opacity { | |
0% { | |
opacity: 0 ; | |
} | |
90%{ | |
opacity: 1 ; | |
} | |
} | |
.player__controls.move .slider__context{ | |
width: 49.48% ; | |
} | |
.player__title { | |
font-size: .7em ; | |
font-weight: bold ; | |
color: #00000086 ; | |
} | |
.progres { | |
width: 90% ; | |
height: .25em ; | |
cursor: pointer ; | |
border-radius: 1em ; | |
touch-action : none ; | |
background-color: #e5e7ea ; | |
transition: width var(--cubic-header) ; | |
} | |
.player__controls.move .progres{ | |
width: 98% ; | |
} | |
.progres__filled { | |
width: 0% ; | |
height: 100% ; | |
display: flex ; | |
position: relative ; | |
align-items: center ; | |
border-radius: inherit ; | |
background-color: #78adfe ; | |
} | |
.progres__filled::before { | |
right: 0 ; | |
width: .35em ; | |
content: " " ; | |
height: .35em ; | |
border-radius: 50% ; | |
position: absolute ; | |
background-color: #5781bd ; | |
} | |
.player__playlist { | |
height: 100% ; | |
overflow: auto ; | |
padding: 1.05em .9em 0 1.2em ; | |
} | |
.player__playlist::-webkit-scrollbar { | |
width: 0 ; | |
} | |
.player__song { | |
/* gap: 0 .65em ; */ | |
display: flex ; | |
cursor: pointer ; | |
margin-bottom: .5em ; | |
padding-bottom: .7em ; | |
border-bottom: .1em solid #d8d8d859 ; | |
} | |
.player__song .player__context { | |
line-height: 1.5 ; | |
margin-left: .65em ; | |
} | |
.player__song-name { | |
font-size: .88em ; | |
} | |
.player__song-time { | |
font-size: .65em ; | |
font-weight: bold ; | |
color: #00000079 ; | |
height: fit-content ; | |
align-self: flex-end ; | |
} | |
.audio { | |
display: none !important ; | |
} | |