تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
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)
})
إنّ محتوى هذه الصفحة مرخّص بموجب ترخيص Creative Commons Attribution 4.0 ما لم يُنصّ على خلاف ذلك، ونماذج الرموز مرخّصة بموجب ترخيص Apache 2.0. للاطّلاع على التفاصيل، يُرجى مراجعة سياسات موقع Google Developers. إنّ Java هي علامة تجارية مسجَّلة لشركة Oracle و/أو شركائها التابعين.
تاريخ التعديل الأخير: 2023-10-25 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2023-10-25 (حسب التوقيت العالمي المتفَّق عليه)"],[],[]]