CRG-20-001
ジェリースイッチJelly Switch
.cg-lq-switch {
position: relative;
width: 140px;
height: 72px;
border: none;
border-radius: 9999px;
background: linear-gradient(180deg, #FDFDFE, #F0F1F4 55%, #FAFBFC);
box-shadow: 0 10px 30px rgba(0, 0, 0, .08),
inset 0 2px 4px rgba(255, 255, 255, .9),
inset 0 -2px 5px rgba(30, 50, 80, .06);
cursor: pointer;
}
.cg-lq-switch .goo {
position: absolute;
inset: 0;
filter: url(#cg-lq-sw-goo);
}
.cg-lq-switch i {
position: absolute;
border-radius: 50%;
background: radial-gradient(circle at 38% 30%, #B7EDFF, rgba(100, 217, 255, .85) 45%, #35A8DE);
}
.cg-lq-switch .knob { top: 6px; left: 6px; width: 60px; height: 60px; }
.cg-lq-switch .tail { top: 18px; left: 18px; width: 36px; height: 36px; opacity: .85; }
.cg-lq-switch .shine {
position: absolute;
top: 14px;
left: 18px;
width: 22px;
height: 12px;
border-radius: 9999px;
background: linear-gradient(180deg, rgba(255, 255, 255, .95), transparent);
filter: blur(1px);
pointer-events: none;
}
.cg-lq-switch[aria-checked="true"] {
box-shadow: 0 10px 30px rgba(0, 0, 0, .08),
inset 0 2px 4px rgba(255, 255, 255, .9),
inset 0 0 18px rgba(100, 217, 255, .35);
}
<button class="cg-lq-switch" type="button" role="switch" aria-checked="false"><svg width="0" height="0" style="position:absolute"><filter id="cg-lq-sw-goo"><feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/><feColorMatrix in="b" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -9"/></filter></svg><span class="goo"><i class="tail"></i><i class="knob"></i></span><span class="shine"></span></button>
(function () {
var btn = document.querySelector('.cg-lq-switch');
if (!btn) return;
var knob = btn.querySelector('.knob');
var tail = btn.querySelector('.tail');
var shine = btn.querySelector('.shine');
var TRAVEL = 68;
/* ミニSpring: pos/velを積分するだけの15行物理エンジン */
function makeSpring(stiff, damp, mass) {
return { p: 0, v: 0, t: 0, step: function (dt) {
var f = (this.t - this.p) * stiff - this.v * damp;
this.v += (f / mass) * dt;
this.p += this.v * dt;
} };
}
var main = makeSpring(280, 16, 1.1);
var lazy = makeSpring(150, 18, 1.6);
btn.addEventListener('click', function () {
var on = btn.getAttribute('aria-checked') === 'true';
btn.setAttribute('aria-checked', on ? 'false' : 'true');
main.t = lazy.t = on ? 0 : TRAVEL;
if (navigator.vibrate) { try { navigator.vibrate(8); } catch (e) {} }
});
var last = performance.now();
(function loop(now) {
var dt = Math.min(.032, (now - last) / 1000);
last = now;
main.step(dt); lazy.step(dt);
/* 速度からsquash&stretchを導出(ここがゼリーの正体) */
var s = Math.max(-1, Math.min(1, main.v / 540));
var sx = 1 + Math.abs(s) * .4, sy = 1 - Math.abs(s) * .28;
knob.style.transform = 'translateX(' + main.p + 'px) skewX(' + (-s * 8) + 'deg) scale(' + sx + ',' + sy + ')';
tail.style.transform = 'translateX(' + lazy.p + 'px)';
shine.style.transform = 'translateX(' + main.p + 'px)';
requestAnimationFrame(loop);
})(last);
})();
GROSS WT. 3116 B
+JSORIGINAL