Koleksiyonlar ile düzeninizi koruyun
İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.
HTML
<label for="switch-1" class="gui-switch">
Default
<input type="checkbox" role="switch" id="switch-1">
</label>
<label for="switch-2" class="gui-switch">
Indeterminate
<input type="checkbox" role="switch" id="switch-2">
<!-- TODO: Devsite - Removed inline handlers -->
<!-- <script>document.getElementById('switch-2').indeterminate = true</script> -->
</label>
<label for="switch-3" class="gui-switch">
Disabled
<input type="checkbox" role="switch" id="switch-3" disabled>
</label>
<label for="switch-4" class="gui-switch">
Disabled (checked)
<input type="checkbox" role="switch" id="switch-4" disabled checked>
</label>
<label for="switch-vertical" class="gui-switch -vertical">
Vertical
<input type="checkbox" role="switch" id="switch-vertical">
</label>
CSS
.gui-switch {
--thumb-size: 2rem;
--thumb: hsl(0 0% 100%);
--thumb-highlight: hsl(0 0% 0% / 25%);
--track-size: calc(var(--thumb-size) * 2);
--track-padding: 2px;
--track-inactive: hsl(80 0% 80%);
--track-active: hsl(80 60% 45%);
--thumb-color: var(--thumb);
--thumb-color-highlight: var(--thumb-highlight);
--track-color-inactive: var(--track-inactive);
--track-color-active: var(--track-active);
--isLTR: 1;
display: flex;
align-items: center;
gap: 2ch;
justify-content: space-between;
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
@media (prefers-color-scheme: dark) {
--thumb: hsl(0 0% 5%);
--thumb-highlight: hsl(0 0% 100% / 25%);
--track-inactive: hsl(80 0% 35%);
--track-active: hsl(80 60% 60%);
}
&:dir(rtl) {
--isLTR: -1;
}
&.-vertical {
min-block-size: calc(var(--track-size) + calc(var(--track-padding) * 2));
& > input {
transform: rotate(calc(90deg * var(--isLTR) * -1));
touch-action: pan-x;
}
}
& > input {
--thumb-position: 0%;
--thumb-transition-duration: .25s;
padding: var(--track-padding);
background: var(--track-color-inactive);
inline-size: var(--track-size);
block-size: var(--thumb-size);
border-radius: var(--track-size);
appearance: none;
pointer-events: none;
touch-action: pan-y;
border: none;
outline-offset: 5px;
box-sizing: content-box;
flex-shrink: 0;
display: grid;
align-items: center;
grid: [track] 1fr / [track] 1fr;
transition: background-color .25s ease;
&::before {
--highlight-size: 0;
content: "";
cursor: pointer;
pointer-events: auto;
grid-area: track;
inline-size: var(--thumb-size);
block-size: var(--thumb-size);
background: var(--thumb-color);
box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight);
border-radius: 50%;
transform: translateX(var(--thumb-position));
@media (--motionOK) { & {
transition:
transform var(--thumb-transition-duration) ease,
box-shadow .25s ease;
}}
}
&:not(:disabled):hover::before {
--highlight-size: .5rem;
}
&:checked {
background: var(--track-color-active);
--thumb-position: calc((var(--track-size) - 100%) * var(--isLTR));
}
&:indeterminate {
--thumb-position: calc(
calc(calc(var(--track-size) / 2) - calc(var(--thumb-size) / 2))
* var(--isLTR)
);
}
&:disabled {
cursor: not-allowed;
--thumb-color: transparent;
&::before {
cursor: not-allowed;
box-shadow: inset 0 0 0 2px hsl(0 0% 100% / 50%);
@media (prefers-color-scheme: dark) {
box-shadow: inset 0 0 0 2px hsl(0 0% 0% / 50%);
}
}
}
}
}
JS
const elements = document.querySelectorAll('.gui-switch')
const switches = new WeakMap()
const state = {
activethumb: null,
recentlyDragged: false,
}
const getStyle = (element, prop) =>
parseInt(
window.getComputedStyle(element)
.getPropertyValue(prop))
const getPseudoStyle = (element, prop) =>
parseInt(
window.getComputedStyle(element, ':before')
.getPropertyValue(prop))
const dragInit = event => {
if (event.target.disabled) return
state.activethumb = event.target
state.activethumb.addEventListener('pointermove', dragging)
state.activethumb.style.setProperty('--thumb-transition-duration', '0s')
}
const dragging = event => {
if (!state.activethumb) return
let {thumbsize, bounds, padding} = switches.get(state.activethumb.parentElement)
let directionality = getStyle(state.activethumb, '--isLTR')
let track = (directionality === -1)
? (state.activethumb.clientWidth * -1) + thumbsize + padding
: 0
let pos = Math.round(event.offsetX - thumbsize / 2)
if (pos < bounds.lower) pos = 0
if (pos > bounds.upper) pos = bounds.upper
state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)
}
const dragEnd = event => {
if (!state.activethumb) return
state.activethumb.checked = determineChecked()
if (state.activethumb.indeterminate)
state.activethumb.indeterminate = false
state.activethumb.style.removeProperty('--thumb-transition-duration')
state.activethumb.style.removeProperty('--thumb-position')
state.activethumb.removeEventListener('pointermove', dragging)
state.activethumb = null
padRelease()
}
const padRelease = () => {
state.recentlyDragged = true
setTimeout(_ => {
state.recentlyDragged = false
}, 300)
}
const preventBubbles = event => {
if (state.recentlyDragged)
event.preventDefault() && event.stopPropagation()
}
const labelClick = event => {
if (
state.recentlyDragged ||
!event.target.classList.contains('gui-switch') ||
event.target.querySelector('input').disabled
) return
let checkbox = event.target.querySelector('input')
checkbox.checked = !checkbox.checked
event.preventDefault()
}
const determineChecked = () => {
let {bounds} = switches.get(state.activethumb.parentElement)
let curpos =
Math.abs(
parseInt(
state.activethumb.style.getPropertyValue('--thumb-position')))
if (!curpos) {
curpos = state.activethumb.checked
? bounds.lower
: bounds.upper
}
return curpos >= bounds.middle
}
elements.forEach(guiswitch => {
let checkbox = guiswitch.querySelector('input')
let thumbsize = getPseudoStyle(checkbox, 'width')
let padding = getStyle(checkbox, 'padding-left') + getStyle(checkbox, 'padding-right')
checkbox.addEventListener('pointerdown', dragInit)
checkbox.addEventListener('pointerup', dragEnd)
checkbox.addEventListener('click', preventBubbles)
guiswitch.addEventListener('click', labelClick)
switches.set(guiswitch, {
thumbsize,
padding,
bounds: {
lower: 0,
middle: (checkbox.clientWidth - padding) / 4,
upper: checkbox.clientWidth - thumbsize - padding,
},
})
})
window.addEventListener('pointerup', event => {
if (!state.activethumb) return
dragEnd(event)
})
Aksi belirtilmediği sürece bu sayfanın içeriği Creative Commons Atıf 4.0 Lisansı altında ve kod örnekleri Apache 2.0 Lisansı altında lisanslanmıştır. Ayrıntılı bilgi için Google Developers Site Politikaları'na göz atın. Java, Oracle ve/veya satış ortaklarının tescilli ticari markasıdır.
Son güncelleme tarihi: 2023-10-25 UTC.
[[["Anlaması kolay","easyToUnderstand","thumb-up"],["Sorunumu çözdü","solvedMyProblem","thumb-up"],["Diğer","otherUp","thumb-up"]],[["İhtiyacım olan bilgiler yok","missingTheInformationINeed","thumb-down"],["Çok karmaşık / çok fazla adım var","tooComplicatedTooManySteps","thumb-down"],["Güncel değil","outOfDate","thumb-down"],["Çeviri sorunu","translationIssue","thumb-down"],["Örnek veya kod sorunu","samplesCodeIssue","thumb-down"],["Diğer","otherDown","thumb-down"]],["Son güncelleme tarihi: 2023-10-25 UTC."],[],[]]