<div class="grid"> <label class="radio"> <input type="radio" name="r" value="1" checked /> <svg viewBox="0 0 24 24" filter="url(#goo-light)"> <circle class="top" cx="12" cy="-12" r="8" /> <circle class="dot" cx="12" cy="12" r="5" /> <circle class="drop" cx="12" cy="12" r="2" /> </svg> </label> <label class="radio"> <input type="radio" name="r" value="2" /> <svg viewBox="0 0 24 24" filter="url(#goo-light)"> <circle class="top" cx="12" cy="-12" r="8" /> <circle class="dot" cx="12" cy="12" r="5" /> <circle class="drop" cx="12" cy="12" r="2" /> </svg> </label> <label class="switch"> <input type="checkbox" checked /> <svg viewBox="0 0 38 24" filter="url(#goo)"> <circle class="default" cx="12" cy="12" r="8" /> <circle class="dot" cx="26" cy="12" r="8" /> <circle class="drop" cx="25" cy="-1" r="2" /> </svg> </label> <label class="switch"> <input type="checkbox" /> <svg viewBox="0 0 38 24" filter="url(#goo)"> <circle class="default" cx="12" cy="12" r="8" /> <circle class="dot" cx="26" cy="12" r="8" /> </svg> </label> <label class="checkbox"> <input type="checkbox" checked /> <svg viewBox="0 0 24 24" filter="url(#goo-light)"> <path class="tick" d="M4.5 10L10.5 16L24.5 1" /> <circle class="dot" cx="10.5" cy="15.5" r="1.5" /> </svg> </label> <label class="checkbox"> <input type="checkbox" /> <svg viewBox="0 0 24 24" filter="url(#goo-light)"> <path class="tick" d="M4.5 10L10.5 16L24.5 1" /> <circle class="dot" cx="10.5" cy="15.5" r="1.5" /> <circle class="drop" cx="25" cy="-1" r="2" /> </svg> </label> <div class="last"> <button class="btn"> <span>Submit</span> <svg preserveAspectRatio="none" viewBox="0 0 132 45"> <g clip-path="url(#clip)" filter="url(#goo-big)"> <circle class="top-left" cx="49.5" cy="-0.5" r="26.5" /> <circle class="middle-bottom" cx="70.5" cy="40.5" r="26.5" /> <circle class="top-right" cx="104" cy="6.5" r="27" /> <circle class="right-bottom" cx="123.5" cy="36.5" r="26.5" /> <circle class="left-bottom" cx="16.5" cy="28" r="30" /> </g> <defs> <clipPath id="clip"> <rect width="132" height="45" rx="7" /> </clipPath> </defs> </svg> </button> </div> </div> <svg width="0" height="0"> <defs> <filter id="goo" x="-50%" width="200%" y="-50%" height="200%" color-interpolation-filters="sRGB"> <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" /> <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -7" result="cm" /> </filter> <filter id="goo-light" x="-50%" width="200%" y="-50%" height="200%" color-interpolation-filters="sRGB"> <feGaussianBlur in="SourceGraphic" stdDeviation="1.25" result="blur" /> <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -7" result="cm" /> </filter> <filter id="goo-big" x="-50%" width="200%" y="-50%" height="200%" color-interpolation-filters="sRGB"> <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur" /> <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 21 -7" result="cm" /> </filter> </defs> </svg> <script src="https://unpkg.co/gsap@3/dist/gsap.min.js"></script> :root { --c-active: #275EFE; --c-active-inner: #FFFFFF; --c-default: #D2D6E9; --c-default-dark: #C7CBDF; --c-black: #1B1B22; } .radio, .checkbox, .switch { display: table; border-radius: var(--border-radius, 12px) var(--border-radius-corner, 12px) var(--border-radius, 12px) var(--border-radius, 12px); position: relative; } .radio input, .checkbox input, .switch input { -webkit-appearance: none; -moz-appearance: none; appearance: none; outline: none; border: none; background: var(--input-background, none); display: block; cursor: pointer; margin: 0; padding: 0; border-radius: inherit; width: var(--input-width, 24px); height: var(--input-height, 24px); } .radio svg, .checkbox svg, .switch svg { display: block; position: absolute; left: 0; right: 0; bottom: 0; top: 0; pointer-events: none; fill: var(--c-active-inner); transform: scale(1.01) translateZ(0); } .radio input, .checkbox input { --border-color: var(--c-default); --border-width: 2px; box-shadow: inset 0 0 0 var(--border-width) var(--border-color); } .radio input:checked, .checkbox input:checked { --border-color: var(--c-active); } .radio input:not(:checked), .checkbox input:not(:checked) { transition: box-shadow 0.25s; } .radio input:not(:checked):hover, .checkbox input:not(:checked):hover { --border-width: 3px; --border-color: var(--c-active); } .radio input:checked { --border-width: 6.75px; } .radio input + svg { --top-y: 0; --dot-y: -17px; --drop-y: -14px; --top-s-x: 1.75; --top-s-y: 1; } .radio input + svg .top { transform-origin: 12px -12px; transform: translateY(var(--top-y)) scale(var(--top-s-x), var(--top-s-y)) translateZ(0); } .radio input + svg .dot { transform: translateY(var(--dot-y)) translateZ(0); } .radio input + svg .drop { transform: translateY(var(--drop-y)) translateZ(0); } .checkbox { --border-radius: 5px; --border-radius-corner: 5px; } .checkbox input:checked { --border-width: 12px; } .checkbox input:checked + svg { --tick-offset: 46.5px; } .checkbox input + svg { --dot-x: 14px; --dot-y: -14px; --dot-s: 1; --tick-offset: 20.5px; --tick-array: 16.5px; --tick-s: 1; --drop-s: 1; } .checkbox input + svg .tick { fill: none; stroke-width: 3px; stroke-linecap: round; stroke-linejoin: round; stroke: var(--c-active-inner); stroke-dasharray: var(--tick-array) 33px; stroke-dashoffset: var(--tick-offset); transform-origin: 10.5px 16px; transform: scale(var(--tick-s)) translateZ(0); } .checkbox input + svg .dot { transform-origin: 10.5px 15.5px; transform: translate(var(--dot-x), var(--dot-y)) scale(var(--dot-s)) translateZ(0); } .checkbox input + svg .drop { transform-origin: 25px -1px; transform: scale(var(--drop-s)) translateZ(0); } .switch { --input-width: 38px; } .switch input { --input-background: var(--c-default); } .switch input:checked { --input-background: var(--c-active); } .switch input:checked + svg { --default-s: 0; --default-x: 8px; --dot-s: 1; --dot-x: 0px; } .switch input + svg { --input-background: var(--c-default); --default-s: 1; --default-x: 0px; --dot-s: 0; --dot-x: -8px; } .switch .default { transform-origin: 12px 12px; transform: translateX(var(--default-x)) scale(var(--default-s)) translateZ(0); } .switch .dot { transform-origin: 26px 12px; transform: translateX(var(--dot-x)) scale(var(--dot-s)) translateZ(0); } .btn { -webkit-appearance: none; -moz-appearance: none; appearance: none; border: none; position: relative; background: var(--c-black); color: #fff; outline: none; cursor: pointer; font-size: 14px; line-height: 21px; font-weight: 600; display: block; width: 132px; text-align: center; border-radius: 7px; margin: 0 auto; padding: 12px 0; } .btn span { position: relative; z-index: 1; } .btn svg { display: block; width: 100%; height: 100%; position: absolute; left: 0; top: 0; fill: var(--c-active); } .btn svg circle { transition: transform var(--duration, 0.25s) ease-out; } .btn svg circle.top-left { transform: translate(var(--spacing, -16px), var(--spacing, -40px)); } .btn svg circle.middle-bottom { transform: translate(var(--spacing, 8px), var(--spacing, 40px)); } .btn svg circle.top-right { transform: translate(var(--spacing, 40px), var(--spacing, -40px)); } .btn svg circle.right-bottom { transform: translate(var(--spacing, 4px), var(--spacing, 40px)); } .btn svg circle.left-bottom { transform: translate(var(--spacing, -40px), var(--spacing, 40px)); } .btn:hover { --spacing: 0; --duration: .45s; } .grid { display: grid; grid-gap: 24px 32px; grid-template-columns: repeat(3, auto); grid-template-rows: repeat(3, auto); grid-auto-flow: column; } .grid .last { grid-column: 1/4; grid-row: 3; } html { box-sizing: border-box; -webkit-font-smoothing: antialiased; } * { box-sizing: inherit; } *:before, *:after { box-sizing: inherit; } body { min-height: 100vh; display: flex; font-family: "Poppins", Arial; justify-content: center; align-items: center; background: #fff; } body .dribbble { position: fixed; display: block; right: 20px; bottom: 20px; } body .dribbble img { display: block; height: 28px; } body .twitter { position: fixed; display: block; right: 64px; bottom: 14px; } body .twitter svg { width: 32px; height: 32px; fill: #1da1f2; } const { to, set, from, fromTo } = gsap const getVar = (key, elem = document.documentElement) => getComputedStyle(elem).getPropertyValue(key) document.querySelectorAll('.radio').forEach(elem => { let svg = elem.querySelector('svg'), input = elem.querySelector('input') input.addEventListener('change', e => { fromTo(input, { '--border-width': '3px' }, { '--border-color': getVar('--c-active'), '--border-width': '12px', duration: .2 }) to(svg, { keyframes: [{ '--top-y': '6px', '--top-s-x': 1, '--top-s-y': 1.25, duration: .2, delay: .2 }, { '--top-y': '0px', '--top-s-x': 1.75, '--top-s-y': 1, duration: .6 }] }) to(svg, { keyframes: [{ '--dot-y': '2px', duration: .3, delay: .2 }, { '--dot-y': '0px', duration: .3 }] }) to(svg, { '--drop-y': '0px', duration: .6, delay: .4, clearProps: true, onComplete() { input.removeAttribute('style') } }) }) }) document.querySelectorAll('.checkbox').forEach(elem => { let svg = elem.querySelector('svg'), input = elem.querySelector('input') input.addEventListener('change', e => { let checked = input.checked if(!checked) { return } fromTo(input, { '--border-width': '3px' }, { '--border-color': getVar('--c-active'), '--border-width': '12px', duration: .2, clearProps: true }) set(svg, { '--dot-x': '14px', '--dot-y': '-14px', '--tick-offset': '20.5px', '--tick-array': '16.5px', '--drop-s': 1 }) to(elem, { keyframes: [{ '--border-radius-corner': '14px', duration: .2, delay: .2 }, { '--border-radius-corner': '5px', duration: .3, clearProps: true }] }) to(svg, { '--dot-x': '0px', '--dot-y': '0px', '--dot-s': 1, duration: .4, delay: .4 }) to(svg, { keyframes: [{ '--tick-offset': '48px', '--tick-array': '14px', duration: .3, delay: .2 }, { '--tick-offset': '46.5px', '--tick-array': '16.5px', duration: .35, clearProps: true }] }) }) }) document.querySelectorAll('.switch').forEach(elem => { let svg = elem.querySelector('svg'), input = elem.querySelector('input') input.addEventListener('pointerenter', e => { if(elem.animated || input.checked) { return } to(input, { '--input-background': getVar('--c-default-dark'), duration: .2 }) }) input.addEventListener('pointerleave', e => { if(elem.animated || input.checked) { return } to(input, { '--input-background': getVar('--c-default'), duration: .2 }) }) input.addEventListener('change', e => { let checked = input.checked let hide = checked ? 'default' : 'dot', show = checked ? 'dot' : 'default' fromTo(svg, { '--default-s': checked ? 1 : 0, '--default-x': checked ? '0px' : '8px', '--dot-s': checked ? 0 : 1, '--dot-x': checked ? '-8px' : '0px' }, { ['--' + hide + '-s']: 0, ['--' + hide + '-x']: checked ? '8px' : '-8px', duration: .25, delay: .15 }) fromTo(input, { '--input-background': getVar(checked ? '--c-default' : '--c-active'), }, { '--input-background': getVar(checked ? '--c-active' : '--c-default'), duration: .35, clearProps: true }) to(svg, { keyframes: [{ ['--' + show + '-x']: checked ? '2px' : '-2px', ['--' + show + '-s']: 1, duration: .25 }, { ['--' + show + '-x']: '0px', duration: .2, clearProps: true }] }) }) }) Навигация по записям PS4 Interface Typographic Clock