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)

  1. Kayar Sekme Çubuğu: Mobilde yatay kaydırma için overflow-x:auto ve scroll-snap-x uygulanarak sekmeler tek tek “oturur” hale getirildi.
  2. Aktif Göstergesi (Active Bar): CSS ile altta akıcı bir gösterge çubuğu eklendi; JS ile aktif sekmeye hizalanıyor.
  3. Odak & Erişilebilirlik: role="tablist", role="tab", aria-selected ve aria-controls eklendi; klavye ile gezinme desteklendi.
  4. Mikro Animasyon: Kaydırma sırasında sekme çubuğunda hafif hareket ve gölge efekti ile yön algısı güçlendirildi.
  5. Performans: Pasif event listener, hafif JS (vanilla), GPU hızlandırmalı transform ve prefers-reduced-motion desteğ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 role ve aria-* öznitelikleri eklendi.
  • Klavye ile gezinme sağlandı (← → Home End).
  • prefers-reduced-motion ile animasyonlar azaltılabiliyor.

Performans Önlemleri

  • Vanilla JS; ek kütüphane kullanılmadı.
  • Pasif scroll dinleyicileri ve GPU hızlandırmalı transform kullanı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:

  1. Sekme başlıklarına hafif ikon seti (opsiyonel, metin öncelikli).
  2. Hızlı erişim için yatay kaydırma “ok butonu” (a11y uyumlu).
  3. Şehir/firma bazlı A/B test: sekme yerleşimi ve sırası ölçülerek en iyi varyantın seçilmesi.

Not: Bu iyileştirmeler, mevcut “scrollable sekme sistemi” mimarisiyle %100 uyumludur ve modüler yapıda devreye alınmıştır.

Benzer Gönderiler

Fikirleriniz, bizim için çok değerli ,lütfen paylaşın.