Geliştirici Günlüğü: Firma Sayfalarında Sekme Sistemi İyileştirmesi
Firma Sayfalarında Sekme Sistemi İyileştirmesi
Tarih: 2025-09-26 • Kapsam: UI/UX, CSS, JS, Erişilebilirlik, Performans
Amaç
Firma sayfalarımızda yer alan Genel / Ürünler / Hizmetler / Blog / Sayfalar sekme yapısının mobilde tam görünür olmaması ve aktif sekmenin yeterince vurgulanmaması sorunlarını gidererek; kaydırılabilir, akıcı, erişilebilir ve performanslı bir sekme deneyimi sunmak.
Mevcut Durum & Sorun Tespiti
- Mobilde sekmeler taşma yapıyor, tamamı görülemiyordu.
- Aktif sekmenin görsel vurgusu zayıftı; kullanıcı hangi sekmede olduğunu anlık ayırt edemiyordu.
- Klavye/okunabilirlik (a11y) ögeleri eksikti (rol, aria-attributes).
Yapılan İyileştirmeler (Özet)
- Kayar Sekme Çubuğu: Mobilde yatay kaydırma için
overflow-x:autovescroll-snap-xuygulanarak sekmeler tek tek “oturur” hale getirildi. - Aktif Göstergesi (Active Bar): CSS ile altta akıcı bir gösterge çubuğu eklendi; JS ile aktif sekmeye hizalanıyor.
- Odak & Erişilebilirlik:
role="tablist",role="tab",aria-selectedvearia-controlseklendi; klavye ile gezinme desteklendi. - Mikro Animasyon: Kaydırma sırasında sekme çubuğunda hafif hareket ve gölge efekti ile yön algısı güçlendirildi.
- Performans: Pasif event listener, hafif JS (vanilla), GPU hızlandırmalı transform ve
prefers-reduced-motiondesteği eklendi.
Teknik Uygulama
1) HTML (Rol & ARIA Yapısı)
<nav class="firma-tabs" role="tablist" aria-label="Firma Sekmeleri">
<button role="tab" class="tab is-active" aria-selected="true" aria-controls="panel-genel" id="tab-genel">Genel</button>
<button role="tab" class="tab" aria-selected="false" aria-controls="panel-urunler" id="tab-urunler">Ürünler</button>
<button role="tab" class="tab" aria-selected="false" aria-controls="panel-hizmetler" id="tab-hizmetler">Hizmetler</button>
<button role="tab" class="tab" aria-selected="false" aria-controls="panel-blog" id="tab-blog">Blog</button>
<button role="tab" class="tab" aria-selected="false" aria-controls="panel-sayfalar" id="tab-sayfalar">Sayfalar</button>
<span class="tab-active-bar" aria-hidden="true"></span>
</nav>
<section id="panel-genel" role="tabpanel" aria-labelledby="tab-genel">...</section>
<section id="panel-urunler" role="tabpanel" aria-labelledby="tab-urunler" hidden>...</section>
<section id="panel-hizmetler" role="tabpanel" aria-labelledby="tab-hizmetler" hidden>...</section>
<section id="panel-blog" role="tabpanel" aria-labelledby="tab-blog" hidden>...</section>
<section id="panel-sayfalar" role="tabpanel" aria-labelledby="tab-sayfalar" hidden>...</section>
2) CSS (Kayar Çubuk, Scroll Snap, Active Bar)
.firma-tabs{
display:flex; gap:.5rem; align-items:center; position:relative;
overflow-x:auto; padding:.5rem .75rem; scroll-snap-type:x mandatory;
border-bottom:1px solid var(--kadence-border, #e5e7eb);
-webkit-overflow-scrolling:touch;
}
.firma-tabs::-webkit-scrollbar{ height:6px; }
.firma-tabs::-webkit-scrollbar-thumb{ background:#d1d5db; border-radius:999px; }
.tab{
white-space:nowrap; scroll-snap-align:start;
border:none; background:transparent; padding:.5rem .75rem; border-radius:.5rem;
font-weight:600; color:#1f2937; position:relative;
}
.tab:is(:hover,:focus){ background:#f3f4f6; outline:none; }
.tab.is-active{ color:#0f66ff; }
.tab-active-bar{
position:absolute; left:0; bottom:0; height:2px; width:0;
background:#0f66ff; border-radius:2px; transition:transform .25s ease, width .25s ease;
transform:translateX(0);
}
/* Kaydırma yönünü hissettiren hafif gölge */
.firma-tabs.scrolling::after{
content:""; position:absolute; right:0; top:0; bottom:0; width:24px;
pointer-events:none; background:linear-gradient(to left, rgba(0,0,0,.06), rgba(0,0,0,0));
}
/* Hareket hassasiyeti olan kullanıcılar için animasyon azalt */
@media (prefers-reduced-motion: reduce){
.tab-active-bar{ transition:none; }
}
3) JS (Aktif Çubuk Konumlama, ARIA & Klavye, Scroll İpuçları)
document.addEventListener('DOMContentLoaded',function(){
const nav = document.querySelector('.firma-tabs');
const tabs = Array.from(nav.querySelectorAll('.tab'));
const bar = nav.querySelector('.tab-active-bar');
function positionBar(el){
const r = el.getBoundingClientRect();
const nr = nav.getBoundingClientRect();
bar.style.width = r.width + 'px';
bar.style.transform = 'translateX(' + (r.left - nr.left + nav.scrollLeft) + 'px)';
}
function setActive(next){
tabs.forEach(t => {
const active = (t === next);
t.classList.toggle('is-active', active);
t.setAttribute('aria-selected', active ? 'true' : 'false');
const panel = document.getElementById(t.getAttribute('aria-controls'));
if(panel){ panel.hidden = !active; }
});
positionBar(next);
// görünür alana kaydır
next.scrollIntoView({behavior:'smooth', inline:'center', block:'nearest'});
}
// ilk konum
const current = tabs.find(t => t.classList.contains('is-active')) || tabs[0];
setActive(current);
// tıklama
tabs.forEach(t => t.addEventListener('click', () => setActive(t)));
// klavye (← → Home End)
nav.addEventListener('keydown', e => {
const i = tabs.indexOf(document.activeElement);
if(i < 0) return;
if(e.key === 'ArrowRight'){ e.preventDefault(); (tabs[i+1]||tabs[0]).focus(); setActive(tabs[i+1]||tabs[0]); }
if(e.key === 'ArrowLeft'){ e.preventDefault(); (tabs[i-1]||tabs.at(-1)).focus(); setActive(tabs[i-1]||tabs.at(-1)); }
if(e.key === 'Home'){ e.preventDefault(); tabs[0].focus(); setActive(tabs[0]); }
if(e.key === 'End'){ e.preventDefault(); tabs.at(-1).focus(); setActive(tabs.at(-1)); }
});
// kaydırma ipucu (gölge)
let scrollingTimer;
nav.addEventListener('scroll', () => {
nav.classList.add('scrolling');
clearTimeout(scrollingTimer);
scrollingTimer = setTimeout(() => nav.classList.remove('scrolling'), 150);
// aktif bar konumunu scroll ile güncel tut
const active = nav.querySelector('.tab.is-active');
if(active) positionBar(active);
}, {passive:true});
// pencere boyutu değişince hizalama
window.addEventListener('resize', () => {
const active = nav.querySelector('.tab.is-active');
if(active) positionBar(active);
});
});
Erişilebilirlik (a11y)
- Sekme yapısına uygun
rolevearia-*öznitelikleri eklendi. - Klavye ile gezinme sağlandı (← → Home End).
prefers-reduced-motionile animasyonlar azaltılabiliyor.
Performans Önlemleri
- Vanilla JS; ek kütüphane kullanılmadı.
- Pasif scroll dinleyicileri ve GPU hızlandırmalı
transformkullanıldı. - DOM ölçümlendirme minimal tutuldu; yalnızca aktif sekmede hesaplama yapılıyor.
Test Sonuçları
- Cihazlar: Android (Chrome), iOS (Safari), masaüstü (Chrome/Firefox).
- Davranış: Sekmeler sorunsuz kayıyor, aktif çubuk doğru konumlanıyor.
- Erişilebilirlik: Klavye navigasyonu ve ekran okuyucu etiketleri başarılı.
Sonuç & Yol Haritası
Mobil kullanılabilirlik, erişilebilirlik ve görsel geri bildirimler belirgin şekilde iyileştirildi. Bir sonraki adımda:
- Sekme başlıklarına hafif ikon seti (opsiyonel, metin öncelikli).
- Hızlı erişim için yatay kaydırma “ok butonu” (a11y uyumlu).
- Şehir/firma bazlı A/B test: sekme yerleşimi ve sırası ölçülerek en iyi varyantın seçilmesi.