Duyarlı ve erişilebilir bir anahtar bileşeni oluşturmaya dair temel bir genel bakış.
Bu gönderide, geçiş bileşenleri oluşturmanın bir yolu üzerine düşüncelerimi paylaşmak istiyorum. Demoyu deneyin.
Video kullanmayı tercih ederseniz bu gönderinin YouTube versiyonunu kullanabilirsiniz:
Genel Bakış
Anahtar, onay kutusuna benzer şekilde çalışır. ancak boole açık ve kapalı durumlarını açıkça temsil eder.
Bu demo, büyük çoğunluğu <input type="checkbox" role="switch">
kullanıyor
veya CSS veya JavaScript'in gerekli olmaması gibi bir avantaja sahiptir:
ve erişilebilir hale getirebilirsiniz. CSS'nin yüklenmesi, sağdan sola desteği sağlar
diller, dikeylik, animasyon ve daha fazlası. JavaScript yüklenirken geçiş yapılır
ve somut olması gerekir.
Özel özellikler
Aşağıdaki değişkenler, anahtarın çeşitli kısımlarını ve bunların
seçenekleri vardır. Üst düzey sınıf olan .gui-switch
, kullanılan özel özellikleri içerir
ve merkezileştirilmiş yapı için giriş noktalarından
birçok seçenek var.
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 renkleri vurgular:
.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%);
}
}
Az hareket
Net bir takma ad eklemek ve tekrarı azaltmak için, hareket tercihini azaltan bir kullanıcı medya sorgusu, PostCSS eklentisi bu taslağa göre Medya Sorgularında spesifikasyon 5:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Brüt kar
<input type="checkbox" role="switch">
öğemi
<label>
, onay kutusu ve etiket ilişkilendirmesini önlemek için ilişkilerini gruplandırıyor
kullanıcıya etiket ile etkileşim kurmasına olanak tanırken
kullanıcıya belirsizlik,
girişi değiştirin.
<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 eyaletmek. İlgili içeriği oluşturmak için kullanılan
tarayıcı
checked
mülk ve giriş
etkinlikler
oninput
ve onchanged
gibi.
Düzenler
Flexbox grid ve custom özellikleri kritik öneme sahiptir. korumak için kritik önem taşır. Değerleri tek bir yerde toplar, size adlar hesaplamaları veya alanları değiştirebilir ve küçük bir özel özelliği etkinleştirebilirsiniz. Kolay bileşen özelleştirmeleri için API.
.gui-switch
Anahtarın üst düzey düzeni flexbox'tır. .gui-switch
sınıfı şunu içeriyor:
çocukların kendi hesaplarını hesaplamak için kullandıkları özel ve
düzenler.
.gui-switch {
display: flex;
align-items: center;
gap: 2ch;
justify-content: space-between;
}
Flexbox düzenini genişletme ve değiştirme, herhangi bir flexbox düzenini değiştirmeye benzer.
Örneğin, etiketleri bir anahtarın üstüne veya altına yerleştirmek ya da
flex-direction
:
<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
ve bunun yerine kendi boyutunu sağ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şparmağını ekranda ayrı ayrı görüntüleyecek şekilde tek hücreli ızgara hak talebi.
Küçük resim
appearance: none
stili,
emin olun. Bu bileşen,
sözde öğe ve :checked
sahte-sınıf olarak
bu görsel göstergeyi değiştirmeyin.
Baş parmak, input[type="checkbox"]
öğesine bağlı sözde öğe bir alt öğesidir ve
ızgara alanında hak talebinde bulunarak reklamın altında değil, üzerinde yığınlar oluşturur
track
:
.gui-switch > input::before {
content: "";
grid-area: track;
inline-size: var(--thumb-size);
block-size: var(--thumb-size);
}
Stiller
Özel özellikler, renge uyum sağlayan çok yönlü bir anahtar bileşeni sağlar sağdan sola yazılan diller ve hareket tercihleri gibi.
Dokunma etkileşimi stilleri
Mobil cihazlarda, tarayıcılar etiketlere ve etiketlere dokunarak vurgulama ve metin seçme özelliklerini
giriş değerleridir. Bunlar, süreç boyunca sergilenen stil ve görsel etkileşim
gerek yoktur. Birkaç satırlık CSS ile bu efektleri kaldırıp öğe ekleme
kendi cursor: pointer
stilim:
.gui-switch {
cursor: pointer;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
Görsel olarak değerli olabileceğinden bu stillerin kaldırılması her zaman tavsiye edilmez. etkileşim geri bildirimidir. Kaldırmanız durumunda özel alternatifler de sağladığınızdan emin olun.
Parça
Bu öğenin stilleri, çoğunlukla şekli ve rengi ile ilgilidir.
ana yayıncıdan .gui-switch
aracılığıyla
cascade.
.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 dört farklı özelleştirme seçeneğinden
özel özellikler. appearance: none
şunu yapmadığı için border: none
eklendi:
tüm tarayıcılarda onay kutusundaki kenarlıkları kaldırın.
Küçük resim
Beğenme öğesi zaten sağ track
üzerinde ancak daire stillerine ihtiyacı var:
.gui-switch > input::before {
background: var(--thumb-color);
border-radius: 50%;
}
Etkileşim
Fareyle üzerine gelindiğinde görüntülenecek etkileşimlere hazırlanmak için özel özellikleri kullanın başparmak konumu değişikliklerine dikkat edin. Kullanıcının tercihi aynı zamanda taşımadan önce kontrol edildi hareket veya fareyle üzerine gelme stillerini ayarlayın.
.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;
}}
}
Küçük resim pozisyonu
Özel özellikler, başparmağınızı konumlandırabilmeniz için tek bir kaynak mekanizma sağlar
parçayı tıklayın. Kullanacağımız ray ve parmak boyutları
başparmağınızın doğru uzaklık ve yol arasında kalmasını sağlayacak şekilde hesaplama yapın:
0%
ve 100%
.
input
öğesi, --thumb-position
konum değişkenine ve baş parmak
sözde öğe, 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
değerini CSS'den ve sözde sınıflardan değiştirebiliriz
sağlanır. Bu öğede koşullu olarak transition: transform
var(--thumb-transition-duration) ease
değerini daha erken 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 bağımsız düzenlemenin işe yaradığını düşünmüştüm. Küçük resim öğesi
yalnızca tek bir stil ve translateX
konumuyla ilgilenir. Giriş, tüm reklam öğelerini
karmaşıklık ve hesaplamalar şeklinde olabilir.
Sektör
Destek, -vertical
değiştirici sınıfıyla yapıldı. Bu sınıf,
CSS, input
öğesine dönüşür.
Bununla birlikte, 3D döndürülmüş bir öğe, bileşenin toplam yüksekliğini değiştirmez,
Bu da blok düzenini bozabilir. Bunu --track-size
ve
--track-padding
değişken. Bir satır için gereken minimum alan miktarını
beklendiği gibi düzene girmek için dikey bir düğme:
.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şı Elad Schecter ve ben, birlikte sağdan sola işlenen CSS dönüşümlerinin kullanıldığı, dışarıya kaydırılan bir yan menü tek bir sayfayı çevirerek değişkenine eklenmelidir. Bunu yaptık. Bunun nedeni, CSS'de mantıksal özellik dönüşümlerinin olmaması ve elde edemeyebilirsiniz. Elad, teklif stratejisi kapsamında özel mülk değeri kendi özel konumlarımızı tek konum yönetimine izin vermek için mantıksal dönüşümler için kullanılan bir metodolojidir. Bu geçişte aynı tekniği kullandım bence:
.gui-switch {
--isLTR: 1;
&:dir(rtl) {
--isLTR: -1;
}
}
--isLTR
adlı özel özellik başlangıçta 1
değerine sahiptir, yani
Düzenimiz varsayılan olarak soldan sağa olduğundan true
. Ardından, CSS'yi kullanarak
sözde sınıf :dir()
,
bileşen sağdan sola düzen içinde olduğunda değer -1
olarak ayarlanır.
--isLTR
öğesini, bir dönüşümün içindeki calc()
içinde kullanarak işleme alın:
.gui-switch.-vertical > input {
transform: rotate(-90deg);
transform: rotate(calc(90deg * var(--isLTR) * -1));
}
Şimdi dikey anahtarın dönüşü karşı taraf konumu dikkate alır sağdan sola düzenin gerektirdiği şekilde değiştirin.
Küçük resim öğesi üzerindeki translateX
dönüşümlerinin de
karşı taraf şartını hesaba katın:
.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 gibi bir kavramla ilgili tüm ihtiyaçları karşılamak için işe yaramayabilir. ancak dönüşüm gerçekleştirildiğinde Birçok kullanıcı için DRY ilkeleri örnekler üzerinden görüntüleyebilirsiniz.
Eyaletler
Yerleşik input[type="checkbox"]
kullanımı,
olabileceği çeşitli durumları ele alıyor: :checked
, :disabled
,
:indeterminate
ve :hover
. :focus
kasıtlı olarak yalnız bırakıldı.
yalnızca ofsetinde yapılan düzenleme; odaklama halkası Firefox'ta ve
Safari:
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, "track" girişi
arka planın etkin renge ve başparmak konumu, "
sona erdir".
.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 düğmenin
element immutable.Etkileşim değişmezliği tarayıcıdan bağımsızdır, ancak
appearance: none
kullanımı nedeniyle görsel durumlar için stil gerekiyor.
.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ışı hem de devre dışı bırakılmış koyu ve açık temaya ihtiyaç duyduğundan zor olabilir. kontrol edilmiş durumda olur. Bu durumlara kolaylık sağlaması için stil olarak minimal stiller seçtim bakım yükünü üstlenmektir.
Belirsiz
Genellikle unutulan durum :indeterminate
şeklindedir. Bu durumda onay kutusu
veya işareti kaldırıldı. Bu eğlenceli bir durum, davet edici ve mütevazı. İyi
boole durumlarının aralarında gizli olabileceğini hatırlatmak isteriz.
Belirsiz bir onay kutusu ayarlamak zordur, 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>
Eyalet benim için mütevazı ve davetkar olduğu için anahtarın başparmak konumu orta:
.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 öğelerin üzerine gelerek etkileşimleri, bağlı kullanıcı arayüzü için görsel destek sağlamalı ve ayrıca, yönlendirici kullanıcı arayüzüne doğru yön verin. Bu geçiş, başparmağını yarı saydam bir halka oluşturarak etiket veya giriş üzerine gelin. Bu fareyle üzerine gelme animasyonu, etkileşimli küçük resim öğesine doğru yön sağlar.
"Öne çıkan an" efekt box-shadow
ile yapılır. Devre dışı bırakılan bir girişin üzerine gelindiğinde --highlight-size
boyutunu artırın. Kullanıcı hareket etmeye uygunsa box-shadow
öğesini değiştiririz ve büyüdüğünü görürüz. Hareketi rahatsız ediyorsa 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 emüle etme girişiminde bir çemberin bulunduğu bu tür bir resim gibi. iOS bunu doğru bildi sağ taraftaki düğmeyle yan yana sürükleyebilirsiniz. Sürükleyebilirsiniz. seçeneği de sunulur. Buna karşılık, sürükleme hareketi ve hiçbir şey olmuyor.
Sürüklenebilir baş parmaklar
Baş parmak sözde öğesi, konumunu .gui-switch > input
öğesinden alır
var(--thumb-position)
ayarlanırsa JavaScript,
başparmak konumunu dinamik olarak güncelleyerek
tıklayın. İşaretçi serbest bırakıldığında satır içi stilleri kaldırın ve
özel özelliği kullanarak sürüklemenin kapalı mı yoksa açık mı olduğunu belirleyin
--thumb-position
Bu, çözümün bel kemiğidir. işaretçi etkinlikleri
İşaretçi konumlarını koşullu olarak izleyerek CSS özel özelliklerini değiştirebilirsiniz.
Bu komut dosyası gösterilmeden önce bileşen zaten% 100 işlevsel olduğundan veya yeniden pazarlama gibi mevcut davranışı korumak için bir etiketi tıklayarak girişi değiştirin. JavaScript kodumuz ve mevcut özelliklerin pahasına.
touch-action
Sürükleme, özel bir harekettir ve bu hareketi yapmak için mükemmel bir adaydır.
touch-action
avantajları. Bu geçişte, yatay bir hareket
komut dosyamız tarafından veya dikey geçiş için yakalanan dikey bir hareket tarafından
varyantı. touch-action
ile tarayıcıya hangi hareketlerin işlenmesini söyleyebiliriz
Böylece bir komut dosyası hareketi rekabet olmadan işleyebilir.
Aşağıdaki CSS, tarayıcıya bir işaretçi hareketinin başlangıcında yatay yönde hareketler yapın, yatay öğelerin yanı sıra hiçbir işlem yapmayın. şunlardır:
.gui-switch > input {
touch-action: pan-y;
}
İstenen sonuç, aynı zamanda kaydırma yapmayan veya kaydırmayan yatay bir harekettir. sayfasını ziyaret edin. İşaretçi, girişin içinden başlayarak dikey olarak kaydırabilir ve ancak yatay olanlar özel olarak işlenir.
Piksel değeri stili yardımcı programları
Kurulumda ve sürükleme sırasında çeşitli hesaplanan sayı değerlerinin yakalanması gerekir.
uzaklaştırın. Aşağıdaki JavaScript işlevleri, hesaplanan piksel değerlerini döndürür
bir CSS mülkü belirtecek olursak. Bu gibi kurulum komut dosyasında 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, sanal bir hedef öğe olan ikinci bir bağımsız değişkeni nasıl kabul ettiğine dikkat edin. JavaScript'in, sözde öğeler de dahil olmak üzere öğelerden bu kadar çok değeri okuyabilmesi çok kullanışlı.
dragging
Bu, sürükleme mantığının temel aşamalarından biridir. Burada dikkat edilmesi gereken birkaç nokta vardır: kodu işlev etkinlik işleyicisinden kaldırın:
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ı hero: state.activethumb
ve bu komut dosyasının küçük dairesi
konumlandırmayı bir işaretçiyle birlikte gösterir. switches
nesnesi bir Map()
olup
anahtar .gui-switch
'lere aittir ve değerler, önbelleğe alınmış sınırlar ve boyutlardır.
verimli olmasını sağlar. Sağdan sola, aynı özel özellik kullanılarak işlenir.
CSS'nin --isLTR
olduğunu ve mantığı tersine çevirmek ve işleme devam etmek için bunu kullanabilir.
RTL'yi destekler. event.offsetX
, delta içerdiği için de değerlidir
başparmağı konumlandırmak için yararlı olacak bir değer kullanın.
state.activethumb.style.setProperty('--thumb-position', `${track + pos}px`)
CSS'nin bu son satırı, thumb öğesi tarafından kullanılan özel özelliği ayarlar. Bu
Aksi takdirde, değer ataması zaman içinde değişecekti, ancak
etkinlik geçici olarak --thumb-transition-duration
ayarını 0s
olarak değiştirdi.
yavaş bir etkileşim olur.
dragEnd
Kullanıcının anahtarın dışına sürükleyip bırakmasına izin verilebilmesi için gerekli genel pencere etkinliğinin kaydedilmesi:
window.addEventListener('pointerup', event => {
if (!state.activethumb) return
dragEnd(event)
})
Bir kullanıcının serbest bir şekilde sürükleme özgürlüğüne ve sahip hesaba katacak kadar akıllı olmasını öneririz. Yapmak çok zor olmadı ancak geliştirme sürecinde dikkatli bir şekilde düşünülmesi gerekti. bahsedeceğim.
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şi ayarlama zamanı işaretlendi
özellik ve tüm hareket etkinliklerini kaldırın. Onay kutusu
state.activethumb.checked = determineChecked()
determineChecked()
dragEnd
tarafından çağrılan bu işlev, baş akımının nerede olduğunu belirler
Parkurun sınırları içindedir ve eşittir veya eşitse true değerini döndürür
henüz yolun ortasında:
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, ilk HTML yapısı nedeniyle biraz kod borçludur
Bu işlem, çoğunlukla girişi bir etikette sarmalar. Ebeveyn olarak etiket
öğesi içeriyorsa girişten sonra tıklama etkileşimleri alır. Bu
dragEnd
etkinliği. padRelease()
sesinin tuhaf geldiğini fark etmiş olabilirsiniz.
işlevini kullanın.
const padRelease = () => {
state.recentlyDragged = true
setTimeout(_ => {
state.recentlyDragged = false
}, 300)
}
Bu, etiketin işareti kaldırılacağından, bu tıklamayı alan etiketin kullanıcının gerçekleştirdiği etkileşimi temel alır.
Bunu tekrar yaparsam DOM'yi JavaScript ile ayarlamayı düşünebilirim Böylece, etiket tıklamalarını işleyen bir öğe oluşturabilirsiniz. yerleşik davranışla savaşmıyor.
Bu tür JavaScript yazmayı pek sevmiyorum çünkü koşullu etkinlik kabarcıkları:
const preventBubbles = event => {
if (state.recentlyDragged)
event.preventDefault() && event.stopPropagation()
}
Sonuç
Bu ufak geçiş bileşeni, tüm GUI Zorlukları arasında en çok çalışma gerektiren oldu Şimdilik hoşça kalın. Şimdi bunu nasıl yaptığımı öğrendiğinize göre siz nasıl ‽ 🙂
Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim. Bir demo oluşturup beni tweet'le bağlantıları eklerim aşağıdaki topluluk remiksleri bölümüne gidin!
Topluluk remiksleri
- Özel bir öğeyle @KonstantinRouda: demo ve kod.
- @jhvanderschee ve bir düğme: Codepen.
Kaynaklar
.gui-switch
kaynak kodunu şurada bulun:
GitHub'ı tıklayın.