CSS anchor positioning (çapa konumlandırma), bir öğeyi sayfadaki başka bir öğeye bağlamanızı sağlar. Bağlanılan öğeye çapa öğesi (anchor element), ona göre konumlanan öğeye çapaya bağlı öğe (anchor-positioned element) denir. Çapaya anchor-name ile bir ad verir, konumlanacak öğeye position: absolute ya da fixed ile position-anchor atar, ardından konumu anchor() fonksiyonu veya position-area özelliğiyle belirlersiniz. İpucu kutuları, açılır menüler ve form alanının yanında çıkan hata mesajları bu yöntemle JavaScript yazmadan konumlanabilir.

MDN'in anlatımına göre bu tür bağlamalar eskiden JavaScript gerektiriyordu; bu da karmaşıklık ve performans sorunları getiriyordu. Bu yazıda ilişkilendirme, konumlandırma ve boyutlandırma özelliklerini, öğe ekran dışına taştığında devreye giren yedek konumları ve koşullu gizlemeyi sırasıyla ele alıyoruz. Klasik konumlandırmayı henüz bilmiyorsanız önce position: relative, absolute, fixed, sticky yazısını okumanızı öneririz.

Temel kavram: ilişki, konum ve yer

Temel kavram: ilişki, konum ve yer: Çapayı adlandırmak, Konumlandırmak, İlişki kurmak, Yerini belirlemek

MDN, bir öğeyi çapaya göre yerleştirmek için üç şey gerektiğini söyler: bir ilişki (hangi çapaya bağlı olduğu), bir konumlandırma (mutlak ya da sabit konum) ve bir yer (çapanın hangi tarafında duracağı). Yalnızca ilişki kurmak öğeyi çapaya yapıştırmaz; çapayı hareket ettirdiğinizde bağlı öğe yerinde kalır. Gerçek bağlama, konumu anchor(), position-area ya da anchor-center ile çapaya göre tanımladığınızda gerçekleşir.

AdımÖzellikNereye yazılır
Çapayı adlandırmakanchor-nameÇapa öğesi
Konumlandırmakposition: absolute veya fixedBağlı öğe
İlişki kurmakposition-anchorBağlı öğe
Yerini belirlemekanchor(), position-area veya anchor-centerBağlı öğe

Adım 1 ve 2: anchor-name ve position-anchor

anchor-name bir öğeyi çapa yapar. Değeri iki tire ile başlayan bir <dashed-ident> olmalıdır, örneğin --ipucu-capasi. Varsayılan değer none'dır ve öğenin çapa olmadığı anlamına gelir. Bir öğeye virgülle ayrılmış birden fazla ad da verebilirsiniz. position-anchor ise konumlanmış öğenin varsayılan çapasını belirler; position-area, position-try ve ad verilmeden çağrılan anchor() ile anchor-size() bu varsayılan çapayı kullanır.

css
.capa {
  anchor-name: --my-anchor;
  width: fit-content;
}

.infobox {
  position: fixed;
  position-anchor: --my-anchor;
}
/* sonuç: iki öğe ilişkilendirildi ama henüz birbirine
   yapıştırılmadı; konum ayrıca belirtilmeli */
html
<div class="capa">Çapa</div>
<div class="infobox"><p>Bilgi kutusu</p></div>

position-anchor şu değerleri alır: normal (position-area değeri none ise none gibi, değilse auto gibi davranır), auto (varsa örtük çapayla ilişkilendirir), none (ilişki kurmaz), bir <dashed-ident> ve match-parent (üst öğenin varsayılan çapasını kullanır). Bu özellik yalnızca position değeri absolute veya fixed olan öğelerde anlamlıdır.

Popover API ile bir düğmeye bağlanan popover'larda ve özelleştirilebilir <select> öğesinin açılır listesinde, iki öğe arasında örtük bir çapa ilişkisi kendiliğinden oluşur. Bu ilişkiyi CSS ile kaldırmak istediğinizde anchor-name ile değil, bağlı öğede position-anchor: none yazarak yapabilirsiniz; çünkü örtük ilişki tarayıcı tarafından içeride yönetilir.

Adım 3a: inset özelliklerinde anchor() fonksiyonu

anchor() fonksiyonu yalnızca mutlak ya da sabit konumlanmış öğelerin inset özelliklerinde (top, left, bottom, right, inset ve mantıksal karşılıkları) geçerlidir ve bir <length> döndürür. Sözdizimi anchor(<anchor-name> <anchor-side>, <length-percentage>) biçimindedir. Ad yazılmazsa varsayılan çapa kullanılır; ikinci parametre çapanın hangi kenarının referans alınacağını, üçüncü parametre ise fonksiyon geçersiz kalırsa kullanılacak yedek değeri belirtir.

css
.infobox {
  position: fixed;
  position-anchor: --my-anchor;
  inset-block-start: anchor(end);
  inset-inline-start: anchor(self-end);
  margin: 5px 0 0 5px;
}
/* sonuç: kutunun üst kenarı çapanın alt kenarına,
   sol kenarı çapanın sağ kenarına hizalanır; margin ile
   5px aşağı ve 5px sağa kayar. Sayfa kaydırılınca kutu
   görünüm alanına değil çapaya bağlı kalır */

<anchor-side> değerleri fiziksel (top, right, bottom, left), göreli (inside, outside), mantıksal (start, end, self-start, self-end), center ya da bir yüzde olabilir. Burada önemli bir kural vardır: kenar değeri, üzerine yazıldığı inset özelliğinin ekseniyle uyumlu olmalıdır. top: anchor(bottom) geçerlidir, çünkü ikisi de dikey eksendedir. top: anchor(left) ise uyumsuzdur; bu durumda yedek değer kullanılır, yedek de yoksa özellik auto gibi davranır. center ve yüzde değerleri bütün inset özelliklerinde geçerlidir.

css
.a { top: anchor(left, 50px); }
/* left yatay, top dikey: uyumsuz. top hesaplanan değeri 50px olur */

.b { inset-block-end: calc(anchor(start) + 10px); }
/* anchor() bir uzunluk döndürdüğü için calc() içinde kullanılabilir */

Adım 3b: position-area ile 3x3 ızgara

Adım 3b: position-area ile 3x3 ızgara

position-area, anchor() yerine daha kısa bir yol sunar. Çapanın ortadaki hücre olduğu 3x3'lük bir ızgara düşünün; bağlı öğeyi bu dokuz hücreden birine koyabilir ya da iki veya üç hücreye yayabilirsiniz. Satırlar top, center, bottom; sütunlar left, center, right ile adlandırılır. Bunların mantıksal (start, end) ve koordinat (x-start, y-end gibi) karşılıkları da vardır.

css
.ipucu {
  position: absolute;
  position-anchor: --dugme;
  position-area: top;
}
/* sonuç: ipucu çapanın üstündeki satıra yerleşir;
   tek fiziksel değer "top span-all" ile aynı etkiyi verir */

Tek değer yazıldığında davranış değere göre değişir: fiziksel bir kenar (top, left gibi) ya da koordinat değeri diğer değeri span-all sayar; mantıksal start veya end diğer değeri kendisiyle aynı sayar (start, start start demektir); center ise center center anlamına gelir. İki değer yazdığınızda belirli bir hücre seçersiniz: top left sol üst köşeyi, bottom center alt orta hücreyi seçer. span-left gibi değerlerle de öğeyi bir satırda birden fazla hücreye yayarsınız.

Boyut konusunda da bir ayrıntı var: açık bir genişlik vermediğinizde position-area ile yerleştirilen öğe, max-content genişliğindeymiş gibi içeriğine göre boyutlanır. bottom center gibi ortalanmış yerleşimlerde ise genişliği çapanın genişliğiyle aynı olur.

Çapaya göre ortalama: anchor-center

Inset özellikleriyle bağladığınız bir öğeyi çapanın ortasına hizalamak için justify-self, align-self ve kısaltmaları anchor-center değerini kabul eder. Bu değer öğeyi varsayılan çapasının merkezine hizalar.

css
.infobox {
  position: fixed;
  position-anchor: --my-anchor;
  top: calc(anchor(bottom) + 5px);
  justify-self: anchor-center;
}
/* sonuç: kutu çapanın 5px altına yerleşir ve
   yatayda çapanın ortasına hizalanır */

Çapaya göre boyutlandırma: anchor-size()

anchor-size(), çapanın genişliğini ya da yüksekliğini bir uzunluk olarak döndürür. width, height, min-width, max-height, inline-size gibi boyut özelliklerinde, ayrıca inset ve margin özelliklerinde kullanılabilir. Boyut değeri width, height ya da mantıksal inline, block, self-inline, self-block olabilir.

css
.infobox {
  position: fixed;
  position-anchor: --my-anchor;
  position-area: right;
  margin-left: 5px;
  width: calc(anchor-size(width) * 5);
}
/* sonuç: kutu çapanın sağına yerleşir; genişliği çapa
   genişliğinin 5 katıdır. Çapanın genişliği 30px ise
   30 x 5 = 150px, 50px'e büyürse 50 x 5 = 250px olur */

MDN'in örneğinde çapanın genişliği :hover ve :focus durumunda bir geçişle büyütülür; bağlı kutu da çapayla birlikte genişler. Bu, boyutun bir kez hesaplanıp sabitlenmediğini, çapanın o anki boyutunu izlediğini gösterir.

Mini örnek: düğmenin altında ortalanmış ipucu

Şimdi parçaları birleştirelim. Bir düğmenin altında, düğmeye ortalanmış bir ipucu göstermek; ipucu ekranın altından taşarsa onu düğmenin üstüne çevirmek istiyoruz:

html
<button class="yardim">Yardım</button>
<div class="ipucu">Bu düğme yardım sayfasını açar.</div>
css
.yardim {
  anchor-name: --yardim;
}

.ipucu {
  position: absolute;
  position-anchor: --yardim;
  position-area: bottom;
  margin-top: 6px;
  position-try-fallbacks: flip-block;
}
/* sonuç: bottom, bottom span-all ile aynıdır; ipucu alt satırın
   ortasına yerleşir ve üç hücreye yayılabilir.
   Altta yer kalmazsa flip-block ile düğmenin üstüne geçer */

MDN, flip-block davranışını şöyle örnekler: çapanın 10px üstünde duran bir öğe üstten taşmaya başlarsa bu seçenekle çapanın 10px altına geçer. Yani çevirme, öğeyi çapanın karşı tarafına aynalar; ipucunun düğmeye göre yönü değişir ama bağlantısı kopmaz. Ok işareti gibi yöne bağlı süslemeleri de değiştirmek isterseniz MDN, hangi yedeğin etkin olduğunu algılayan anchored container query özelliğini anlatır.

Ekrana sığmayınca: yedek konumlar

İpucu çapanın üstüne yerleştirildiyse ve kullanıcı sayfayı çapa görünüm alanının tepesine gelecek şekilde kaydırırsa ipucu ekrandan taşar. position-try-fallbacks özelliği, tarayıcının bu durumda deneyeceği alternatif konumları sıralar. Hazır seçenekler (<try-tactic>) öğeyi eksenler boyunca yansıtır: flip-block blok ekseninde (üst ve alt), flip-inline satır ekseninde (sol ve sağ), flip-start ise çapanın köşegeni boyunca çevirir.

css
.infobox {
  position: fixed;
  position-anchor: --my-anchor;
  position-area: top left;
  position-try-fallbacks:
    flip-block,
    flip-inline,
    flip-block flip-inline;
}
/* sonuç: önce yalnızca dikey çevirme, sonra yalnızca yatay
   çevirme, ikisi de sığmazsa aynı anda iki yönde çevirme denenir */

Virgülle ayrılan seçenekler yazıldıkları sırayla denenir. Boşlukla ayrılan değerler ise tek bir birleşik seçenek oluşturur. MDN'in örneğinde yalnızca flip-block, flip-inline yazıldığında, çapa sol üst köşeye yaklaştığında iki seçenek de tek başına yetmez; tarayıcı sığan bir seçenek bulamadığı için öğeyi ilk tanımlanan konumda gösterir ve öğe iki yönde birden taşar. Üçüncü, birleşik seçenek bu sorunu çözer.

Hazır seçenekler yetmediğinde @position-try ile kendi seçeneğinizi tanımlarsınız. Bu kuralın içinde yalnızca sınırlı bir tanımlayıcı listesi kullanılabilir: position-anchor, position-area, inset özellikleri, margin özellikleri, boyut özellikleri ve anchor-center için align-self ile justify-self. Seçenek uygulandığında bu değerler öğeye doğrudan yazılmış değerlerden önceliklidir.

css
@position-try --sol-ozel {
  position-area: left;
  width: 100px;
  margin-right: 10px;
}

.infobox {
  position: fixed;
  position-anchor: --my-anchor;
  position-area: top;
  width: 200px;
  margin-bottom: 10px;
  position-try-fallbacks: --sol-ozel, flip-block;
}
/* sonuç: taşma yoksa kutu üstte ve 200px genişliktedir;
   taşarsa önce sola geçip 100px genişliğe iner,
   olmazsa alta çevrilir */

position-try-order ise kaydırma sırasında değil, öğe ilk gösterildiğinde hangi seçeneğin seçileceğini etkiler. most-height, most-width, most-block-size ya da most-inline-size yazdığınızda tarayıcı yedekler arasından o yönde en çok alan bırakanı uygular; varsayılan normal değerinde ilk gösterimde hiçbir yedek denenmez. position-try kısaltması bu iki özelliği tek bildirimde yazmanızı sağlar.

Koşullu gizleme: position-visibility

Bazen öğeyi taşımak yerine gizlemek daha anlamlıdır; örneğin çapası ekrandan çıkmış bir ipucu artık neyi anlattığı belli olmayan bir kutuya dönüşür. position-visibility şu değerleri alır: always (her zaman gösterilir), anchors-valid (position-anchor geçerli bir çapayı göstermiyorsa gizler), anchors-visible (çapa tamamen gizlenmişse gizler) ve no-overflow (öğe kapsayıcısından veya görünüm alanından taşmaya başlarsa gizler). Bu şekilde gizlenen öğe ve torunları, kendi visibility değerlerinden bağımsız olarak hidden gibi davranır. MDN, çoğu durumda önce yedek konum denemenin daha kullanışlı olduğunu hatırlatır.

Tekrarlanan bileşenler: anchor-scope

Aynı anchor-name birden fazla öğede kullanılırsa, bağlı öğe kaynak sırasındaki son çapaya bağlanır. Sayfada tekrarlanan bir kart bileşeniniz varsa bütün ipuçları son kartın çapasına gider. anchor-scope bu sorunu çözer: bir kapsayıcıya anchor-scope: --my-anchor (ya da all) yazdığınızda, o alt ağaçta tanımlanan çapa adlarına yalnızca aynı alt ağaçtaki bağlı öğeler bağlanabilir. Varsayılan değer none'dır.

css
.anchor { anchor-name: --my-anchor; }

.positioned {
  position: absolute;
  position-anchor: --my-anchor;
  position-area: right;
}

.scoped { anchor-scope: --my-anchor; }
/* sonuç: her .scoped bölümündeki öğe kendi bölümündeki
   çapanın sağına yerleşir */

Sık yapılan hatalar

Sık yapılan hatalar: position değerini unutmak, Yalnızca ilişki kurup yer belirtmemek, Eksenleri karıştırmak, Gizli çapa
  • position değerini unutmak: position-anchor ve anchor() yalnızca absolute veya fixed konumlu öğelerde çalışır. anchor() başka bir yerde yedek değere düşer.
  • Yalnızca ilişki kurup yer belirtmemek: position-anchor tek başına öğeyi çapaya yapıştırmaz; anchor(), position-area veya anchor-center gerekir.
  • Eksenleri karıştırmak: left: anchor(top) gibi uyumsuz eşleşmeler yedek değere ya da auto davranışına düşer.
  • Gizli çapa: Çapa display: none veya visibility: hidden ile gizliyse ilişki kurulamaz.
  • Inset değerini doğrudan yazmak: bottom: 50px gibi düz bir uzunluk, öğeyi çapaya göre değil, olağan mutlak ya da sabit konumlandırma kurallarına göre yerleştirir; MDN'e göre bu, bottom: anchor(right, 50px) gibi uyumsuz bir yazımla aynı sonucu verir.
  • Popover varsayılanlarını sıfırlamamak: MDN, popover'ları anchor() ile konumlarken varsayılan margin ve inset değerlerinin çakışabileceğini, bunları margin: 0; inset: auto; ile sıfırlamanın önerildiğini belirtir.

Sık Sorulan Sorular

anchor() ile position-area arasında hangisini seçmeliyim?

position-area çapanın etrafındaki dokuz hücreden birine hızlıca yerleştirme yapar ve çoğu ipucu ile menü için yeterlidir. anchor() ise her kenarı ayrı ayrı ve calc() ile hassas biçimde ayarlamanızı sağlar; MDN de inset özellikleriyle birlikte daha fazla kontrol sunduğunu belirtir.

Bir öğe birden fazla çapaya bağlanabilir mi?

Farklı inset özelliklerinde farklı adlarla anchor() çağırarak öğenin kenarlarını farklı çapalara göre konumlayabilirsiniz. Ancak öğe yalnızca position-anchor ile belirtilen tek bir çapayla ilişkilidir; kaydırmada birlikte hareket ettiği çapa odur.

Sözde öğeler çapa olabilir mi?

Evet. MDN'e göre anchor-name ana kutu üreten bütün öğelerde desteklenir; ::before ve ::after ile oluşturulan içerik de çapa olabilir. Sözde öğeler hakkında daha fazlası için ::before ve ::after yazısına bakın.

Yedek konumlar hiçbiri sığmazsa ne olur?

Tarayıcı listedeki seçenekleri sırayla dener; hiçbiri öğeyi tamamen görünür alana sığdıramazsa öğe, hiçbir yedek uygulanmadan ilk tanımlanan konumunda gösterilir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: CSS öğrenme rehberi · position değerleri · z-index ve stacking context · @supports · Ortalama yöntemleri