Anahtar bileşeni oluşturma

Duyarlı ve erişilebilir bir geçiş bileşeni oluşturmaya ilişkin temel bir genel bakış.

Bu yayında, anahtar bileşenlerini oluşturmanın bir yolu üzerine düşünmek istiyorum. Demoyu deneyin.

Tanıtım

Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:

Genel bakış

anahtar, onay kutusuna benzer şekilde çalışır ancak boole açık ve kapalı durumlarını açık bir şekilde temsil eder.

Bu demo, işlevlerinin çoğunda <input type="checkbox" role="switch"> kullanılmaktadır. Bu da, CSS veya JavaScript'in tam olarak işlevsel ve erişilebilir olması gerekmemesi gibi bir avantaja sahiptir. CSS'nin yüklenmesi sağdan sola diller, dikeylik, animasyon ve daha fazlasını destekler. JavaScript'in yüklenmesi anahtarı sürüklenebilir ve somut hale getirir.

Özel özellikler

Aşağıdaki değişkenler, anahtarın çeşitli parçalarını ve bunların seçeneklerini temsil eder. Üst düzey sınıf olan .gui-switch, bileşen alt öğeleri genelinde kullanılan özel özellikleri ve merkezi özelleştirme için giriş noktalarını içerir.

Parça

Uzunluk (--track-size), dolgu ve iki renk:

.gui-switch {
  --track-size: calc(var(--thumb-size) * 2);
  --track-padding: 2px;

  --track-inactive: hsl(80 0% 80%);
  --track-active: hsl(80 60% 45%);

  --track-color-inactive: var(--track-inactive);
  --track-color-active: var(--track-active);

  @media (prefers-color-scheme: dark) {
    --track-inactive: hsl(80 0% 35%);
    --track-active: hsl(80 60% 60%);
  }
}

Küçük resim

Boyut, arka plan rengi ve etkileşim vurgu renkleri:

.gui-switch {
  --thumb-size: 2rem;
  --thumb: hsl(0 0% 100%);
  --thumb-highlight: hsl(0 0% 0% / 25%);

  --thumb-color: var(--thumb);
  --thumb-color-highlight: var(--thumb-highlight);

  @media (prefers-color-scheme: dark) {
    --thumb: hsl(0 0% 5%);
    --thumb-highlight: hsl(0 0% 100% / 25%);
  }
}

Azaltılmış hareket

Net bir takma ad eklemek ve tekrarı azaltmak için azaltılmış hareket tercihi kullanıcı medya sorgusu, şu Medya Sorguları'ndaki taslak spesifikasyona dayanarak PostCSS eklentisi ile özel bir mülke yerleştirilebilir:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

Markup

<input type="checkbox" role="switch"> öğemi bir <label> ile sarmalamayı seçtim, onay kutusu ve etiket ilişkilendirmesinin belirsizliğini önlemek için ilişkilerini paket hâline getirdim. Ayrıca kullanıcıya, girişi açıp kapatmak için etiketle etkileşim kurma olanağı verdim.

Doğal, stili olmayan bir etiket ve onay kutusu.

<label for="switch" class="gui-switch">
  Label text
  <input type="checkbox" role="switch" id="switch">
</label>

<input type="checkbox">, önceden oluşturulmuş bir API ve state ile birlikte gelir. Tarayıcı, checked özelliğini ve oninput ile onchanged gibi giriş etkinliklerini yönetir.

Düzenler

Flexbox, grid ve özel özellikler, bu bileşenin stillerini korumak açısından kritik öneme sahiptir. Değerleri merkezileştirir, belirsiz hesaplamalara veya alanlara adlar verir ve kolay bileşen özelleştirmeleri için küçük bir özel özellik API'si sağlar.

.gui-switch

Anahtarın üst düzey düzeni flexbox'tır. .gui-switch sınıfı, çocukların düzenlerini hesaplamak için kullandığı gizli ve herkese açık özel özellikleri içerir.

Flexbox Geliştirici Araçları, yer paylaşımlı yatay bir etiket ve anahtarın üzerine yerleştirilerek alanın düzen dağılımını gösteriyor.

.gui-switch {
  display: flex;
  align-items: center;
  gap: 2ch;
  justify-content: space-between;
}

flexbox düzenini genişletmek ve değiştirmek, herhangi bir flexbox düzenini değiştirmek gibidir. Örneğin, etiketleri bir anahtarın üstüne veya altına yerleştirmek ya da flex-direction öğesini değiştirmek için:

Flexbox Geliştirici Araçları&#39;nın üzerine dikey etiket ve anahtar yerleştiriliyor.

<label for="light-switch" class="gui-switch" style="flex-direction: column">
  Default
  <input type="checkbox" role="switch" id="light-switch">
</label>

Parça

Onay kutusu girişi, normal appearance: checkbox öğesi kaldırılıp bunun yerine kendi boyutu sağlanarak geçiş kanalı olarak biçimlendirilir:

Geçiş kanalını yer paylaşımlı olarak gösteren ve adlandırılmış kılavuz izleme alanlarını &quot;track&quot; adıyla gösteren Izgara Geliştirici Araçları.

.gui-switch > input {
  appearance: none;

  inline-size: var(--track-size);
  block-size: var(--thumb-size);
  padding: var(--track-padding);

  flex-shrink: 0;
  display: grid;
  align-items: center;
  grid: [track] 1fr / [track] 1fr;
}

Parça, başparmak tarafından talep edilmesi için tek tek hücre ızgara izleme alanı da oluşturur.

Küçük resim

appearance: none stili, tarayıcının sağladığı görsel onay işaretini de kaldırır. Bu bileşen, bu görsel göstergeyi değiştirmek için girişte bir sözde öğe ve :checked sözde sınıf kullanır.

Baş parmak, input[type="checkbox"] öğesine eklenmiş yapay bir öğedir ve kılavuz alanını track belirterek kanalın altında değil üstüne üst kısımda yer alır:

Gerçek olmayan öğenin küçük resmini CSS ızgarasının içine yerleştirilmiş şekilde gösteren Geliştirici Araçları.

.gui-switch > input::before {
  content: "";
  grid-area: track;
  inline-size: var(--thumb-size);
  block-size: var(--thumb-size);
}

Stiller

Özel özellikler, renk şemalarına, sağdan sola dillere ve hareket tercihlerine uyum sağlayan çok yönlü bir anahtar bileşeni sağlar.

Anahtar ve durumlarının açık ve koyu temanın yan yana karşılaştırması.

Dokunma etkileşim stilleri

Mobil cihazlarda tarayıcılar, etiketlere ve girişlere dokunarak vurgulama vurgulamaları ve metin seçimi özellikleri ekler. Bu sorunlar, geçiş için gereken stil ve görsel etkileşim geri bildirimini olumsuz etkiledi. Birkaç satır CSS ile bu efektleri kaldırıp kendi cursor: pointer stilimi ekleyebilirim:

.gui-switch {
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

Değerli görsel etkileşim geri bildirimleri olabileceğinden bu stilleri kaldırmanız her zaman tavsiye edilmez. Bunları kaldırırsanız özel alternatifler sağlamayı unutmayın.

Parça

Bu öğenin stilleri çoğunlukla şekli ve rengiyle ilgilidir. Öğeye, basamakla aracılığıyla üst .gui-switch öğesinden erişir.

Özel kanal boyutları ve renklerine sahip varyantlar.

.gui-switch > input {
  appearance: none;
  border: none;
  outline-offset: 5px;
  box-sizing: content-box;

  padding: var(--track-padding);
  background: var(--track-color-inactive);
  inline-size: var(--track-size);
  block-size: var(--thumb-size);
  border-radius: var(--track-size);
}

Geçiş kanalı için çok çeşitli özelleştirme seçenekleri dört özel özellikten gelir. appearance: none tüm tarayıcılarda onay kutusundaki kenarlıkları kaldırmadığı için border: none eklendi.

Küçük resim

Baş parmak öğesi zaten sağ track konumunda ancak daire stillerine ihtiyaç duyuyor:

.gui-switch > input::before {
  background: var(--thumb-color);
  border-radius: 50%;
}

Daire baş parmak sözde öğe vurgulanmış olarak gösterilen Geliştirici Araçları.

Etkileşim

Fareyle üzerine gelerek vurgulamaları ve başparmak konumu değişikliklerini gösterecek etkileşimlere hazırlanmak için özel özellikleri kullanın. Hareket veya fareyle üzerine gelme vurgulama stilleri değiştirilmeden önce kullanıcının tercihi de kontrol edilir.

.gui-switch > input::before {
  box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight);

  @media (--motionOK) { & {
    transition:
      transform var(--thumb-transition-duration) ease,
      box-shadow .25s ease;
  }}
}

Başparmak konumu

Özel özellikler, başparmağın kanalda konumlandırılması için tek bir kaynak mekanizması sağlar. Elimizde, başparmakların belirli uzaklıkta kopyasının ve kanalın içinde doğru şekilde ilerlemesini sağlamak için hesaplamalarda kullanacağımız parça ve başparmak boyutları bulunmaktadır: 0% ve 100%.

input öğesi --thumb-position konum değişkeninin sahibidir ve baş parmak sözde öğesi, bunu bir translateX konumu olarak kullanır:

.gui-switch > input {
  --thumb-position: 0%;
}

.gui-switch > input::before {
  transform: translateX(var(--thumb-position));
}

Artık --thumb-position öğesini CSS'den ve onay kutusu öğelerinde sağlanan sözde sınıflardan değiştirebiliriz. Bu öğede önceden transition: transform var(--thumb-transition-duration) ease öğesini koşullu olarak ayarladığımızdan şu değişiklikler değiştirildiğinde animasyon gösterilebilir:

/* positioned at the end of the track: track length - 100% (thumb width) */
.gui-switch > input:checked {
  --thumb-position: calc(var(--track-size) - 100%);
}

/* positioned in the center of the track: half the track - half the thumb */
.gui-switch > input:indeterminate {
  --thumb-position: calc(
    (var(--track-size) / 2) - (var(--thumb-size) / 2)
  );
}

Bence bu ayrıştırılmış düzenleme iyi sonuç verdi. Baş parmak öğesi yalnızca tek bir stille, bir translateX konumuyla ilgilidir. Giriş, tüm karmaşıklık ve hesaplamaları yönetebilir.

Dikey

Destek, input öğesine CSS dönüşümleriyle rotasyon ekleyen -vertical adlı bir değiştirici sınıfıyla gerçekleştirildi.

3D döndürülmüş bir öğe, bileşenin toplam yüksekliğini değiştirmez. Bu durum, blok düzenine yol açabilir. --track-size ve --track-padding değişkenlerini kullanarak bunu hesaba katın. Dikey bir düğmenin düzende beklendiği gibi akması için gereken minimum alan miktarını hesaplayın:

.gui-switch.-vertical {
  min-block-size: calc(var(--track-size) + calc(var(--track-padding) * 2));

  & > input {
    transform: rotate(-90deg);
  }
}

(RTL) sağdan sola

Bir CSS arkadaşım olan Elad Schecter ile birlikte, tek bir değişkeni çevirerek sağdan sola yazılan dilleri işleyen CSS dönüştürmelerini kullanan, dışa doğru kaydırılan yan menünün prototipini oluşturduk. CSS'de mantıksal özellik dönüşümü olmadığı ve hiçbir zaman olmayacağı için bunu yaptık. Elad, yüzdeleri ters çevirmek, böylece mantıksal dönüşümler için kendi özel mantığımızın tek bir konum olarak yönetilmesini sağlamak üzere özel bir özellik değeri kullanmayı düşünmüştü. Bu geçişte de aynı tekniği kullandım ve bence çok işe yaradı:

.gui-switch {
  --isLTR: 1;

  &:dir(rtl) {
    --isLTR: -1;
  }
}

--isLTR adlı özel bir özellik başlangıçta 1 değerini alır. Diğer bir deyişle, düzenimiz varsayılan olarak soldan sağa olduğundan true değerine sahiptir. Daha sonra :dir() CSS sözde sınıfı kullanılarak, bileşen sağdan sola bir düzen içinde olduğunda değer -1 olarak ayarlanır.

Bir dönüşümün içindeki calc() içinde kullanarak --isLTR işlemini gerçekleştirin:

.gui-switch.-vertical > input {
  transform: rotate(-90deg);
  transform: rotate(calc(90deg * var(--isLTR) * -1));
}

Şimdi dikey anahtarın döndürülmesi, sağdan sola düzen için gereken zıt kenar konumunu hesaba katar.

Baş parmak sözde öğedeki translateX dönüşümlerinin de karşı taraf gereksinimini hesaba katacak şekilde güncellenmesi gerekir:

.gui-switch > input:checked {
  --thumb-position: calc(var(--track-size) - 100%);
  --thumb-position: calc((var(--track-size) - 100%) * var(--isLTR));
}

.gui-switch > input:indeterminate {
  --thumb-position: calc(
    (var(--track-size) / 2) - (var(--thumb-size) / 2)
  );
  --thumb-position: calc(
   ((var(--track-size) / 2) - (var(--thumb-size) / 2))
    * var(--isLTR)
  );
}

Bu yaklaşım, mantıksal CSS dönüşümleri gibi bir kavramla ilgili tüm ihtiyaçları çözmek için işe yaramasa da birçok kullanım alanı için bazı DRY ilkeleri sunar.

Eyaletler

Yerleşik input[type="checkbox"], içinde bulunabileceği çeşitli durumlar işlenmeden tamamlanmış olmaz: :checked, :disabled, :indeterminate ve :hover. :focus bilinçli bir şekilde yalnız bırakıldı, yalnızca belirli uzaklıktaki bir düzenleme yapıldı. Odak halkası Firefox ve Safari'de harika görünüyordu:

Firefox ve Safari&#39;de bir anahtara odaklanmış odak halkasının ekran görüntüsü.

Kontrol edildi

<label for="switch-checked" class="gui-switch">
  Default
  <input type="checkbox" role="switch" id="switch-checked" checked="true">
</label>

Bu eyalet, on durumunu temsil eder. Bu durumda, giriş "iz" arka planı etkin renge ve baş parmak konumu "son"a ayarlanır.

.gui-switch > input:checked {
  background: var(--track-color-active);
  --thumb-position: calc((var(--track-size) - 100%) * var(--isLTR));
}

Devre dışı

<label for="switch-disabled" class="gui-switch">
  Default
  <input type="checkbox" role="switch" id="switch-disabled" disabled="true">
</label>

:disabled düğmesi yalnızca görsel olarak farklı görünmekle kalmaz, aynı zamanda öğeyi sabit hale getirmelidir.Etkileşim değişmezliği tarayıcıdan bağımsızdır, ancak appearance: none kullanımı nedeniyle görsel durumların stillere ihtiyacı vardır.

.gui-switch > input: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%);
    }}
  }
}

Devre dışı, işaretli ve işaretlenmemiş durumlarda koyu renkli anahtar.

Bu durum, hem devre dışı hem de işaretlenmiş durumda koyu ve açık temalara ihtiyaç duyduğu için yanıltıcıdır. Stil kombinasyonlarının sağladığı bakım yükünü azaltmak amacıyla, bu durumlar için stil açısından minimum stiller seçtim.

Belirsiz

Genellikle unutulan bir durum olan :indeterminate, bir onay kutusunun işaretli olmadığı veya işaretsiz olduğu bir durumdur. Bu eğlenceli bir durumdur, davetkar ve mütevazıdır. Boole durumlarının durumlar arasında gizli olabileceğine dair iyi bir hatırlatma.

Belirsiz için onay kutusu ayarlamak karmaşıktır, bunu yalnızca JavaScript ayarlayabilir:

<label for="switch-indeterminate" class="gui-switch">
  Indeterminate
  <input type="checkbox" role="switch" id="switch-indeterminate">
  <script>document.getElementById('switch-indeterminate').indeterminate = true</script>
</label>

Belirsiz durum. Karar verilmemiş olduğunu belirtmek için izleme başparmağının ortasında yer alır.

Eyalet mütevazı ve davetkar olduğu için geçişin baş parmağını ortaya koymayı uygun hissettim:

.gui-switch > input:indeterminate {
  --thumb-position: calc(
    calc(calc(var(--track-size) / 2) - calc(var(--thumb-size) / 2))
    * var(--isLTR)
  );
}

Üzerine gelme

Fareyle üzerine gelme etkileşimleri, bağlı kullanıcı arayüzü için görsel destek sağlamalı ve etkileşimli kullanıcı arayüzüne yön vermelidir. Bu anahtar, etiketin veya girişin üzerine geldiğinizde başparmağı yarı şeffaf bir halkayla vurgular. Ardından bu fareyle üzerine gelme animasyonu, etkileşimli başparmak öğesine yön sağlar.

"Vurgula" efekti box-shadow ile tamamlandı. Fareyle devre dışı bırakılmış bir girişin üzerine geldiğinizde --highlight-size boyutunu artırın. Kullanıcı hareket konusunda bir sıkıntı yaşıyorsa box-shadow öğesinin geçişini yapıp büyüttüğünü görüyoruz. Hareketten memnun değilse vurgu anında görünür:

.gui-switch > input::before {
  box-shadow: 0 0 0 var(--highlight-size) var(--thumb-color-highlight);

  @media (--motionOK) { & {
    transition:
      transform var(--thumb-transition-duration) ease,
      box-shadow .25s ease;
  }}
}

.gui-switch > input:not(:disabled):hover::before {
  --highlight-size: .5rem;
}

JavaScript

Bir anahtar arayüzü, fiziksel bir arayüzü, özellikle de parça içindeki bir daireyi taklit etme girişimi nedeniyle bana sıra dışı gelebilir. iOS, anahtarlarıyla bunu doğru yaptı. Bunları bir yandan diğer yana sürükleyebilirsiniz. Bu seçeneğin olması çok tatmin edici. Öte yandan, bir sürükleme hareketi denendiğinde hiçbir şey olmazsa kullanıcı arayüzü öğesi etkin değilmiş gibi hissedebilir.

Sürüklenebilir küçük resimler

Sözde baş parmak öğesi, konumunu .gui-switch > input kapsamlı var(--thumb-position) öğesinden alır. JavaScript, baş parmak konumunu dinamik bir şekilde güncellemek ve işaretçi hareketini izliyormuş gibi göstermek için girişe bir satır içi stil değeri sağlayabilir. İşaretçi serbest bırakıldığında satır içi stilleri kaldırın ve --thumb-position özel özelliğini kullanarak sürüklemenin kapalı mı yoksa açık mı olduğunu belirleyin. Bu, çözümün bel kemiğidir. İşaretçi etkinlikleri, CSS özel özelliklerini değiştirmek için işaretçi konumlarını koşullu olarak izler.

Bu komut dosyası gösterilmeden önce bileşen zaten% 100 işlevsel durumda olduğundan, girişi açıp kapatmak için bir etiketi tıklamak gibi mevcut davranışı sürdürmek için epey çalışma gerekiyor. JavaScript'imiz, mevcut özellikleri yitirip yeni özellikler eklememelidir.

touch-action

Sürükleme, özel bir hareket olduğundan touch-action avantajları için mükemmel bir adaydır. Bu geçiş durumunda, yatay bir hareket komut dosyamız tarafından veya dikey anahtar varyantı için yakalanan dikey bir hareket olmalıdır. touch-action ile tarayıcıya bu öğe üzerinde hangi hareketleri kullanacağını söyleyebiliriz. Böylece, komut dosyası bir hareketi rekabet olmadan işleyebilir.

Aşağıdaki CSS, tarayıcıya bir işaretçi hareketi bu geçiş yolunun içinden başladığında, dikey hareketleri ele alacağını ve yatay hareketlerle hiçbir şey yapmayacağını bildirir:

.gui-switch > input {
  touch-action: pan-y;
}

İstenen sonuç, sayfayı kaydırmayan veya kaydırmayan yatay bir harekettir. İşaretçiler girişin içinden dikey olarak başlayabilir ve sayfayı kaydırabilir. Ancak yatay olanlar özel olarak işlenir.

Piksel değeri stili yardımcı programları

Kurulum sırasında ve sürükleme sırasında öğelerden çeşitli hesaplanan sayı değerlerinin yakalanması gerekir. Aşağıdaki JavaScript işlevleri, bir CSS özelliği verildiğinde hesaplanan piksel değerlerini döndürür. Kurulum komut dosyasında şu şekilde kullanılır: getStyle(checkbox, 'padding-left').

​​const getStyle = (element, prop) => {
  return parseInt(window.getComputedStyle(element).getPropertyValue(prop));
}

const getPseudoStyle = (element, prop) => {
  return parseInt(window.getComputedStyle(element, ':before').getPropertyValue(prop));
}

export {
  getStyle,
  getPseudoStyle,
}

window.getComputedStyle() öğesinin ikinci bir bağımsız değişkeni, bir hedef sözde öğeyi nasıl kabul ettiğine dikkat edin. JavaScript'in, sözde öğelerden bile bu kadar çok öğe okuyabilmesi oldukça düzenlidir.

dragging

Bu, sürükleme mantığı için önemli bir andır ve işlev etkinlik işleyicisinde belirtilmesi gereken birkaç nokta vardır:

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`)
}

Komut dosyası kahramanı state.activethumb, bu komut dosyasının bir işaretçiyle birlikte konumlandırdığı küçük daire. switches nesnesi, anahtarların .gui-switch olduğu bir Map() öğesidir ve değerlerin, komut dosyasını verimli hale getiren önbelleğe alınmış sınırlar ve boyutlardır. Sağdan sola yönü, CSS ile aynı özel özellik (--isLTR) kullanılarak işlenir ve bu özelliği, mantığı tersine çevirerek RTL'yi desteklemeye devam etmek için kullanabilir. event.offsetX, başparmağı konumlandırmak için yararlı bir delta değeri içerdiğinden de değerlidir.

state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)

CSS'nin bu son satırı, küçük öğe tarafından kullanılan özel özelliği ayarlar. Aksi takdirde, bu değer ataması zaman içinde geçiş yapar ancak önceki bir işaretçi etkinliğinde --thumb-transition-duration yavaşça geçebilecek etkileşimi geçici olarak 0s olarak ayarlar.

dragEnd

Kullanıcının anahtarın uzağa sürükleyip bırakmasına izin verilmesi için global bir pencere etkinliğinin kaydedilmesi gerekir:

window.addEventListener('pointerup', event => {
  if (!state.activethumb) return

  dragEnd(event)
})

Kullanıcının rahatça sürükleme özgürlüğüne sahip olması ve arayüzün bunu karşılayacak kadar akıllı olması bence çok önemli. Bu geçişle bunu halletmek fazla uzun sürmedi, ancak geliştirme sürecinde dikkatle düşünülmesi gerekiyordu.

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()
}

Öğeyle etkileşim tamamlandı. Giriş kontrol edilen özelliğinin ayarlanması ve tüm hareket etkinliklerini kaldırma zamanı. Onay kutusu state.activethumb.checked = determineChecked() ile değiştirildi.

determineChecked()

dragEnd tarafından çağrılan bu işlev, baş parmak akımının parkurunun sınırları içinde nerede olduğunu belirler ve yolun yarısına eşitse veya yolun yarısına eşitse true değerini döndürür:

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
}

Ekstra düşünceler

Sürükleme hareketi, seçilen ilk HTML yapısı nedeniyle bir miktar kod borcuna neden olur ve en önemlisi, girişin bir etiket içine sarmalanmasıdır. Üst öğe olan etiket, girişten sonra tıklama etkileşimlerini alır. dragEnd etkinliğinin sonunda padRelease() işlevinin garip bir ses işlevi olduğunu fark etmiş olabilirsiniz.

const padRelease = () => {
  state.recentlyDragged = true

  setTimeout(_ => {
    state.recentlyDragged = false
  }, 300)
}

Bunun nedeni, kullanıcının gerçekleştirdiği etkileşimin işaretini kaldıracağı veya bu etkileşimi kontrol edeceği için daha sonra bu tıklamayı alan etiketin hesaba katılmasıdır.

Bunu tekrar yaparsam kullanıcı deneyimi yeni sürüme geçiş sırasında JavaScript ile DOM'yi ayarlamayı düşünebilirim. Örneğin, etiket tıklamalarını kendi kendine işleyen ve yerleşik davranışla mücadele etmeyen bir öğe oluşturabilirim.

Bu tür JavaScript kullanmayı çok sevmedim. Koşullu etkinlik balonlarını yönetmek istemiyorum:

const preventBubbles = event => {
  if (state.recentlyDragged)
    event.preventDefault() && event.stopPropagation()
}

Sonuç

Bu ufak tefek geçiş bileşeni, şimdiye kadarki tüm GUI Meydan Okumaları arasında en fazla sonucu alan bileşen oldu. Nasıl yaptığımı artık bildiğine göre siz de nasıl yapardınız? 🙂

Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim. Bir demo oluşturun, bana tweet atın bağlantıları, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.

Topluluk remiksleri

Kaynaklar

.gui-switch kaynak kodunu GitHub'da bulun.