Bu blog yazısının Haziran 2015'te yayınlandığını, dolayısıyla ne zaman okuduğunuza bağlı olarak bazı bölümlerinin güncelliğini yitirebileceğini lütfen unutmayın. Maalesef, bilgilerin doğru kalmasını sağlamak için bu yazıları her zaman tam olarak güncel tutamıyorum.
- Test Sayfam
- Varsayılan Davranışı Anlamak
- "-webkit-overflow-scrolling" CSS Kuralının Ne Yaptığını Anlamak
- Kullanıcı, lastik bant etkisi bitene kadar beklemeli
- Arka Plan Sayfasının Kaydırılmasını Nasıl Önlersiniz
- Arka sayfaya aşırı kaydırmayı nasıl engellersiniz?
- Arka Sayfaya Aşırı Kaydırmayı Nasıl Önlersiniz?
- Tüm Sayfa Kaynak Kodu
iOS'ta Safari'de yaşanan son bir kaydırma sorununu çözebilmek için kendi basit test sayfamı oluşturmam gerekti ve ardından sorunu çözmeye çalışmak için internette bulabildiğim tüm bilgiler ve kombinasyonları uygulamaya çalıştım.
Bu süreçte keşfettiklerimin kısa bir özeti aşağıdadır.
Test Sayfam
Test sayfam oldukça basitti. Sayfayı temsil etmek için statik bir div içinde sahte veriler vardı ve sayfanın üzerinde yer alan bir menüyü temsil eden sabit bir div de bulunuyordu; şu şekildeydi.
Sayfaya ait tüm kaynak kodu bu blog yazısının en altında bulunabilir.
Varsayılan Davranışı Anlamak
İlk yaptığım şey, iOS'taki Safari'nin varsayılan davranışını anlamaya çalışmaktı. En dikkat çekici gözlem ise, menünün en altına kadar kaydırdığınızda sayfanın gövdesinin bir lastik bant etkisi göstermesiydi - Safari'de yerleşik olarak kodlanmış bir özelliktir.
Menünün en üstüne kaydırırken de aynı şey oldu.
Ancak fark ettiğim ilk sorun, sürekli olarak en üste ya da en altta kadar kaydırırsanız Safari'nin hem arka plan sayfasında hem de menüde render hataları göstermeye başlamasıydı.
Nedenini tam olarak bilmiyorum, ama bunun lastik bant özelliğiyle ilgili olduğuna inanıyorum.
"-webkit-overflow-scrolling" CSS Kuralının Ne Yaptığını Anlamak
Bir sonraki adım olarak menüye -webkit-overflow-scrolling CSS kuralını uyguladım; bu, momentum tabanlı kaydırmayı etkinleştirir.
Aşağıdaki resimde gösterildiği gibi, parmağımla kaydırdıktan sonra bile kaydırma devam ediyor.
Ama en üste ya da en alta kaydırırken de lastik bant etkisi oluşur; aşağıda gösterildiği gibi.
Kullanıcı, lastik bant etkisi bitene kadar beklemeli
Testlerim sırasında, kauçuk bant etkisi devam ederken kullanıcının animasyon tamamen tamamlanana kadar başka bir öğeye odaklanamayacağını da fark ettim.
Aşağıdaki örnekte önce arka plan sayfasını kaydırıyorum, sonra menüyü hızlıca kaydırmaya çalışıyorum; ancak sonunda arka plan sayfasını kaydırmaya devam ediyorum.
Ancak efektin bitmesini bir an beklersem menüyü kaydırmaya başlayabilirim.
Arka Plan Sayfasının Kaydırılmasını Nasıl Önlersiniz
Testlerim sırasında, lastik bant etkisi devam ederken kullanıcı başka bir öğeye odaklanamıyor ve animasyon tamamen bitene kadar bu durum sürüyor.
Stack Overflow'daki bu yanıt temel alınarak, Stack Overflow ile, disable-scrolling sınıfına sahip öğelerin touchmove olayı tetiklendiğinde varsayılan kaydırma işlemini gerçekleştirmemelerini sağlayabilirsiniz.
document.ontouchmove = function(event) {
var isTouchMoveAllowed = true,
target = event.target;
while (target !== null) {
if (target.classList && target.classList.contains('disable-scrolling')) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if (!isTouchMoveAllowed) {
event.preventDefault();
}
};
Ve sonra disable-scrolling sınıfını sayfa içindeki div'e uygulayın:
<div class="page disable-scrolling">
Bu şekilde çalışıyor, ancak daha kapsamlı testler, menünün en üstüne veya en altına ulaştığınızda arka plan sayfasının hâlâ bazen kaydırılabileceğini gösteriyor.
Arka sayfaya aşırı kaydırmayı nasıl engellersiniz?
Bu çözüm ile artık 'overscroll'ı önlemek mümkün hale geliyor. Bu, bir öğe en üstte ya da en altta kaydırıldığında kaydırmanın sayfa içeriğine geçmemesi anlamına gelir.
Sonuç olarak sayfa kaydırılamaz hâle gelir ve bu da lastik bant etkisinin oluşmasını engeller.
function removeIOSRubberEffect(element) {
element.addEventListener("touchstart", function() {
var top = element.scrollTop,
totalScroll = element.scrollHeight,
currentScroll = top + element.offsetHeight;
if (top === 0) {
element.scrollTop = 1;
} else if (currentScroll === totalScroll) {
element.scrollTop = top - 1;
}
});
}
removeIOSRubberEffect(document.querySelector(".scrollable"));
Bu JavaScript kod parçacığının yaptığı iş, öğenin en üstte ya da en altta tamamen ulaşmasını engellemek için onu sadece 1 piksel uzağa tutmaktır.
Kaydırma konumu mutlak en üst veya en alt sınırına hiç ulaşmazsa, aşırı kaydırma asla meydana gelmez.
Arka Sayfaya Aşırı Kaydırmayı Nasıl Önlersiniz?
Menüden kauçuk bant etkisini kaldırmak istersen — estetik nedenlerle veya benim durumumda olduğu gibi ek render hatalarına yol açtığı için — sadece -webkit-overflow-scrolling CSS kuralını kaldır.
Ancak aşağıda gördüğünüz gibi akıcı kaydırma hareketini de kaybediyorsunuz.
Tüm Sayfa Kaynak Kodu
Sayfanın tüm kaynak kodu burada.
<!-- License MIT, Author Special Agent Squeaky (specialagentsqueaky.com) --> <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style> .page{ font-size: 24px; overflow: scroll; } .menu{ position: fixed; top: 0; bottom: 0; left: 0; width: 80%; background: gray; z-index: 1; font-size: 10px; overflow: scroll; /* uncomment to get smooth momentum scroll, but also a rubber band effect */ /*-webkit-overflow-scrolling: touch;*/ } .menu-item{ padding: 10px; background: darkgray; font-size: 24px; } </style>
</head>
<body>
<div class="menu scrollable">
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
<div class="menu-item">hello world</div>
</div>
<div class="page disable-scrolling">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book. It has survived not only five centuries, but also the leap into
electronic typesetting, remaining essentially unchanged. It was popularised in
the 1960s with the release of Letraset sheets containing Lorem Ipsum passages,
and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</div>
<script>
document.ontouchmove = function(event) {
var isTouchMoveAllowed = true,
target = event.target;
while (target !== null) {
if (target.classList && target.classList.contains('disable-scrolling')) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if (!isTouchMoveAllowed) {
event.preventDefault();
}
};
function removeIOSRubberEffect(element) {
element.addEventListener("touchstart", function() {
var top = element.scrollTop,
totalScroll = element.scrollHeight,
currentScroll = top + element.offsetHeight;
if (top === 0) {
element.scrollTop = 1;
} else if (currentScroll === totalScroll) {
element.scrollTop = top - 1;
}
});
}
removeIOSRubberEffect(document.querySelector(".scrollable"));
</script>
</body>
</html>