Duyarlı ve erişilebilir bir anahtar bileşeni oluşturma hakkında temel bilgiler.
Bu yayında, anahtar bileşenleri oluşturma yöntemiyle ilgili düşüncelerimi paylaşmak istiyorum. Demoyu deneyin.
Video tercih ediyorsanız bu yayının YouTube versiyonunu aşağıda bulabilirsiniz:
Genel Bakış
Anahtar, onay kutusuna benzer şekilde çalışır ancak açık ve kapalı durumları açıkça gösterir.
Bu demoda işlevlerin çoğu için <input type="checkbox" role="switch">
kullanılır. Bu, tam işlevsel ve erişilebilir olması için CSS veya JavaScript'in gerekmemesi avantajını sağlar. CSS yükleme, sağdan sola diller, dikey yön, animasyon ve daha fazlası için destek sunar. JavaScript'in yüklenmesi, anahtarı sürüklenebilir ve somut hale getirir.
Özel özellikler
Aşağıdaki değişkenler, anahtarın çeşitli bölümlerini ve seçeneklerini gösterir. Üst düzey sınıf olarak .gui-switch
, bileşen alt öğelerinde 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%);
}
}
İndirgenmiş hareket
Net bir takma ad eklemek ve tekrarı azaltmak için, Media Queries 5'teki bu taslak spesifikasyonuna dayalı olarak PostCSS eklentisi ile özel bir özelliğe azaltılmış hareket tercihi kullanıcı medya sorgusu yerleştirilebilir:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Brüt kar
<input type="checkbox" role="switch">
öğemi <label>
ile sarmayı tercih ettim. Böylece, onay kutusu ve etiket ilişkilendirme belirsizliğini önlemek için bu öğelerin ilişkisini bir araya getirdim. Ayrıca, kullanıcının girişi açıp kapatmak için etiketle etkileşime geçmesine olanak tanıdım.
<label for="switch" class="gui-switch">
Label text
<input type="checkbox" role="switch" id="switch">
</label>
<input type="checkbox">
, API ve durum ile birlikte önceden oluşturulmuş olarak gelir. Tarayıcı, checked
özelliğini ve oninput
ile onchanged
gibi giriş etkinliklerini yönetir.
Düzenler
Flexbox, grid ve custom properties, bu bileşenin stillerini korumak için çok önemlidir. Değerleri merkezileştirir, aksi takdirde belirsiz olacak hesaplamalara veya alanlara ad verir ve kolay bileşen özelleştirmeleri için küçük bir özel mülk API'si sağlar.
.gui-switch
Anahtarın üst düzey düzeni flexbox'tır. Sınıf .gui-switch
, çocukların düzenlerini hesaplamak için kullandığı özel ve genel özel özellikleri içerir.
.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
simgesini değiştirmek için:
<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
değeri kaldırılarak ve bunun yerine kendi boyutu sağlanarak anahtar yolu olarak şekillendirilir:
.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, bir küçük resmin talep edilebileceği bire bir tek hücreli bir ızgara parça alanı da oluşturur.
Küçük resim
appearance: none
stili, tarayıcı tarafından sağlanan 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ını kullanır.
Başparmak, input[type="checkbox"]
öğesine eklenmiş bir sözde öğe alt öğesidir ve ızgara alanını track
talep ederek parçanın altında değil, üstünde yer alır:
.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 dillerine ve hareket tercihlerine uyum sağlayan çok yönlü bir anahtar bileşeni sağlar.
Dokunma etkileşimi stilleri
Mobil cihazlarda tarayıcılar, etiketlere ve girişlere dokunma vurguları ve metin seçimi özellikleri ekler. Bu durum, geçişin gerektirdiği stil ve görsel etkileşim geri bildirimini olumsuz etkiledi. Birkaç satırlık CSS koduyla bu efektleri kaldırıp kendi cursor: pointer
stilimi ekleyebilirim:
.gui-switch {
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
Bu stiller değerli görsel etkileşim geri bildirimleri olabileceğinden, her zaman kaldırılması önerilmez. Kaldırdığınızda özel alternatifler sunduğunuzdan emin olun.
Parça
Bu öğenin stilleri çoğunlukla şekli ve rengiyle ilgilidir. Bu öğe, stillerine basamaklı stil sayfaları aracılığıyla üst öğe .gui-switch
üzerinden erişir.
.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ş parçası için çok çeşitli özelleştirme seçenekleri dört özel özellikten gelir. border: none
, appearance: none
tüm tarayıcılarda onay kutusundaki kenarlıkları kaldırmadığından eklenir.
Küçük resim
Başparmak öğesi zaten sağda track
ancak daire stillerine ihtiyacı var:
.gui-switch > input::before {
background: var(--thumb-color);
border-radius: 50%;
}
Etkileşim
Fareyle üzerine gelme vurgularını ve küçük resim konumundaki değişiklikleri gösterecek etkileşimlere hazırlanmak için özel özellikleri kullanın. Hareket veya fareyle üzerine gelme vurgulama stillerine geçiş yapılmadan ö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, parçadaki küçük resmi konumlandırmak için tek bir kaynak mekanizması sağlar. Kaydırma çubuğunun ve başparmağın boyutları, başparmağın doğru şekilde dengelenmesini ve kaydırma çubuğu içinde kalmasını sağlamak için hesaplamalarda kullanılabilir: 0%
ve 100%
.
input
öğesi, --thumb-position
konum değişkenine sahiptir ve thumb sözde öğesi bunu 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 daha önce koşullu olarak transition: transform
var(--thumb-transition-duration) ease
ayarladığımız için bu değişiklikler değiştirildiğinde animasyonlu olabilir:
/* 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)
);
}
Bu ayrılmış düzenlemenin iyi çalıştığını düşünüyorum. Başparmak öğesi yalnızca bir stil olan translateX
konumuyla ilgilenir. Giriş, tüm karmaşıklığı ve hesaplamaları yönetebilir.
Dikey
Destek, -vertical
öğesine CSS dönüşümleriyle döndürme ekleyen bir değiştirici sınıf -vertical
ile yapıldı.input
3D döndürülmüş bir öğe, bileşenin genel yüksekliğini değiştirmez ancak bu durum blok düzenini bozabilir. --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ı 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 Elad Schecter ile birlikte, tek bir değişkeni çevirerek sağdan sola dillerin işlendiği CSS dönüşümlerini kullanan kayarak açılan bir yan menü prototipi oluşturduk. Bunun nedeni, CSS'de mantıksal özellik dönüşümlerinin olmaması ve hiçbir zaman olmamasıdır. Elad, mantıksal dönüşümler için kendi özel mantığımızın tek bir konumdan yönetilmesine olanak tanımak amacıyla yüzdeleri tersine çevirmek için özel bir mülk değeri kullanma fikrini ortaya attı. Bu anahtarda da aynı tekniği kullandım ve çok iyi sonuç verdiğini düşünüyorum:
.gui-switch {
--isLTR: 1;
&:dir(rtl) {
--isLTR: -1;
}
}
--isLTR
adlı özel bir özellik başlangıçta 1
değerini içerir. Bu, düzenimiz varsayılan olarak soldan sağa olduğundan true
anlamına gelir. Ardından, CSS sözde sınıfı :dir()
kullanılarak bileşen soldan sağa düzen içinde olduğunda değer -1
olarak ayarlanır.
Dönüşüm içinde calc()
kullanarak --isLTR
öğesini işleme alın:
.gui-switch.-vertical > input {
transform: rotate(-90deg);
transform: rotate(calc(90deg * var(--isLTR) * -1));
}
Artık dikey anahtarın dönüşü, sağdan sola düzenin gerektirdiği karşı taraf konumunu hesaba katıyor.
Ayrıca, translateX
dönüşümlerinin, karşı taraf şartını 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ı karşılamasa da birçok kullanım alanı için bazı DRY (Kendini Tekrar Etme) ilkeleri sunar.
Eyaletler
Yerleşik input[type="checkbox"]
özelliğini kullanırken, bu özelliğin bulunabileceği çeşitli durumları (:checked
, :disabled
, :indeterminate
ve :hover
) ele almadan olmaz. :focus
, yalnızca ofsetinde ayarlama yapılarak kasıtlı olarak yalnız bırakıldı. Odak halkası Firefox ve Safari'de harika görünüyordu:
Kontrol edildi
<label for="switch-checked" class="gui-switch">
Default
<input type="checkbox" role="switch" id="switch-checked" checked="true">
</label>
Bu durum, on
durumunu gösterir. Bu durumda, giriş "parça" arka planı etkin renge, başparmak konumu ise "sona" 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 değişmez hale getirmelidir.Etkileşim değişmezliği tarayıcıdan bağımsızdır ancak appearance: none
kullanımı nedeniyle görsel durumlar için stiller gerekir.
.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%);
}}
}
}
Bu durum, hem devre dışı bırakılmış hem de işaretlenmiş durumlarla birlikte koyu ve açık temalar gerektirdiğinden karmaşıktır. Stil kombinasyonlarının bakım yükünü azaltmak için bu durumlar için stilistik olarak minimal stiller seçtim.
Belirsiz
Genellikle unutulan bir durum da onay kutusunun işaretli veya işaretsiz olmadığı :indeterminate
durumudur. Bu durum eğlenceli, davetkar ve mütevazı. Boole durumlarının, aralarda gizli durumları olabileceğini hatırlatır.
Onay kutusunu belirsiz olarak ayarlamak zordur, yalnızca JavaScript ile ayarlanabilir:
<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>
Durum bana göre mütevazı ve davetkar olduğundan anahtar başparmak konumunu ortaya yerleştirmek uygun olur:
.gui-switch > input:indeterminate {
--thumb-position: calc(
calc(calc(var(--track-size) / 2) - calc(var(--thumb-size) / 2))
* var(--isLTR)
);
}
İmleçle üzerine gelin
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önlendirmelidir. Bu anahtar, etiket veya girişin üzerine gelindiğinde yarı şeffaf bir halkayla küçük resmi vurgular. Bu fareyle üzerine gelme animasyonu, etkileşimli küçük resim öğesine yönlendirir.
"Vurgulama" efekti box-shadow
ile yapılır. Devre dışı bırakılmamış bir girişin üzerine gelindiğinde --highlight-size
simgesinin boyutunu artırın. Kullanıcı hareketle ilgili bir sorun yaşamıyorsa box-shadow
geçişini yaparız ve bu geçişin büyümesini izleriz. Kullanıcı hareketle ilgili bir sorun yaşıyorsa öne çıkan an anında gösterilir:
.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
Bana göre, özellikle bir pistin içindeki daire gibi bir anahtar arayüzü, fiziksel bir arayüzü taklit etmeye çalışırken tuhaf bir his veriyor. iOS, anahtarıyla bu işi doğru yaptı. Anahtarları yan yana sürükleyebiliyorsunuz ve bu seçeneğin olması çok tatmin edici. Aksine, bir sürükleme hareketi denenip hiçbir şey olmazsa kullanıcı arayüzü öğesi etkin değilmiş gibi görünebilir.
Sürüklenebilir küçük resimler
Başparmak sözde öğesi, konumunu .gui-switch > input
kapsamlı var(--thumb-position)
öğesinden alır. JavaScript, başparmak konumunu dinamik olarak güncellemek için girişte satır içi stil değeri sağlayabilir. Böylece başparmak, işaretçi hareketini takip ediyormuş gibi görünür. İşaretçi bırakıldığında satır içi stilleri kaldırın ve --thumb-position
özel özelliğini kullanarak sürüklemenin kapalıya mı yoksa açığa mı daha yakın olduğunu belirleyin. Bu, çözümün temelini oluşturur. CSS özel özelliklerini değiştirmek için işaretçi konumlarını koşullu olarak izleyen işaretçi etkinlikleri.
Bileşen, bu komut dosyası gösterilmeden önce zaten% 100 işlevsel olduğundan, mevcut davranışı korumak (ör. girişi değiştirmek için bir etiketi tıklamak) oldukça fazla çalışma gerektirir. JavaScript'imiz, mevcut özelliklerin pahasına özellik eklememelidir.
touch-action
Sürükleme, özel bir hareket olduğundan touch-action
avantajları için mükemmel bir adaydır. Bu anahtar için yatay hareket komut dosyamız tarafından işlenmeli veya dikey anahtar varyantı için dikey hareket yakalanmalıdır. touch-action
ile tarayıcıya bu öğede hangi hareketlerin işleneceğini söyleyebiliriz. Böylece bir komut dosyası, hareketi rekabet olmadan işleyebilir.
Aşağıdaki CSS, tarayıcıya bir işaretçi hareketi bu anahtar izinin içinden başladığında dikey hareketleri işlemesini, yatay hareketlerle ilgili hiçbir şey yapmamasını söyler:
.gui-switch > input {
touch-action: pan-y;
}
İstenen sonuç, sayfayı kaydırmayan veya sayfada gezinmeyen yatay bir harekettir. İşaretçi, girişte dikey olarak kaydırmaya başlayabilir ve sayfayı kaydırabilir ancak yatay kaydırma özel olarak işlenir.
Piksel değer stili yardımcı programları
Kurulum sırasında ve sürükleme işlemi esnasında, öğelerden çeşitli hesaplanmış sayı değerlerinin alınması gerekir. Aşağıdaki JavaScript işlevleri, bir CSS özelliği verildiğinde hesaplanmış 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()
işlevinin ikinci bir bağımsız değişkeni, hedef sözde öğeyi nasıl kabul ettiğine dikkat edin. JavaScript'in öğelerden, hatta sözde öğelerden bu kadar çok değer okuyabilmesi oldukça kullanışlıdır.
dragging
Bu, sürükleme mantığı için temel bir andır ve işlev etkinlik işleyicisinde dikkat edilmesi 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ı, bu komut dosyasının bir işaretçiyle birlikte konumlandırdığı küçük daire olan state.activethumb
'dır. switches
nesnesi, anahtarların .gui-switch
olduğu ve değerlerin, komut dosyasının verimli kalmasını sağlayan önbelleğe alınmış sınırlar ve boyutlar olduğu bir Map()
'dir. Sağdan sola, CSS'nin --isLTR
aynı özel özellik kullanılarak işlenir ve mantığı tersine çevirmek ve sağdan sola dil desteğini sürdürmek için bu özellikten yararlanılabilir. event.offsetX
değeri de önemlidir. Çünkü bu değer, başparmağın konumlandırılması için yararlı bir delta değeri içerir.
state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)
CSS'nin bu son satırı, küçük resim öğesi tarafından kullanılan özel özelliği ayarlar. Bu değer ataması normalde zaman içinde geçiş yapardı ancak önceki bir işaretçi etkinliği, --thumb-transition-duration
değerini geçici olarak 0s
olarak ayarlayarak yavaş bir etkileşime neden olabilecek durumu ortadan kaldırdı.
dragEnd
Kullanıcının anahtarın çok dışına sürükleyip bırakabilmesi için genel bir pencere etkinliğinin kaydedilmesi gerekiyordu:
window.addEventListener('pointerup', event => {
if (!state.activethumb) return
dragEnd(event)
})
Kullanıcının serbestçe sürükleme yapabilmesi ve arayüzün bunu hesaba alacak kadar akıllı olması gerektiğini düşünüyorum. Bu anahtarla işlemek çok fazla zaman almadı ancak geliştirme sürecinde dikkatli bir şekilde ele alınması gerekti.
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şin checked özelliğini ayarlamanın ve tüm hareket etkinliklerini kaldırmanın zamanı geldi. Onay kutusu state.activethumb.checked = determineChecked()
ile değiştirildi.
determineChecked()
dragEnd
tarafından çağrılan bu işlev, mevcut başparmağın parçasının sınırları içinde nerede bulunduğunu belirler ve parçanın yarısına eşit veya yarısından fazla ise 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
}
Ek düşünceler
Sürükleme hareketi, başlangıçta seçilen HTML yapısı nedeniyle biraz kod borcuna yol açtı. Özellikle de girişin bir etiketle sarmalanması bu duruma neden oldu. Bir üst öğe olan etiket, girişten sonra tıklama etkileşimleri alır. dragEnd
etkinliğinin sonunda, padRelease()
'nin garip bir işlev olduğunu fark etmiş olabilirsiniz.
const padRelease = () => {
state.recentlyDragged = true
setTimeout(_ => {
state.recentlyDragged = false
}, 300)
}
Bu, kullanıcının gerçekleştirdiği etkileşimin işaretini kaldıracağı veya işaretleyeceği için etiketin bu sonraki tıklamayı hesaba katması içindir.
Bu işlemi tekrar yapacak olsam, etiketin tıklamalarını kendisi işleyen ve yerleşik davranışla çakışmayan bir öğe oluşturmak için kullanıcı deneyimi yükseltmesi sırasında JavaScript ile DOM'u ayarlamayı düşünebilirim.
Bu tür JavaScript'i yazmayı en az sevdiğim şeydir. Koşullu etkinlik kabarcıklanmasını yönetmek istemiyorum:
const preventBubbles = event => {
if (state.recentlyDragged)
event.preventDefault() && event.stopPropagation()
}
Sonuç
Bu minik anahtar bileşeni, şimdiye kadarki tüm GUI Challenges'da en çok uğraştıran oldu. Bunu nasıl yaptığımı öğrendiğinize göre, siz nasıl yapardınız? 🙂
Yaklaşımlarımızı çeşitlendirelim ve web'de içerik oluşturmanın tüm yollarını öğrenelim. Bir demo oluşturun, bağlantıları bana tweet atın. Ben de bu bağlantıları aşağıdaki topluluk remiksleri bölümüne ekleyeyim.
Topluluk remiksleri
- @KonstantinRouda, demo ve code özel öğeleriyle.
- @jhvanderschee tarafından oluşturulan düğme: Codepen.
Kaynaklar
.gui-switch
Kaynak kodunu GitHub'da bulabilirsiniz.