Trendyol’da Baklava design sistemi geliştiriyoruz ve kullanıyoruz. Geçenlerde bir diyalog açıkken bir toast mesajı geldiğinde diyalog elementinin dışında kalan alanların üzerini kapattığımız elemanın (backdrop) altında kalıyor. Burada şöyle bir sorun var biz modal bileşeni için HTML <dialog>elementini kullanıyoruz. Bu elementin backdrop özelliği dokümanın z-index yapısından etkilenmemek için üst katman (aşağıda daha fazla detay var) adı verilen HTML dokümanı ile aynı seviyede bir yere konumlanıyor. Böyle olunca doküman içindeki herhangi bir elemanınızın üste çıkma ihtimali kalmıyor. Peki bu sorunu aşmak için ne yapabiliriz? Biraz araştırınca Popover API ile karşılaştık. Popover API <dialog> elementi ile aynı seviyede olduğu için z-index sorununu çözüyor. Tabi buradaki sorun henüz tarayıcıların bu özelliği yeni yeni desteklemeye başlıyor olması. Bir ihtimal olarak polyfill ile çözüm oluşturulabilir.

Popover elemanı web sayfalarında genel olarak kullanılan yapılardır. Sayfa içeriğinin üzerinde kullanıcının dikkatini çeken bir alan oluşturup, kullanıcıyı bilgilendirmek veya aksiyon almak için oluşturulan yapılar olarak tanımlayabiliriz. Datepicker, tooltip, selectmenu, toast mesajları, form alanlarında kullanılan otomatik doldurma alanları ve öğretici yapılar popover için örnek kullanım alanları olarak gösterilebilir.

Üst katman (top layer)

Gerek dialog ve gerekse popover tanımları ile tanımlanan bu elemanlar en üst seviye z-index’e sahip oluyor ve <html> elemanına kardeş seviyede konumlanıyor. Doküman içindeki z-index değerleri ile bu elemanın üzerine çıkamıyoruz. Bir nevi kendine has bir alan oluşturmuş oluyoruz. Üst katman içindeki elemanlar ise aralarındaki sıralamaya göre görünürler.

google chrome top layer görünümü

Üst katmanlar tarayıcı kontrolünde olduğu için geliştiriciler olarak bizim bir elemanı oraya taşıma veya çıkarma imkanımız yok.(Umarım ilerde bu yönde bir değişiklik olur.) Bir elemanı üst katmana koymak için <dialog>, popover veya Fullscrean özelliğinden biri olarak tanımlamak gerekiyor.

dialog & popover farkları

Daha önce bahsettiğim <dialog> elementi ile popover’un ne farkı var diye bir soru geliyor ilk başta.

<dialog>elementi sayfadaki diğer içerik ile bağın koparıldığı ve backdrop ile belki de diğer içeriğin üzerinin kapatıldığı yapılar için kullanılır. Kullanıcının tüm odağı açılan diyalog içeriğine yönlendirilir ve sayfadaki diğer ögelerin kullanılmasına izin verilmez. Örneğin Son kararınız gibi onay isteyen yapılar, Doldurulmadan geçilmesi istenmeyen form alanları gibi.

<dialog popover>ise açılan alanın önceliği olsa da kullanıcının diğer içeriklerden uzak kalması ve kopması istenmeyen durumlarda kullanılır.

Popover API kullanımı

Popover API’ın kullanımı çok basittir.

<button
	popovertarget="fazla-bilgi"
	popovertargetaction="toggle">
		Bilgi ver
</button>

<div id="fazla-bilgi" popover>
	<p>Daha fazla bilgi verilir.<p>
</div>

popover olacak elemana bir id (my-popover) verilir ve popover özniteliği eklenir. Açacak olan butona hedef olarak bu id verilir. popovertarget="my-popover"

  • popover: özniteliği tanımlandığı elemanı bir popover elemanı haline getirir.
    • auto: (başlangıç değeri) popover elemanı dışına tıklandığında veya esc tuşuna basıldığında kapanır.
    • manuel: Bu tanım yapıldığında dışa tıklandığında ve esc’e basıldığında yapılacak kapama işlemlerini javascript ile bizim yapmamız gerekir.
  • popovertarget tanımlandığı<button> veya <input> elemanlarını popover kontrol elemanı haline dönüştürür. Kontrol edilecek popover’un id’sini değer olarak alır.
  • popovertargetaction <button> veya <input> gibi kontrol elemanlarının popover üzerindeki aksiyonlarının nasıl olacağını belirler.
    • toggle: (başlangıç değeri) Popover’ın açıksa kapatmak, kapalı ise açmaya yarayan aksiyondur.
    • show: Popover elemanını açar
    • hide: Popover elemanını kapatır

Bunların dışında popover elemanını stillendirmek için bir adet sözde sınıf bir adet sözde element vardır.

  • ::backdrop - <dialog>elementinde bildiğimiz bir sözde element. Popover’ın arakasında tam ekran açılan bir elemandır. Bu tanım bize animasyon ve stillendirme yapma imkanı sağlıyor.
  • :popover-open sözde sınıfı popover elementinin görünür olduğu durumu yakalamak için kullanılır. Bu tanım ile popover elemanının açık olduğundaki stillendirmeyi yaparız.

Bunların dışında popover elemanını javascript kontrol ve metodları da vardır.

  • PopoverElement.hidePopover() - Popover elemanını gizler. Aslında bu bir display:none tanımlamak gibidir.
  • PopoverElement.showPopover() - Popover elemanını görünür hale getirir.
  • PopoverElement.togglePopover() - Popover elemanını görünür ise gizler gizli ise görünür hale getirir.

Bunların dışında 2 adet de event vardır.

  • beforetoggle - Popover elemanının gizle/göster değişiminden önceki tetiklenen event’tır.
  • toggle - Popover elemanının gizle/göster değişiminden sonra tetiklenen event’tır.

Erişebilirlik

Bu tip API bileşenlerinin en güzel yanı bir çok projede unutulan erişilebilirlik durumları bu bileşenlerle birlikte hazır gelmesidir. Yaptığımız bir çok projede erişebilirlik süreçleri genelde olmaz veya yönetilmez.

Sayfadaki diğer ögelerin önemi gözetilmeksizin popover açılan alanların odakları her daim ilk sıradadır. Kullanıcı odakları bu alana çekilir.

Açılan alanlar herhangibir javascript gereksinimi olmadan ESC tuşuna basınca kapanır.

Tarayıcı desteği

Daha yeni yeni desteği geliyor. Şu an Chrome’da (114) aktif Safari 17 ile birlikte desteği geliyor. Firefox ise henüz flag ile destekliyor.

Tarayıcı Desteği

Chrome explorer Firefox
+ - -

Mobil Tarayıcılar

Chrome Mobil Safari Samsung Internet
+ - -

Sonuç

Bu tip API elementlerinin gelmesi güzel oluyor. Tabi hala tarayıcı desteği eksik ve gelişmesi gereken yönleri var. Örneği açarken ve kapatırken animasyon tanımları yapamıyoruz. Chrome ekibi bu yönde çalışmaları (@starting-style) var.

Ayrıca Murat Çorlu’nun verdiği bilgilere göre popover elemanlarının görünür alanda kalmasını sağlayacak @position-fallback diye bir özelliğinde geleceğinden bahsetti. Umarım bir an önce gelir ve desteği artar. Bu konu aslında Anchor positioning konusunun bir parçası. Umarım en kısı sürede tarayıcı desteği artar ve kullanmaya başlarız.

Kalın sağlıcakla.

Kaynaklar

CSS mantıksal tanımları(Logical Properties) Arapça, Çince, İbranice vb. diller için kodlama yaparken büyük avantaj sağlıyor. Bu konuda Ahmad Shadeed’in güzel biz yazısı (Digging Into CSS Logical Properties) var. Detayları bu yazıdan öğrenebilirsiniz.

Burada size bu özellikleri farklı bir amaç için kullanımını anlatacağım. Genelde dikeyde veya yatayda bir tanım yapacaksak özelliklerin dörtlü kısaltmalarını kullanırız. Sadece yatay veya sadece dikey tanımlama yapamıyorduk. İşte burada yardımımıza koşuyor mantıksal tanımlar. Örneğin klasik ortalama yöntemi margin: 0 auto aslında amaç sadece yatayda auto tanımı yapmak ama bunu yapamıyorduk.

.kapsul {
    width: 800px;
    margin: 0 auto;
}

Evet şimdi bu kodu sadece şöyle yazabiliyoruz.

.kapsul {
    width: 800px;
    margin-inline: auto;
}

Süper değil mi?

Benzer şekilde padding, margin, border tanımlarında aynı şeyi yapabiliyoruz.

Örneğin bir elemanın sadece dikey kenarlarına kenarlık tanımlamak için

.liste-ogesi {
    border-top: 1px solid blue;
    border-bottom: 1px solid blue;
}

gibi iki tanım yazmamız gerekirken

.liste-ogesi {
    border-block: 1px solid blue;
}

şeklinde bu işi tek satırda yapabiliyoruz.

Dikey için block yatay için ìnline eklemesi yeterli.

CSS ile resim, video ve iframe yapılarını uyumlu web gereği genişlik/yükseklik oranına (aspect ratio) göre küçültmek veya büyültmek için farklı bir yöntem kullanıyorduk. Artık aspect-ratio tanımı ile alternatif çözüme gerek kalmadı. Ayrıca bu tanım ile Chrome ekibinin performans kriterlerinden Cumulative Layout Shift (CLS): sorununu da çözebiliyoruz.

Şimdi özelliğin bize kazandırdıklarına bir göz atalım.

Eski çözüm yolları

Uyumlu(responsive) web hayatımıza girdiğinden beri bazı sorunlarla karşılaşıyoruz. Bunlardan en önemlisi galiba kullandığımız resimlerin boyutlarının istediğimiz oranda küçülmesi olabilir. Bu sorunu aşmak için çeşitli yöntemlerimiz vardı.

Bunlardan birisi resimlere width: 100%; verip yüksekliğinide height: auto; tanımlayıp esnek bir resim el etmekti.

Ancak bu yöntem ardalan resimlerinde işe yaramıyordu.

Mavi kutunun sağ alt kısmındaki boyutlandırma ikonundan büyültüp küçülterek sonucu görebilirsiniz.

Bir diğer yöntem de yüzde padding-top değeri kullanımıdır.

  • 1:1 aspect ratio = 1 / 1 = 1 = padding-top: 100%
  • 4:3 aspect ratio = 3 / 4 = 0.75 = padding-top: 75%
  • 3:2 aspect ratio = 2 / 3 = 0.66666 = padding-top: 66.67%
  • 16:9 aspect ratio = 9 / 16 = 0.5625 = padding-top: 56.25%

Yukarıdaki gibi bir hesaplama ile resimlerin belli bir boy/en oranıyla küçülmesini sağlayabiliyorduk.

aspect-ratio tanımı

Tabi sonra bu işi kökten çözen aspect-ratio özelliği çıktı ve bir satır CSS kodu ile çözüm oluşturdu.

Aynı örneği aspect-ratio ile yaparsak.

Bu tanımı sadece resim, video ve iframe’de değil normal bir etikete de uygulayabiliriz. Örneğin üç kolonlu bir içeriğin div‘lerine uygulayabiliriz.

Tabi içerik eğer en/boy oranını bozacak şekilde uzunsa oran bozuluyor. Ancak normal şartlarda en/boy oranını koruyor.

aspect-ratio medya sorguları

aspect-ratio medya sorgularında da kullanılabiliyor.

@media (aspect-ratio: 1/1) {
  body {
    background: lightblue;
  }
}

gibi sadece o orana göre kod yazıldığı gibi min-aspect-ratio ve max-aspect-ratio gibi daha geniş yelpazeye göre de medya sorgusu ekleyebiliyoruz.

performansa aspect-ratio’lu çözüm

Yazının başında da belirttiğimiz gibi aspect-ratio tanımı CLS çözümü olarakta kullanılabilmektedir. Aşağıda görüldüğü gibi resmin sonradan yüklenmesiyle layout zıplaması oluyor.

aspect-ration CLS çözümü

Cumulative Layout Shift (CLS): Tarayıcı ek veriler yüklendikçe sayfada meydana gelen zıplamayı (shift) ölçer.

Bu sorunu aşmak için resimlerimize aspect-ratio tanımlamamız yeterli. Performans açısından süper bir kolaylık.

Tarayıcı desteği konusunda da gayet iyi bir durumda.

Kalın sağlıcakla.

Kaynaklar