Tailwind CSS, kaynak dosyalarınızı düz metin olarak tarar ve yalnızca orada tam haliyle geçen sınıflar için CSS üretir. Varsayılan olarak çalışma dizinindeki her dosyaya bakar; .gitignore içindeki yolları, node_modules klasörünü, ikili dosyaları, CSS dosyalarını ve paket yöneticisi kilit dosyalarını atlar. Bu davranışı CSS içinden yönetirsiniz: @source "yol" ek bir yolu taramaya katar, @source not "yol" bir yolu dışarıda bırakır, source("yol") taramanın başlangıç noktasını değiştirir, source(none) otomatik taramayı tamamen kapatır, @source inline("...") ise hiçbir dosyada geçmeyen sınıfları zorla üretir.

Bu yazıda her direktifi küçük klasör yapıları kurup Tailwind CSS v4.3.5 standalone CLI ile derleyerek sınadık. Ayrıca en sık karşılaşılan sorunu, yani parça parça birleştirilen sınıf adlarının neden üretilmediğini, gerçek çıktıyla gösteriyoruz. Sınıf adının yapısı için utility class mantığı yazısına, serinin geri kalanı için Tailwind CSS öğrenme rehberi sayfasına bakabilirsiniz.

Tarama nasıl çalışır: kod değil metin

Tarama nasıl çalışır: kod değil metin

Resmî sınıf tespiti sayfasının temel vurgusu şudur: Tailwind dosyalarınızı bir programlama dili olarak ayrıştırmaz, her dosyayı düz metin gibi okur. Sınıf adında bulunabilecek karakterlerden oluşan parçaları (token) toplar, her biri için CSS üretmeyi dener ve bilinen bir utility'ye karşılık gelmeyenleri atar. Bu yaklaşımın iki sonucu vardır. Birincisi, HTML, JSX, Vue, PHP, Markdown ya da düz JavaScript fark etmez; sınıf adı dosyada yazılıysa bulunur. İkincisi, derleyici kodu çalıştırmadığı için çalışma zamanında birleştirilen bir dizgeyi göremez.

Bu nedenle bir sınıf adının kaynakta tam haliyle geçmesi gerekir. Bir değişken, şablon dizgesi ya da koşul ifadesiyle parça parça oluşturulan adlar, derleyici için hiç var olmamış gibidir. Bu, Tailwind'de "sınıf yazdım ama çalışmıyor" sorununun en yaygın nedenidir ve aşağıda ayrı bir derlemeyle gösteriliyor.

Otomatik tespit ve .gitignore

Otomatik taramanın gerçekte neyi gördüğünü sınamak için bir git deposu kurduk. Kökte build/ satırını içeren bir .gitignore vardı ve üç klasörde birer HTML dosyası bulunuyordu:

bash
s1/
  .gitignore          (içerik: build/)
  src/giris.css       (içerik: @import "tailwindcss";)
  src/a.html          (<p class="p-4">)
  legacy/b.html       (<p class="m-3">)
  build/c.html        (<p class="text-center">)
bash
cd s1
tailwindcss -i src/giris.css -o cikti.css

v4.3.5 ile derlenen CSS'in utilities katmanı:

css
@layer utilities {
  .m-3 {
    margin: calc(var(--spacing) * 3);
  }
  .p-4 {
    padding: calc(var(--spacing) * 4);
  }
}

src ve legacy klasörlerindeki sınıflar üretildi, build klasöründeki text-center üretilmedi; çünkü o klasör .gitignore ile dışlanmıştı. Ayrıca taramanın CSS dosyasının bulunduğu src klasöründen değil, komutun çalıştırıldığı s1 klasöründen başladığına dikkat edin: legacy klasörü CSS dosyasının bir üst seviyesinde olduğu halde tarandı. Resmî belge de varsayılan başlangıç noktasının geçerli çalışma dizini olduğunu belirtir.

@source ile yol eklemek

Taranmayan bir klasörü ya da dosyayı açıkça kaydetmek için @source kullanılır. Yol, CSS dosyasının bulunduğu konuma göre çözülür. Belgenin verdiği tipik örnek, Tailwind ile yazılmış harici bir arayüz kütüphanesidir; bağımlılıklar genellikle node_modules içinde durduğu ve bu klasör otomatik taramanın dışında kaldığı için kütüphanenin sınıfları ancak böyle görünür hale gelir:

css
@import "tailwindcss";
@source "../node_modules/@acmecorp/ui-lib";

Aynı mekanizma .gitignore ile dışlanmış bir klasörü geri almak için de çalışır. Aynı depoda src/g2.css dosyasıyla hem build klasörünü ekledik hem de legacy klasörünü çıkardık:

css
@import "tailwindcss";
@source not "../legacy";
@source "../build";

v4.3.5 ile derlenen CSS:

css
@layer utilities {
  .p-4 {
    padding: calc(var(--spacing) * 4);
  }
  .text-center {
    text-align: center;
  }
}

Sonuç tam olarak beklenen tablodur: m-3 artık yok, text-center geri geldi. Her iki yol da CSS dosyasına göre yazıldığı için ../legacy ve ../build ifadeleri src klasörünün bir üstüne işaret eder.

@source not: büyük klasörleri dışarıda bırakmak

@source not: büyük klasörleri dışarıda bırakmak

@source not, Tailwind sınıfı içermeyen büyük klasörleri taramadan çıkarmak için tasarlanmıştır. Belge eski bileşenleri ve üçüncü taraf kodu örnek verir. Bu iki fayda sağlar: gereksiz dosyalar okunmadığı için tarama işi azalır ve o klasörlerdeki sınıfa benzeyen kelimeler yanlışlıkla CSS üretmez. Yukarıdaki denemede legacy klasörü çıkarılınca m-3 kuralı da çıktıdan kayboldu. Aynı sınıf başka bir taranan dosyada geçseydi yine üretilecekti; @source not bir sınıfı değil bir yolu dışlar.

source() ile başlangıç noktasını belirlemek

Derleme aracının hangi klasörden çalıştırıldığına bağlı kalmak istemiyorsanız, başlangıç noktasını @import satırında source() ile verebilirsiniz. Belge bunun özellikle derlemelerin monorepo kökünden çalıştırıldığı projelerde işe yaradığını belirtir. Denemede src/g3.css dosyasına şu satırı yazdık ve CLI'yi bilerek tamamen ilgisiz bir dizinden, diskin kökünden, dosya yollarını tam vererek çalıştırdık:

css
@import "tailwindcss" source("../src");
css
@layer utilities {
  .p-4 {
    padding: calc(var(--spacing) * 4);
  }
}

Yalnızca src/a.html içindeki p-4 üretildi. Çalışma dizini değişse bile tarama, stil dosyasına göre çözülen src klasörüyle sınırlı kaldı. Bu ayar sayesinde aynı CSS dosyası, derleme aracı hangi klasörden çalışırsa çalışsın aynı sonucu verir.

source(none): taramayı tamamen kapatmak

source(none) otomatik tespiti kapatır; bundan sonra yalnızca @source ile kaydettiğiniz yollar taranır. Belge bunu birden fazla stil dosyası olan projeler için önerir: örneğin yönetim paneli ile genel sitenin ayrı CSS dosyaları varsa, her biri yalnızca kendi şablonlarındaki sınıfları içerir.

css
@import "tailwindcss" source(none);
@source "../admin";
@source "../shared";

Bu serideki örneklerin neredeyse tamamı da aynı tekniği kullanır: source(none) ile tarama kapatılır ve yalnızca örnek HTML dosyası ya da bir @source inline() listesi kaydedilir. Böylece çıktıda başka hiçbir klasörden sınıf karışmaz ve gösterilen CSS kısa kalır.

@source inline(): safelist yerine

@source inline(): safelist yerine: Aralıklarla toplu üretim, @source not inline(): üretimi engellemek

Bazen bir sınıfın hiçbir kaynak dosyada geçmediği halde üretilmesi gerekir; örneğin sınıf adları bir veritabanından ya da içerik yönetim sisteminden geliyorsa. v4'te bunun yolu @source inline()'dır. Verdiğiniz dizge, sanki bir kaynak dosyada yazıyormuş gibi taranır. Dizge süslü parantez açılımını da destekler; bu sayede tek satırla çok sayıda sınıf ve varyant üretilebilir.

css
@import "tailwindcss" source(none);
@source inline("{hover:,focus:,}underline");

Süslü parantez içindeki üç seçenek (hover:, focus: ve boş dizge) sınıfın önüne tek tek eklenir. v4.3.5 ile derlenen CSS:

css
@layer utilities {
  .underline {
    text-decoration-line: underline;
  }
  @media (hover: hover) {
    .hover\:underline:hover {
      text-decoration-line: underline;
    }
  }
  .focus\:underline:focus {
    text-decoration-line: underline;
  }
}

Burada küçük bir ayrıntı var: resmî belgedeki örnek çıktıda focus kuralı da bir medya sorgusu içinde gösterilir, ancak v4.3.5'in gerçek çıktısında yalnızca hover kuralı @media (hover: hover) içine alındı; focus kuralı doğrudan yazıldı. Bu, bu yazıda neden her örneğin CLI ile derlendiğini gösteren iyi bir örnektir. Hover davranışının nedeni hover ve focus yazısında anlatılır.

Aralıklarla toplu üretim

Süslü parantez içinde {başlangıç..bitiş..adım} biçiminde sayı aralıkları da yazılabilir. Belgedeki örnek 100'den 900'e kadar 100'er adımla renk tonları üretir. Biz adımı 200 yaptık ve 50 ile 950 tonlarını ayrıca ekledik:

css
@import "tailwindcss" source(none);
@source inline("bg-red-{50,{100..900..200},950}");
css
@layer utilities {
  .bg-red-50 {
    background-color: var(--color-red-50);
  }
  .bg-red-100 {
    background-color: var(--color-red-100);
  }
  .bg-red-300 {
    background-color: var(--color-red-300);
  }
  .bg-red-500 {
    background-color: var(--color-red-500);
  }
  .bg-red-700 {
    background-color: var(--color-red-700);
  }
  .bg-red-900 {
    background-color: var(--color-red-900);
  }
  .bg-red-950 {
    background-color: var(--color-red-950);
  }
}

Aralık 100, 300, 500, 700 ve 900 değerlerini üretti; dışarıdaki virgüllü liste de 50 ile 950'yi ekledi. Varyant açılımıyla birleştirildiğinde ({hover:,}bg-red-{...}) aynı satır her tonun hover sürümünü de üretir. Bu güç dikkatle kullanılmalıdır: geniş aralıklar ve çok sayıda varyant, hiç kullanılmayan yüzlerce kural demektir. Paletteki ton adları için renk paleti yazısına bakın.

@source not inline(): üretimi engellemek

Tersi de mümkündür. @source not inline(), kaynaklarda geçse bile belirli sınıfların üretilmesini engeller. Belge bunu kırmızı arka plan tonlarının bütün hover ve focus sürümleriyle birlikte çıkarılması üzerinden gösterir. Bu, örneğin tasarım sisteminizde kullanılmasını istemediğiniz bir renk ailesini derleme düzeyinde yasaklamanın bir yoludur. Aşağıdaki dinamik ad örneğinde bu direktifi de deneyeceğiz.

Dinamik sınıf adları neden çalışmaz?

Şu şablon parçası, hata durumuna göre kırmızı ya da yeşil metin vermeye çalışıyor. İlk satırda renk adı sınıfın ortasına yerleştiriliyor, ikinci satırda ise koşul tam sınıf adları arasında seçim yapıyor:

html
<div class="text-{{ hata ? 'red' : 'green' }}-600">Dinamik</div>
<div class="{{ hata ? 'text-red-700' : 'text-green-600' }}">Tam ad</div>

Dosyayı source(none) ve @source "./ornek.html" ile derledik. v4.3.5 ile derlenen CSS:

css
@layer utilities {
  .text-green-600 {
    color: var(--color-green-600);
  }
  .text-red-700 {
    color: var(--color-red-700);
  }
}

İlk satırdaki birleştirme hiçbir kural üretmedi. Dosyanın metninde text-red-600 ya da bu satıra ait text-green-600 diye bitişik bir dizge yoktur; sınıf adı ancak şablon çalıştığında oluşur, derleyici ise şablonu çalıştırmaz. Bu yüzden text-red-600 üretilemedi. İkinci satırdaki iki sınıf ise tam haliyle yazıldığı için ikisi de üretildi. Çıktıdaki text-green-600 kuralı da ilk satırdan değil, ikinci satırda tam yazılmış olmasından gelir.

Aynı dosyayı bu kez giriş CSS'ine @source not inline("text-green-600"); ekleyerek derlediğimizde çıktıda yalnızca .text-red-700 kuralı kaldı. Sınıf HTML'de tam haliyle yazılı olduğu halde dışlama direktifi kazandı.

JavaScript bileşenlerinde doğru kalıp

Belgenin bileşen kütüphaneleri için önerisi, prop değerini sınıfın ortasına koymak yerine prop değerlerini tam sınıf adlarına eşleyen bir nesne kullanmaktır. Aşağıdaki dosyada hem doğru eşleme hem de yanlış şablon dizgesi var:

javascript
const renkler = { mavi: "bg-blue-600 hover:bg-blue-500", kirmizi: "bg-red-600 hover:bg-red-500" };
const yanlis = `bg-${renk}-600`;

Bu JavaScript dosyası @source "./ornek.js" ile kaydedildiğinde v4.3.5 ile derlenen CSS:

css
@layer utilities {
  .bg-blue-600 {
    background-color: var(--color-blue-600);
  }
  .bg-red-600 {
    background-color: var(--color-red-600);
  }
  @media (hover: hover) {
    .hover\:bg-blue-500:hover {
      background-color: var(--color-blue-500);
    }
    .hover\:bg-red-500:hover {
      background-color: var(--color-red-500);
    }
  }
}

Eşleme nesnesindeki dört sınıfın hepsi üretildi; şablon dizgesindeki bg-${renk}-600 ise hiçbir şey üretmedi. Derleyici dosyanın JavaScript olduğunu umursamadı, yalnızca metindeki tam sınıf adlarını topladı. Eşleme kalıbının bir avantajı daha vardır: her prop değeri farklı tonlara ya da ek sınıflara bağlanabilir, örneğin sarı düğmede beyaz yerine siyah metin kullanılabilir.

Hangi aracı ne zaman kullanmalı?

Direktiflerin hepsi aynı soruya yanıt verir: derleyici hangi metinlere bakacak? Aşağıdaki tablo, bu yazıdaki denemelerden çıkan pratik eşleştirmeyi özetler. Çoğu projede hiçbirine ihtiyaç duymazsınız; otomatik tespit, .gitignore kurallarıyla birlikte yeterince isabetlidir. Direktiflere genellikle proje yapısı varsayımların dışına çıktığında başvurulur: kütüphane node_modules içindeyse, derleme başka bir klasörden çalışıyorsa, birden fazla stil dosyası varsa ya da sınıf adları dosyalarda hiç geçmiyorsa.

İhtiyaçKullanılacak yazım
Taranmayan bir klasörü eklemek@source "../yol"
Büyük, sınıfsız bir klasörü çıkarmak@source not "../yol"
Taramanın başlangıcını sabitlemek@import "tailwindcss" source("../src")
Her stil dosyasının kaynağını elle seçmeksource(none) ve ardından @source satırları
Dosyada geçmeyen sınıfları üretmek@source inline("...")
Belirli sınıfları hiç üretmemek@source not inline("...")

Tablodaki yazımlar birlikte de kullanılabilir. Bu yazıdaki ikinci denemede aynı dosyada hem @source hem @source not vardı ve ikisi de beklenen etkiyi gösterdi.

Sık yapılan hatalar

  • Sınıf adını birleştirmek: bg-${renk}-600 ya da text-{{ renk }}-600 gibi yazımlar hiçbir CSS üretmez; tam adları bir eşleme ile seçin.
  • source(none) yazıp kaynak eklememek: Bu durumda hiçbir dosya taranmaz; denemede çıktıda yalnızca boş bir @layer utilities; bildirimi kaldı. source(none) ile birlikte en az bir @source yolu verin.
  • Yolu yanlış yere göre yazmak: @source ve source() yolları CSS dosyasına göre çözülür, komutun çalıştığı dizine göre değil.
  • node_modules içindeki kütüphaneyi unutmak: Tailwind ile yazılmış bir paketin sınıfları ancak @source ile kaydedilirse üretilir.
  • Aşırı geniş inline listeler: @source inline() içinde büyük aralıklar ve çok sayıda varyant, kullanılmayan kural yığını üretir.

Sık Sorulan Sorular

v3'teki safelist ayarının karşılığı nedir?

v4'te safelist işlevini CSS içinde @source inline() görür; süslü parantez açılımıyla varyantlar ve aralıklar da tanımlanabilir. Diğer v3 farkları için Tailwind v4 yenilikleri yazısına bakabilirsiniz.

@source ile tek bir dosya kaydedebilir miyim?

Evet. Yol bir klasör olabileceği gibi tek bir dosya da olabilir. Bu serideki örneklerin çoğu source(none) ile birlikte yalnızca @source "./ornek.html"; satırını kullanır ve derleyici sadece o dosyadaki sınıfları üretir. Küçük deneyler, belge örnekleri ya da tek sayfalık açılış sayfaları için bu en öngörülebilir düzendir.

Markdown ya da PHP dosyalarım taranır mı?

Evet. Tarama metin tabanlıdır; dosya türü fark etmeksizin, otomatik dışlama kurallarına takılmayan her dosyadaki tam sınıf adları bulunur.

Bir sınıfın neden üretilmediğini nasıl anlarım?

Önce derlenmiş CSS'te seçiciyi arayın. Yoksa sınıfın kaynakta tam haliyle geçip geçmediğini, dosyanın .gitignore ya da @source not ile dışlanıp dışlanmadığını kontrol edin. Diğer olasılıklar sık hatalar yazısında listelenmiştir.

source(none) kullanınca Preflight da kapanır mı?

Hayır. source(none) yalnızca kaynak taramasını etkiler; bu serideki derlemelerin hepsinde theme ve base katmanları yine üretildi. Preflight'ı kapatmak ayrı bir işlemdir ve Preflight yazısında anlatılır.

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 · Utility class mantığı · Standalone CLI · Tailwind sık hatalar · Vite ve PostCSS kurulumu