<!--
A slider with track fill, configurable tick marks and min/max labels
Design by Outcrowd https://dribbble.com/shots/9659984-Mobile-App-Mail-Service
-->
<div id="wrapper">
<div id="sliderContainer">
<div class="tick-slider">
<div class="tick-slider-header">
<h5><label for="weightSlider">Total weight</label></h5>
<h5>kg</h5>
</div>
<div class="tick-slider-value-container">
<div id="weightLabelMin" class="tick-slider-label">0</div>
<div id="weightLabelMax" class="tick-slider-label">40</div>
<div id="weightValue" class="tick-slider-value"></div>
</div>
<div class="tick-slider-background"></div>
<div id="weightProgress" class="tick-slider-progress"></div>
<div id="weightTicks" class="tick-slider-tick-container"></div>
<input
id="weightSlider"
class="tick-slider-input"
type="range"
min="0"
max="40"
step="5"
value="9"
data-tick-step="5"
data-tick-id="weightTicks"
data-value-id="weightValue"
data-progress-id="weightProgress"
data-handle-size="18"
data-min-label-id="weightLabelMin"
data-max-label-id="weightLabelMax"
/>
</div>
<div class="tick-slider">
<div class="tick-slider-header">
<h5><label for="sizeSlider">Total size</label></h5>
<h5>cm</h5>
</div>
<div class="tick-slider-value-container">
<div id="sizeLabelMin" class="tick-slider-label">0</div>
<div id="sizeLabelMax" class="tick-slider-label">300</div>
<div id="sizeValue" class="tick-slider-value"></div>
</div>
<div class="tick-slider-background"></div>
<div id="sizeProgress" class="tick-slider-progress"></div>
<div id="sizeTicks" class="tick-slider-tick-container"></div>
<input
id="sizeSlider"
class="tick-slider-input"
type="range"
min="0"
max="300"
step="25"
value="150"
data-tick-step="25"
data-tick-id="sizeTicks"
data-value-id="sizeValue"
data-progress-id="sizeProgress"
data-handle-size="18"
data-min-label-id="sizeLabelMin"
data-max-label-id="sizeLabelMax"
/>
</div>
</div>
</div>
<!-- Twitter link -->
<a class="twitter" style="position: fixed; left: 20px; bottom: 20px; opacity: 0.2;" href="https://twitter.com/park_narrative" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 72 72"><path fill="black" d="M67.812 16.141a26.246 26.246 0 0 1-7.519 2.06 13.134 13.134 0 0 0 5.756-7.244 26.127 26.127 0 0 1-8.313 3.176A13.075 13.075 0 0 0 48.182 10c-7.229 0-13.092 5.861-13.092 13.093 0 1.026.118 2.021.338 2.981-10.885-.548-20.528-5.757-26.987-13.679a13.048 13.048 0 0 0-1.771 6.581c0 4.542 2.312 8.551 5.824 10.898a13.048 13.048 0 0 1-5.93-1.638c-.002.055-.002.11-.002.162 0 6.345 4.513 11.638 10.504 12.84a13.177 13.177 0 0 1-3.449.457c-.846 0-1.667-.078-2.465-.231 1.667 5.2 6.499 8.986 12.23 9.09a26.276 26.276 0 0 1-16.26 5.606A26.21 26.21 0 0 1 4 55.976a37.036 37.036 0 0 0 20.067 5.882c24.083 0 37.251-19.949 37.251-37.249 0-.566-.014-1.134-.039-1.694a26.597 26.597 0 0 0 6.533-6.774z"></path></svg></a>
@import url("https://fonts.googleapis.com/css?family=Hind+Madurai:300,600|Poppins:300&display=swap");
:root {
--yellow: #ffd049;
--light-yellow: #fdf2d2;
--orange: #ffa929;
--light-gray: #e3e4e8;
--gray: #71738b;
--light-blue: #7a7c93;
--blue: #34385a;
--slider-handle-size: 14px;
--slider-handle-border-radius: 2px;
--slider-handle-margin-top: -4px;
--slider-track-height: 6px;
--slider-track-border-radius: 4px;
}
* {
box-sizing: border-box;
}
body {
margin: 0 auto;
}
#wrapper {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#sliderContainer {
width: 100%;
max-width: 440px;
padding: 56px 40px;
border-radius: 40px;
box-shadow: 0px 8px 40px rgba(128, 128, 128, 0.15);
}
#sliderContainer>div:first-child {
margin-bottom: 48px;
}
.tick-slider-header {
display: flex;
justify-content: space-between;
margin-bottom: 24px;
}
.tick-slider-header>h5 {
margin: 0;
font-family: "Poppins", sans-serif;
font-size: 18px;
font-weight: 300;
color: var(--gray);
}
.tick-slider {
position: relative;
width: 100%;
}
.tick-slider-value-container {
position: relative;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-family: "Hind Madurai", sans-serif;
font-size: 18px;
color: var(--gray);
}
.tick-slider-value {
position: absolute;
top: 0;
font-weight: bold;
color: var(--blue);
border-radius: var(--slider-handle-border-radius);
}
.tick-slider-value>div {
animation: bulge 0.3s ease-out;
}
.tick-slider-background,
.tick-slider-progress,
.tick-slider-tick-container {
position: absolute;
bottom: 5px;
left: 0;
height: var(--slider-track-height);
pointer-events: none;
border-radius: var(--slider-track-border-radius);
z-index: -1;
}
.tick-slider-background {
width: 100%;
background-color: var(--light-gray);
}
.tick-slider-progress {
background-color: var(--yellow);
}
.tick-slider-tick-container {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 calc(var(--slider-handle-size) / 2);
}
.tick-slider-tick {
width: 2px;
height: 2px;
border-radius: 50%;
background-color: white;
}
.tick-slider-label {
opacity: 0.85;
transition: opacity 0.1s ease;
}
.tick-slider-label.hidden {
opacity: 0;
}
@keyframes bulge {
0% {
transform: scale(1);
}
25% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
/*
REMOVE SLIDER STYLE DEFAULTS
*/
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 100%;
background: transparent;
outline: none;
margin: 5px 0;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-moz-focus-outer {
border: 0;
}
/*
HANDLE
*/
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: var(--slider-handle-size);
height: var(--slider-handle-size);
background: var(--orange);
border-radius: var(--slider-handle-border-radius);
cursor: pointer;
margin-top: var(--slider-handle-margin-top);
-webkit-transform: scale(1);
transform: scale(1);
transition: transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
input[type="range"]:hover::-webkit-slider-thumb,
input[type="range"]:focus::-webkit-slider-thumb {
transform: scale(1.2);
}
input[type="range"]::-moz-range-thumb {
-webkit-appearance: none;
width: var(--slider-handle-size);
height: var(--slider-handle-size);
background: var(--orange);
border: none;
border-radius: var(--slider-handle-border-radius);
cursor: pointer;
transition: transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
input[type="range"]:hover::-moz-range-thumb,
input[type="range"]:focus::-moz-range-thumb {
transform: scale(1.2);
}
/*
TRACK
*/
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: var(--slider-track-height);
cursor: pointer;
background: none;
border-radius: var(--slider-track-border-radius);
}
input[type="range"]::-moz-range-track {
width: 100%;
height: var(--slider-track-height);
cursor: pointer;
background: none;
border-radius: var(--slider-track-border-radius);
}
input[type="range"]:focus::-webkit-slider-runnable-track {
background: none;
}
input[type="range"]:active::-webkit-slider-runnable-track {
background: none;
}
function init() {
const sliders = document.getElementsByClassName("tick-slider-input");
for (let slider of sliders) {
slider.oninput = onSliderInput;
updateValue(slider);
updateValuePosition(slider);
updateLabels(slider);
updateProgress(slider);
setTicks(slider);
}
}
function onSliderInput(event) {
updateValue(event.target);
updateValuePosition(event.target);
updateLabels(event.target);
updateProgress(event.target);
}
function updateValue(slider) {
let value = document.getElementById(slider.dataset.valueId);
value.innerHTML = "<div>" + slider.value + "</div>";
}
function updateValuePosition(slider) {
let value = document.getElementById(slider.dataset.valueId);
const percent = getSliderPercent(slider);
const sliderWidth = slider.getBoundingClientRect().width;
const valueWidth = value.getBoundingClientRect().width;
const handleSize = slider.dataset.handleSize;
let left = percent * (sliderWidth - handleSize) + handleSize / 2 - valueWidth / 2;
left = Math.min(left, sliderWidth - valueWidth);
left = slider.value === slider.min ? 0 : left;
value.style.left = left + "px";
}
function updateLabels(slider) {
const value = document.getElementById(slider.dataset.valueId);
const minLabel = document.getElementById(slider.dataset.minLabelId);
const maxLabel = document.getElementById(slider.dataset.maxLabelId);
const valueRect = value.getBoundingClientRect();
const minLabelRect = minLabel.getBoundingClientRect();
const maxLabelRect = maxLabel.getBoundingClientRect();
const minLabelDelta = valueRect.left - (minLabelRect.left);
const maxLabelDelta = maxLabelRect.left - valueRect.left;
const deltaThreshold = 32;
if (minLabelDelta < deltaThreshold) minLabel.classList.add("hidden");
else minLabel.classList.remove("hidden");
if (maxLabelDelta < deltaThreshold) maxLabel.classList.add("hidden");
else maxLabel.classList.remove("hidden");
}
function updateProgress(slider) {
let progress = document.getElementById(slider.dataset.progressId);
const percent = getSliderPercent(slider);
progress.style.width = percent * 100 + "%";
}
function getSliderPercent(slider) {
const range = slider.max - slider.min;
const absValue = slider.value - slider.min;
return absValue / range;
}
function setTicks(slider) {
let container = document.getElementById(slider.dataset.tickId);
const spacing = parseFloat(slider.dataset.tickStep);
const sliderRange = slider.max - slider.min;
const tickCount = sliderRange / spacing + 1; // +1 to account for 0
for (let ii = 0; ii < tickCount; ii++) {
let tick = document.createElement("span");
tick.className = "tick-slider-tick";
container.appendChild(tick);
}
}
function onResize() {
const sliders = document.getElementsByClassName("tick-slider-input");
for (let slider of sliders) {
updateValuePosition(slider);
}
}
window.onload = init;
window.addEventListener("resize", onResize);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.