<section class="device">
<div class="device__top">
<img class="album-art" src="https://res.cloudinary.com/andrewcanham/image/upload/v1579132801/everything-everything.jpg" alt="album art" />
<img class="album-art" src="https://res.cloudinary.com/andrewcanham/image/upload/v1579132801/jamie-xx.jpg" alt="album art" />
<img class="album-art" src="https://res.cloudinary.com/andrewcanham/image/upload/v1579132801/gidge.jpg" alt="album art" />
</div>
<div class="device__mid">
<div class="info">
<hgroup class="info__left">
<h1 class="info__song">
<span class="song">No Reptiles</span>
<span class="song">Gosh</span>
<span class="song">Norrland</span>
</h1>
<h2 class="info__artist">
<span class="artist">by Everything Everything</span>
<span class="artist">by Jamie xx</span>
<span class="artist">by Gidge</span>
</h2>
</hgroup>
<hgroup class="info__right">
<h1 class="info__type">Playlist <span id="current-song">1</span> of 3</h1>
<h2 class="info__type-name">My faves</h2>
</hgroup>
</div>
</div>
<div class="device__bottom">
<div class="progress">
<input id="slider" type="range" value="0" min="0" max="1800" step="1" />
</div>
<div class="equaliser"></div>
<div class="controls">
<button class="controls__round-button" id="previous-button">
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.13672 5L9.5 0.5V9.5L3.13672 5ZM0.5 0.5H2.01172V9.5H0.5V0.5Z" />
</svg>
<span class="sr-only">Previous</span>
</button>
<button class="controls__round-button controls__round-button--large" id="play-button">
<div class="play">
<svg class="controls__play" width="14" height="18" viewBox="0 0 14 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.0195312 0.269531L13.7305 9L0.0195312 17.7305V0.269531Z"/>
</svg>
<span class="sr-only">Play</span>
</div>
<div class="pause">
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5195 0.269531H15.5V17.7305H10.5195V0.269531ZM0.5 17.7305V0.269531H5.48047V17.7305H0.5Z" fill="#728C98"/>
</svg>
<span class="sr-only">Pause</span>
</div>
</button>
<button class="controls__round-button" id="next-button">
<svg aria-hidden="true" focusable="false" width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.98828 0.5H9.5V9.5H7.98828V0.5ZM0.5 9.5V0.5L6.86328 5L0.5 9.5Z" />
</svg>
<span class="sr-only">Next</span>
</button>
</div>
</div>
</section>
// font
@import url('https://fonts.googleapis.com/css?family=Roboto:300,700&display=swap');
// colours
$palest: #F7FBFD;
$pale: #EFF5F9;
$mid: #AEBEC6;
$base: #728C98;
$shade: #4E86A5;
$bright: #49C6FF;
$glow: lighten($bright, 10%);
// variables
// ---------
// Change this to change the size of the player
// The entire design scales from this
$baseFontSize: 12px;
html {
font-size: $baseFontSize;
}
body {
background: $pale;
color: $base;
font-family: 'Roboto', sans serif;
font-weight: 300;
}
.sr-only:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(100%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
// device styling, layout
.device {
background: $palest;
border-radius: 2.4rem;
box-shadow: 2rem 2rem 8rem rgba($shade, 0.09), 1rem 1rem 4rem rgba($shade, 0.09), inset 4rem 4rem 10rem rgba($shade, 0.05);
display: flex;
flex-direction: column;
height: 50rem;
left: 50%;
overflow: hidden;
position: absolute;
top: 50%;
transform: translate3D(-50%,-50%,0);
width: 26.8rem;
}
.device__top {
background: rgba(255,255,255,0.6);
height: 27.2rem;
overflow: hidden;
position: relative;
}
.album-art {
height: 100%;
object-fit: cover;
width: 100%;
position: absolute;
transform: translateY(100%);
}
.album-art.active {
transform: translateY(0);
}
.device__mid {
flex: 1;
}
// information about current track, playlist etc.
.info {
display: flex;
font-size: 0.9rem;
padding: 2rem 3rem;
}
.info__right {
flex: 1;
text-align: right;
}
.info__song {
font-weight: 700;
height: 1.6rem;
margin: 0;
overflow: hidden;
padding: 0 0 0.4rem;
position: relative;
}
.song {
display: block;
position: absolute;
transform: translateY(150%);
}
.song.active {
transform: translateY(0);
}
.info__artist {
font-size: 1rem;
font-weight: 300;
height: 1.2rem;
margin: 0;
overflow: hidden;
padding: 0;
position: relative;
width: 12rem;
}
.artist {
display: block;
left: 0;
top: 0;
position: absolute;
transform: translateY(150%);
}
.artist.active {
transform: translateY(0);
}
.info__type {
color: $mid;
font-size: 0.8rem;
font-weight: 700;
margin: 0.4rem 0 0.3rem;
padding: 0 0 0.3rem;
text-transform: uppercase;
}
.info__type-name {
font-size: 1rem;
font-weight: 300;
margin: 0;
padding: 0;
}
// controls
.controls {
align-items: center;
display: flex;
justify-content: center;
}
.progress {
height: 0.5rem;
margin: 3rem 0 3.6rem;
position: relative;
}
#play-button {
.pause {
display: none;
}
.play {
display: block;
}
}
#play-button.pause {
.pause {
display: block;
}
.play {
display: none;
}
}
.controls__round-button {
background: rgba(#fff, 0.5);
border-radius: 10rem;
box-shadow:
1rem 1rem 4rem rgba(78, 134, 165, 0.09),
0.5rem 0.5rem 2rem rgba(78, 134, 165, 0.09),
-0.5rem -1.5rem 2rem rgba(255, 255, 255, 1),
inset 1rem 1rem 2.3rem rgba(78, 134, 165, 0.05),
0px 0px 0.1rem #FFFFFF,
inset 0.1rem 0.1rem 0 #FFFFFF;
height: 5rem;
margin: 0 1rem 3rem;
position: relative;
transition: box-shadow 0.05s ease-in;
width: 5rem;
svg {
height: 1.6rem;
left: 50%;
position: absolute;
top: 50%;
transform: translate3d(-50%,-50%,0);
width: 1.6rem;
path {
fill: $base;
transition: fill 0.05s ease-in;
}
}
}
.controls__round-button:active {
* {
fill: $bright;
filter: drop-shadow(0 0 0.1rem rgba($glow, 0.5));
}
box-shadow:
1rem 1rem 4rem rgba(78, 134, 165, 0),
0 0.1rem 0.1rem rgba(78, 134, 165, 0.25),
-0.5rem -1.5rem 2rem rgba(255, 255, 255, 0),
inset 1rem 1rem 2.3rem rgba(78, 134, 165, 0.05),
0 0.1rem 0.1rem rgba(255,255,255,1),
inset 0.1rem -0.1rem 0 rgba(255,255,255,0);
}
.controls__round-button--large {
height: 7.5rem;
text-align: center;
width: 7.5rem;
svg {
height: 2.6rem;
width: 2.6rem;
}
}
.controls__play {
margin-left: 0.4rem;
}
// button reset
button {
border: none;
color: $base;
cursor: pointer;
display: inline-block;
font-family: "roboto", sans-serif;
font-size: 1rem;
line-height: 1;
margin: 0;
padding: 1rem;
text-align: center;
text-decoration: none;
-webkit-appearance: none;
-moz-appearance: none;
}
button:hover,
button:focus {
background: #fff;
}
button:focus {
outline: none;
}
button:active {
}
// slider
input[type=range] {
background: transparent;
height: 2.5rem;
-webkit-appearance: none;
margin: 0.1rem 3rem;
width: calc(100% - 6rem);
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 0.5rem;
cursor: pointer;
animate: 0.2s;
border: 0;
background: rgba(78, 134, 165, 0.03);
border-radius: 1rem;
bottom: 0;
box-shadow:
0.3rem 0.3rem 1rem #FFFFFF,
-0.3rem -0.2rem 0.8rem rgba(78, 134, 165, 0.03),
inset 1rem 1rem 2.3rem rgba(78, 134, 165, 0.05),
inset 0.1rem 0.1rem 0 rgba(78, 134, 165, 0.05);
}
input[type=range]::-webkit-slider-thumb {
border: 0;
cursor: pointer;
-webkit-appearance: none;
margin-top: -6px;
background: $palest;
border-radius: 1rem;
box-shadow:
0.2rem 0.2rem 1.2rem rgba(78, 134, 165, 0.12),
0.1rem 0.1rem 0.5rem rgba(78, 134, 165, 0.12),
0 0 0.1rem #fff,
inset 0.2rem 0.2rem 0.5rem rgba(78, 134, 165, 0.05),
inset 0.2rem 0.2rem 0 #fff;
height: 1.4rem;
padding: 0;
width: 1.4rem;
}
input[type=range]::-webkit-slider-thumb:hover {
background: #fff;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: rgba($bright, 0.5);
}
input[type=range]::-moz-range-track {
width: 100%;
height: 0.5rem;
cursor: pointer;
animate: 0.2s;
border: 0;
background: rgba(78, 134, 165, 0.03);
border-radius: 1rem;
bottom: 0;
box-shadow:
0.3rem 0.3rem 1rem #FFFFFF,
-0.3rem -0.2rem 0.8rem rgba(78, 134, 165, 0.03),
inset 1rem 1rem 2.3rem rgba(78, 134, 165, 0.05),
inset 0.1rem 0.1rem 0 rgba(78, 134, 165, 0.05);
}
input[type=range]::-moz-range-thumb {
border: 0;
cursor: pointer;
-webkit-appearance: none;
margin-top: -6px;
background: $palest;
border-radius: 1rem;
box-shadow:
0.2rem 0.2rem 1.2rem rgba(78, 134, 165, 0.12),
0.1rem 0.1rem 0.5rem rgba(78, 134, 165, 0.12),
0 0 0.1rem #fff,
inset 0.2rem 0.2rem 0.5rem rgba(78, 134, 165, 0.05),
inset 0.2rem 0.2rem 0 #fff;
height: 1.4rem;
padding: 0;
width: 1.4rem;
}
input[type=range]::-ms-track {
width: 100%;
height: 0.5rem;
cursor: pointer;
animate: 0.2s;
border: 0;
background: rgba(78, 134, 165, 0.03);
border-radius: 1rem;
bottom: 0;
box-shadow:
0.3rem 0.3rem 1rem #FFFFFF,
-0.3rem -0.2rem 0.8rem rgba(78, 134, 165, 0.03),
inset 1rem 1rem 2.3rem rgba(78, 134, 165, 0.05),
inset 0.1rem 0.1rem 0 rgba(78, 134, 165, 0.05);
}
input[type=range]::-ms-fill-lower {
}
input[type=range]::-ms-fill-upper {
}
input[type=range]::-ms-thumb {
border: 0;
cursor: pointer;
-webkit-appearance: none;
margin-top: -6px;
background: $palest;
border-radius: 1rem;
box-shadow:
0.2rem 0.2rem 1.2rem rgba(78, 134, 165, 0.12),
0.1rem 0.1rem 0.5rem rgba(78, 134, 165, 0.12),
0 0 0.1rem #fff,
inset 0.2rem 0.2rem 0.5rem rgba(78, 134, 165, 0.05),
inset 0.2rem 0.2rem 0 #fff;
height: 1.4rem;
padding: 0;
width: 1.4rem;
}
input[type=range]:focus::-ms-fill-lower {
}
input[type=range]:focus::-ms-fill-upper {
}
View Compiled
// set variables
let currentSong = 0, maxSong, playing = false, position = 0, maxPosition = 1800, pause = false;
// grab relevant element references
const elements = {
images: document.getElementsByClassName("album-art"),
songs: document.getElementsByClassName("song"),
artists: document.getElementsByClassName("artist"),
play: document.getElementById("play-button"),
previous: document.getElementById("previous-button"),
next: document.getElementById("next-button"),
currentSong: document.getElementById("current-song"),
slider: document.getElementById("slider")
}
// controlling the DOM
function next() {
updateDOM('remove');
currentSong++;
if (currentSong > maxSong) {
currentSong = 0;
}
updateDOM('add');
elements.slider.value = 0;
position = 0;
}
function previous() {
updateDOM('remove');
currentSong--;
if (currentSong < 0) {
currentSong = maxSong;
}
updateDOM('add');
elements.slider.value = 0;
}
function updateDOM(action) {
elements.currentSong.innerHTML = currentSong + 1;
if (action === 'add') {
elements.images[currentSong].classList.add("active");
elements.songs[currentSong].classList.add("active");
elements.artists[currentSong].classList.add("active");
} else {
elements.images[currentSong].classList.remove("active");
elements.songs[currentSong].classList.remove("active");
elements.artists[currentSong].classList.remove("active");
}
}
function playBar() {
if (!pause) {
setTimeout(function() {
elements.slider.value = position++;
if (position > maxPosition) {
position = 0;
next();
}
playBar();
}, 10);
}
}
function play() {
if (!playing) {
pause = false;
playBar();
elements.play.classList.add("pause");
} else {
pause = true;
elements.play.classList.remove("pause");
}
playing = !playing;
}
function sliderChange() {
position = elements.slider.value;
}
// initial setup
function init() {
// setup first image
elements.images[currentSong].classList.toggle("active");
elements.songs[currentSong].classList.toggle("active");
elements.artists[currentSong].classList.toggle("active");
maxSong = elements.images.length - 1;
// event listeners for controls
elements.next.addEventListener("click", function() {
next();
});
elements.previous.addEventListener("click", function() {
previous();
});
elements.play.addEventListener("click", function(){
play();
});
elements.slider.oninput = sliderChange;
}
init();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.