Tailwind ile klasik bir sayfa iskeleti, yani üstte yapışkan bir header, solda bir sidebar, ortada içerik ve en altta footer, yaklaşık on sınıfla kurulur. Header için sticky top-0 z-40, sayfa gövdesi için flex min-h-screen flex-col, içerik bölgesi için flex-1 ve sidebar ile içeriği yan yana dizmek için md:grid-cols-[16rem_1fr] yeterlidir. Mobilde sidebar hidden md:block ile gizlenir, içerik tek sütuna düşer ve footer, içerik kısa olsa bile ekranın altına itilir.

Bu yazıda bu iskeleti parça parça kuruyor, v4.3.5 ile derlenen CSS'i gösteriyor ve her sınıfın neden orada olduğunu açıklıyoruz. Flexbox ve grid'in kendisini CSS Flexbox ve CSS Grid yazılarında, Tailwind sınıflarını ise flexbox sınıfları ve grid sınıfları yazılarında anlattık. Serinin tamamı Tailwind CSS öğrenme rehberi sayfasında.

İskeletin tamamı

İskeletin tamamı

Önce bütün resmi görelim. Aşağıdaki HTML, mobilde tek sütun, md (48rem) ve üstünde iki sütunlu bir sayfa kurar:

html
<body class="flex min-h-screen flex-col">
  <header class="sticky top-0 z-40 border-b border-gray-200 bg-white/80 backdrop-blur-sm">
    <div class="mx-auto flex h-16 max-w-6xl items-center justify-between px-4">Logo</div>
  </header>
  <div class="mx-auto grid w-full max-w-6xl flex-1 gap-6 px-4 py-8 md:grid-cols-[16rem_1fr]">
    <aside class="hidden md:block">Menü</aside>
    <main class="min-w-0">İçerik</main>
  </div>
  <footer class="border-t border-gray-200 py-6">Alt bilgi</footer>
</body>

v4.3.5 ile derlenen CSS'in utilities katmanı (yalnızca bu bölümdeki sınıflar; backdrop-blur-sm kuralı aşağıda ayrıca ele alındığı için kısaltıldı):

css
@layer utilities {
  .sticky {
    position: sticky;
  }
  .top-0 {
    top: 0px;
  }
  .z-40 {
    z-index: 40;
  }
  .mx-auto {
    margin-inline: auto;
  }
  .flex {
    display: flex;
  }
  .grid {
    display: grid;
  }
  .hidden {
    display: none;
  }
  .h-16 {
    height: calc(var(--spacing) * 16);
  }
  .min-h-screen {
    min-height: 100vh;
  }
  .w-full {
    width: 100%;
  }
  .max-w-6xl {
    max-width: var(--container-6xl);
  }
  .min-w-0 {
    min-width: 0px;
  }
  .flex-1 {
    flex: 1;
  }
  .flex-col {
    flex-direction: column;
  }
  .items-center {
    align-items: center;
  }
  .justify-between {
    justify-content: space-between;
  }
  .gap-6 {
    gap: calc(var(--spacing) * 6);
  }
  .border-t {
    border-top-style: var(--tw-border-style);
    border-top-width: 1px;
  }
  .border-b {
    border-bottom-style: var(--tw-border-style);
    border-bottom-width: 1px;
  }
  .border-gray-200 {
    border-color: var(--color-gray-200);
  }
  .bg-white\/80 {
    background-color: color-mix(in srgb, #fff 80%, transparent);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--color-white) 80%, transparent);
    }
  }
  .px-4 {
    padding-inline: calc(var(--spacing) * 4);
  }
  .py-6 {
    padding-block: calc(var(--spacing) * 6);
  }
  .py-8 {
    padding-block: calc(var(--spacing) * 8);
  }
  /* (kısaltıldı) */
  @media (width >= 48rem) {
    .md\:block {
      display: block;
    }
    .md\:grid-cols-\[16rem_1fr\] {
      grid-template-columns: 16rem 1fr;
    }
  }
}

Tema bloğunda --container-6xl: 72rem tanımlı; 16px kök yazı boyutunda bu 1152px eder. Şimdi iskeleti bölge bölge açalım.

Yapışkan header

Header'da sticky top-0 birlikte kullanılır. Belgelere göre sticky bir element, belirlenen eşiği geçene kadar relative gibi davranır, sonra üst elementi ekrandan çıkana kadar fixed gibi kalır. Eşiği top-0 verir; top değeri olmadan yapışma gerçekleşmez. Header body elementinin doğrudan çocuğu olduğu için sayfa boyunca yapışık kalır.

z-40, kayan içerikteki konumlandırılmış elementlerin header'ın üstüne çıkmasını engeller. bg-white/80 yüzde 80 opak beyaz bir zemin, backdrop-blur-sm ise arkadan geçen içeriği bulanıklaştırır. Bu ikili skill'deki yapışkan header kalıbından geliyor. Bulanıklık kuralı uzun bir değişken zinciri üretir:

css
  .backdrop-blur-sm {
    --tw-backdrop-blur: blur(var(--blur-sm));
    -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
    backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
  }

Tema bloğunda --blur-sm: 8px değeri var. Diğer backdrop filtreleri boş bırakıldığı için yalnızca bulanıklık uygulanır; bu filtre ailesi blur ve backdrop-blur yazısında. Header'ın içindeki mx-auto flex h-16 max-w-6xl items-center justify-between px-4 satırı da içerikle aynı genişlikte ortalanmış bir şerit kurar: logo solda, menü sağda, ikisi de dikeyde ortada.

Kayarken yerinde duran sidebar

Uzun bir içerik sayfasında sidebar menüsünün görünür kalmasını istiyorsanız onu da yapışkan yapabilirsiniz. Ancak grid içinde ögeler varsayılan olarak satır yüksekliği boyunca uzar; uzayan bir öge yapışamaz, çünkü kayacak yeri kalmaz. Bu yüzden sidebar'a self-start verilir:

html
<aside class="hidden md:block md:sticky md:top-20 md:self-start">Menü</aside>
css
  @media (width >= 48rem) {
    .md\:sticky {
      position: sticky;
    }
    .md\:top-20 {
      top: calc(var(--spacing) * 20);
    }
    .md\:block {
      display: block;
    }
    /* (kısaltıldı) */
    .md\:self-start {
      align-self: flex-start;
    }
  }

md:top-20 5rem, yani 16px kökte 80px verir; bu değer 4rem (h-16) yüksekliğindeki header'ın altında küçük bir boşluk bırakmak için seçildi. self-start, bu derlemede align-self: flex-start üretti. Mobilde sidebar zaten gizli olduğu için tüm bu sınıfları md: ile sınırladık.

Katman sırası: z-index nereye gerekir?

Sayfa iskeletinde z-* sınıflarına yalnızca birkaç yerde ihtiyaç vardır ve bunları rastgele büyük sayılarla doldurmak ileride çözülmesi zor sorunlara yol açar. Bu iskelette yalnızca header'a z-40 verdik, çünkü kayan içerikteki konumlandırılmış elementler (örneğin relative bir kartın içindeki absolute bir rozet) header'ın altından geçmelidir. Sidebar yapışkan olsa bile header ile aynı alanı paylaşmadığı için ayrı bir z-index gerektirmez: md:top-20 sayesinde header'ın altında durur.

Daha karmaşık arayüzlerde açılır menüler, bildirimler ve modal pencereler de devreye girer. Bunlar için küçük bir ölçek belirleyip her katmana bir değer ayırmak iyi bir alışkanlıktır: içerik için hiçbir değer, yapışkan header için z-40, header'dan çıkan açılır menüler ve modal pencereler için daha yüksek bir değer. Skill'de z-0'dan z-50'ye kadar onar adımlı bir ölçek ve z-auto ile negatif -z-10 listelenir; skill'deki yapışkan header kalıbı ise z-50 kullanır. Önemli olan değerin kendisi değil, projenin her yerinde aynı ölçeğe uymaktır. Konumlandırma ve yığın sırası position ve z-index yazısında ayrıntılı.

İskeleti dar ve geniş ekranda okumak

Responsive bir iskeleti doğru kurup kurmadığınızı anlamanın iyi bir yolu, sınıf listesini önce varsayılan (mobil) durum için, sonra her breakpoint için ayrı ayrı okumaktır. 48rem'den dar bir ekranda md: ile başlayan bütün sınıfları yok sayın: geriye dikey bir flex body, yapışkan header, tek sütunlu bir grid içinde yalnızca main (çünkü aside hidden) ve footer kalır. 48rem ve üstünde ise @media (width >= 48rem) bloğundaki iki kural devreye girer: sidebar display: block olur ve grid iki sütuna bölünür.

Bu okuma, hatalı varsayımları da hızla ortaya çıkarır. Örneğin sidebar'ı mobilde göstermek isteseydiniz hidden sınıfını kaldırmanız yeterdi; grid tek sütun olduğu için sidebar içeriğin üstünde yer alırdı. Sidebar'ın mobilde içeriğin altına düşmesini istiyorsanız HTML sırasını değiştirmeden order-* sınıflarıyla yer değiştirebilirsiniz; bu sınıflar flex-1, grow, shrink ve order yazısında. Ancak görsel sıra ile HTML sırası birbirinden ne kadar uzaklaşırsa klavye ile gezinme o kadar şaşırtıcı hâle gelir; bu yüzden mümkün olduğunda HTML'i görsel sıraya göre yazın.

Genişlik sınırı: max-w-6xl mi, container mı?

Genişlik sınırı: max-w-6xl mi, container mı? body, header, orta bölge, aside

Bu iskelette içeriği mx-auto max-w-6xl px-4 ile sınırladık: en fazla 72rem genişlik, yatayda ortalama ve kenarlarda 1rem iç boşluk. Skill'deki ortak kalıp ise container mx-auto px-4 şeklinde. container sınıfı her breakpoint'te farklı bir max-width verir ve v4'te kendiliğinden ortalanmaz, bu yüzden mx-auto ile birlikte kullanılır. Hangisini seçeceğiniz, genişliğin breakpoint'lerle adım adım mı yoksa tek bir üst sınırla mı büyümesini istediğinize bağlıdır; karşılaştırma container sınıfı yazısında.

BölgeSınıflarGörevi
bodyflex min-h-screen flex-colDikey düzen, en az ekran yüksekliği
headersticky top-0 z-40 border-b bg-white/80 backdrop-blur-smYapışkan, yarı saydam üst şerit
orta bölgemx-auto grid w-full max-w-6xl flex-1 gap-6 px-4 py-8 md:grid-cols-[16rem_1fr]Esneyen alan ve iki sütun
asidehidden md:blockMobilde gizli menü
mainmin-w-0Taşmayı önleyen içerik sütunu
footerborder-t border-gray-200 py-6Alt bilgi, flex-1 sayesinde en altta

Sık yapılan hatalar

  • top değeri olmadan sticky: sticky tek başına yapışmaz; top-0 gibi bir eşik gerekir.
  • Footer'ı alta itmek için fixed kullanmak: fixed bottom-0 footer'ı içeriğin üstüne bindirir; flex-1 yaklaşımı akışı bozmaz.
  • min-h-screen yerine h-screen: h-screen yüksekliği sabitler, içerik uzadığında taşar.
  • Grid içinde uzayan sticky sidebar: self-start olmadan sidebar yapışmaz.
  • İçerik sütununda min-w-0 unutmak: Uzun kod blokları veya tablolar sayfayı yatayda kaydırır.
  • Mobil önce düşünmemek: İki sütunlu düzeni temel sınıf, tek sütunu max-md: ile yazmak yerine tek sütunu varsayılan, iki sütunu md: ile yazın; bkz. responsive tasarım.

Sık Sorulan Sorular

Header içeriğin üstüne biniyor, ne yapmalıyım?

sticky elementler akışta yer kaplamaya devam eder; bu yüzden binme genellikle fixed kullanıldığında olur. fixed kullanmak zorundaysanız içeriğe header yüksekliği kadar üst boşluk (örneğin pt-16) verin. Konumlandırma türleri position ve inset yazısında.

Sidebar'ı mobilde açılır menü yapabilir miyim?

Evet, ama açma kapama davranışı JavaScript veya details gibi bir HTML elementi gerektirir. Tailwind tarafında yapmanız gereken, menünün görünürlüğünü bir sınıf veya nitelikle değiştirmek ve aria-expanded gibi durumları aria varyantları ile stillemektir.

Üç sütunlu (sidebar, içerik, sağ panel) düzen nasıl kurulur?

Skill'deki grid-cols-[200px_1fr_200px] kalıbı bunu yapar. Mobilde tek sütun için bu sınıfı lg: gibi bir breakpoint ile sınırlamanız yeterlidir.

Bu iskeleti her sayfada yeniden mi yazmalıyım?

Hayır. Header, sidebar ve footer gibi her sayfada tekrar eden bölümler, Tailwind belgelerinin tekrar konusunda önerdiği gibi bir şablon parçasına ya da bileşene taşınmalıdır. Kullandığınız şablon dili (Blade, Twig, Nunjucks) veya framework (React, Vue, Svelte) bir düzen (layout) bileşeni kurmanıza izin verir; iskeletin sınıfları orada bir kez yazılır, sayfalar yalnızca ortadaki içeriği doldurur. Böylece max-w-6xl gibi bir değeri değiştirmek istediğinizde tek bir dosyayı düzenlemeniz yeter ve header ile içerik genişliği birbirinden kopmaz.

İçeriği yatay ve dikey ortalamak için ne kullanmalıyım?

Tek bir kutuyu ekranın ortasına almak için flex min-h-screen items-center justify-center en kısa yoldur. Diğer tarifler div ortalama yazısında.

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: Tailwind CSS öğrenme rehberi · Flexbox sınıfları · Grid sınıfları · Container ve max-width · Position ve inset · Kart, buton ve input örnekleri · Mobil uyumluluk nedir