Skip to content

Instantly share code, notes, and snippets.

@tuliopc23
Created October 11, 2025 23:28
Show Gist options
  • Save tuliopc23/22dae64177e9609c73fc9b825d6360cf to your computer and use it in GitHub Desktop.
Save tuliopc23/22dae64177e9609c73fc9b825d6360cf to your computer and use it in GitHub Desktop.
Slider Button Liquid Glass Apple iOS 26 - 2025
<!-- developed © Maxuiux -->
<div class="slider-container" id="slider">
<div class="slider-progress" id="progress"></div>
<div class="slider-thumb-glass" id="thumb">
<div class="slider-thumb-glass-filter"></div>
<div class="slider-thumb-glass-overlay"></div>
<div class="slider-thumb-glass-specular"></div>
</div>
</div>
<svg width="0" height="0">
<filter id="mini-liquid-lens" x="-50%" y="-50%" width="200%" height="200%">
<feImage x="0" y="0" result="normalMap" xlink:href="data:image/svg+xml;utf8,
<svg xmlns='http://www.w3.org/2000/svg' width='300' height='300'>
<radialGradient id='invmap' cx='50%' cy='50%' r='75%'>
<stop offset='0%' stop-color='rgb(128,128,255)'/>
<stop offset='90%' stop-color='rgb(255,255,255)'/>
</radialGradient>
<rect width='100%' height='100%' fill='url(#invmap)'/>
</svg>" />
<feDisplacementMap in="SourceGraphic" in2="normalMap" scale="-252" xChannelSelector="R" yChannelSelector="G"
result="displaced" />
<feMerge>
<feMergeNode in="displaced" />
</feMerge>
</filter>
</svg>
<!-- developed © Maxuiux -->
/* developed © Maxuiux */
;(() => {
const slider = document.getElementById('slider')
const progress = document.getElementById('progress')
const thumb = document.getElementById('thumb')
let isDragging = false
let sliderRect = slider.getBoundingClientRect()
const updateThumbAndProgress = (percent) => {
percent = Math.max(0, Math.min(100, percent))
const px = (percent / 100) * sliderRect.width
progress.style.width = `${percent}%`
thumb.style.left = `${px}px`
}
const getPercentFromClientX = (clientX) => {
const offsetX = clientX - sliderRect.left
return (offsetX / sliderRect.width) * 100
}
const onMove = (clientX) => {
const percent = getPercentFromClientX(clientX)
updateThumbAndProgress(percent)
}
const onMouseDown = (e) => {
isDragging = true
sliderRect = slider.getBoundingClientRect()
onMove(e.clientX)
thumb.classList.add('active')
}
const onTouchStart = (e) => {
isDragging = true
sliderRect = slider.getBoundingClientRect()
onMove(e.touches[0].clientX)
thumb.classList.add('active')
}
const onMouseMove = (e) => {
if (isDragging) onMove(e.clientX)
}
const onTouchMove = (e) => {
if (isDragging) onMove(e.touches[0].clientX)
}
const stopDrag = () => {
isDragging = false
thumb.classList.remove('active')
}
const init = (initialValue = 40) => {
sliderRect = slider.getBoundingClientRect()
updateThumbAndProgress(initialValue)
}
// Events
thumb.addEventListener('mousedown', onMouseDown)
thumb.addEventListener('touchstart', onTouchStart, { passive: true })
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', stopDrag)
document.addEventListener('touchmove', onTouchMove, { passive: false })
document.addEventListener('touchend', stopDrag)
slider.addEventListener('mousedown', (e) => {
sliderRect = slider.getBoundingClientRect()
onMove(e.clientX)
})
slider.addEventListener(
'touchstart',
(e) => {
sliderRect = slider.getBoundingClientRect()
onMove(e.touches[0].clientX)
},
{ passive: true }
)
init(40)
})()
/* developed © Maxuiux */
/* developed © Maxuiux */
html {
box-sizing: border-box;
scroll-behavior: smooth;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
body {
font-family: "Inter", sans-serif;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
height: 100dvh;
background-color: #f8f8f8;
/* background-color: #606060; */
}
input {
border: initial;
outline: none;
}
button {
border: initial;
background: initial;
cursor: pointer;
}
.slider-container {
position: relative;
width: 320px;
height: 10px;
background: #D6D6DA;
border-radius: 999px;
}
.slider-progress {
position: absolute;
height: 100%;
background: linear-gradient(117deg, #49a3fc 0%, #3681ee 100%);
border-radius: 999px;
width: 0%;
z-index: 1;
}
.slider-thumb-glass {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 65px;
height: 42px;
border-radius: 999px;
cursor: pointer;
z-index: 2;
background-color: #fff;
box-shadow: 0 1px 8px 0 rgba(0, 30, 63, 0.1), 0 0 2px 0 rgba(0, 9, 20, 0.1);
overflow: hidden;
transition: transform 0.15s ease, height 0.15s ease;
}
.slider-thumb-glass-filter {
position: absolute;
inset: 0;
z-index: 0;
backdrop-filter: blur(0.6px);
-webkit-backdrop-filter: blur(0.6px);
filter: url(#mini-liquid-lens);
}
.slider-thumb-glass-overlay {
position: absolute;
inset: 0;
z-index: 1;
background-color: rgba(255, 255, 255, 0.1);
}
.slider-thumb-glass-specular {
position: absolute;
inset: 0;
z-index: 2;
border-radius: inherit;
box-shadow:
inset 1px 1px 0 rgba(69, 168, 243, 0.2),
inset 1px 3px 0 rgba(28, 63, 90, 0.05),
inset 0 0 22px rgb(255 255 255 / 60%),
inset -1px -1px 0 rgba(69, 168, 243, 0.12);
}
.slider-thumb-glass-filter,
.slider-thumb-glass-overlay,
.slider-thumb-glass-specular {
opacity: 0;
}
.slider-thumb-glass.active {
background-color: transparent;
box-shadow: none;
}
.slider-thumb-glass.active .slider-thumb-glass-filter,
.slider-thumb-glass.active .slider-thumb-glass-overlay,
.slider-thumb-glass.active .slider-thumb-glass-specular {
opacity: 1;
}
.slider-thumb-glass:active {
transform: translate(-50%, -50%) scaleY(0.98) scaleX(1.1);
}
/* developed © Maxuiux */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment