İçindekiler
Sağdan Sola (RTL) Desteği: Pratik CSS ve React Uygulama Rehberi
RTL desteği, ertelenebileceği kadar ertelenen özelliklerden biridir. Sonra ekipler, metnin soldan sağa aktığını varsayan eksiksiz bir ürün inşa ettiklerini fark eder ve RTL'yi sonradan eklemek, sahip oldukları her düzen dosyasına dokunmak anlamına gelir.
Bu rehber, işi başından doğru yapmak — ya da en azından sonradan eklemeyi mümkün olduğunca temiz yapmak — üzerinedir. CSS mantıksal özellikleri, dir niteliği, flexbox davranışı, React kalıpları, Tailwind yardımcı sınıfları ve aradaki her şeyi ele alacağız.
Hangi Diller RTL Gerektirir?
Uygulamadan önce hedef kitleyi anlayın. RTL yazı sistemleri şunlardır:
- Arapça — 400 milyonun üzerinde anadili konuşan, 26 ülkede resmi dil
- İbranice — 10 milyonun üzerinde konuşan, yüksek GSYİH'li bir pazarda baskın dil
- Farsça — İran, Afganistan ve Tacikistan'da 80 milyonun üzerinde konuşan
- Urduca — 70 milyonun üzerinde anadili konuşan, Pakistan'ın ortak resmi dili
- Peştuca — 60 milyonun üzerinde konuşan
- Sindhi, Uygurca, Kürtçe (Sorani) — daha küçük ama önemli kullanıcı tabanları
Sadece Arapça ve İbranice pazarları, devasa bir e-ticaret ve SaaS gelir potansiyeli temsil eder. RTL desteği olmayan ürünler bu bölgelere basitçe gönderilmez — düzeni yerelleştirmeden içeriği yerelleştirmek anlamsızdır.
CSS Mantıksal Özellikler: Temel
RTL desteği için CSS'inizde yapabileceğiniz en büyük tek iyileştirme, fiziksel özelliklerden mantıksal özelliklere geçmektir. Fiziksel özellikler (margin-left, padding-right, border-left) ekran kenarlarına sabit kodludur. Mantıksal özellikler (margin-inline-start, padding-inline-end, border-inline-start) belgenin yazım yönüne göre otomatik olarak uyum sağlar.
Bu tek değişiklik, RTL düzen sorunlarının yaklaşık %80'ini çözer.
Eşleştirme tablosu:
| Fiziksel Özellik | Mantıksal Karşılığı |
|---|---|
margin-left | margin-inline-start |
margin-right | margin-inline-end |
padding-left | padding-inline-start |
padding-right | padding-inline-end |
border-left | border-inline-start |
border-right | border-inline-end |
left | inset-inline-start |
right | inset-inline-end |
margin-top | margin-block-start |
margin-bottom | margin-block-end |
padding-top | padding-block-start |
padding-bottom | padding-block-end |
text-align: left | text-align: start |
text-align: right | text-align: end |
width | inline-size |
height | block-size |
2026'da tarayıcı desteği: Mükemmel. Tüm büyük tarayıcılar CSS mantıksal özelliklerini yıllardır desteklemektedir. Tereddütsüz kullanabilirsiniz.
/* Önce — RTL'de bozulur */
.card {
margin-left: 1rem;
padding-right: 1.5rem;
border-left: 2px solid var(--accent);
text-align: left;
}
/* Sonra — hem LTR hem de RTL'de çalışır */
.card {
margin-inline-start: 1rem;
padding-inline-end: 1.5rem;
border-inline-start: 2px solid var(--accent);
text-align: start;
}
LTR modunda margin-inline-start, margin-left olarak çözümlenir. RTL'de ise margin-right olarak çözümlenir. CSS'i bir kez yazarsınız, her iki yön de doğru çalışır.
dir Niteliği
Yönü HTML öğesi düzeyinde belirleyin:
<html lang="ar" dir="rtl">
Ya da karışık içeriğiniz olduğunda öğe bazında:
<p dir="rtl">مرحباً بالعالم</p> <p dir="ltr">Hello world</p>
CSS direction özelliği aynı şeyi CSS'te yapar:
.arabic-content {
direction: rtl;
}
[dir="rtl"] seçici kalıbı, mantıksal özelliklerin yetmediği durumlarda RTL'ye özgü geçersiz kılmalar için kullanışlıdır:
/* Varsayılan (LTR) */
.nav-icon {
transform: none;
}
/* Yönsel ikonlar için RTL geçersiz kılma */
[dir="rtl"] .nav-icon--arrow {
transform: scaleX(-1);
}
unicode-bidi: bidi-override içerikten bağımsız olarak belirli bir yönü zorlar. Bunu tutumlu kullanın — genellikle yalnızca kod blokları veya yeniden sıralanmaması gereken içerik için gereklidir:
.code-block {
direction: ltr;
unicode-bidi: isolate;
}
RTL'de Flexbox ve Grid
Gerçekten iyi bir haber var: flexbox ve CSS grid, belge yönünü otomatik olarak dikkate alır.
.nav {
display: flex;
flex-direction: row;
gap: 1rem;
}
LTR'de öğeler soldan sağa akar. RTL'de aynı CSS, öğelerin sağdan sola akmasına neden olur. Hiçbir şeyi değiştirmenize gerek yoktur.
Otomatik olarak çalışanlar:
flex-direction: rowRTL'de tersine dönerjustify-content: flex-startsatır başlangıcına hizalanır (RTL'de sağ)- Grid sütun sıralaması yönü dikkate alır
- Grid şablon alanları doğru şekilde uyum sağlar
Manuel dikkat gerektiren durumlar:
/* Bu transform otomatik olarak çevrilmez */
.slide-in {
transform: translateX(-100%);
}
/* Mantıksal özellik karşılığı ile düzeltin */
[dir="rtl"] .slide-in {
transform: translateX(100%);
}
left/right ile konumlandırma da çevrilmez:
/* RTL'de bozulur */
.tooltip {
position: absolute;
left: 100%;
}
/* Bunun yerine mantıksal özellikler kullanın */
.tooltip {
position: absolute;
inset-inline-start: 100%;
}
RTL Düzeltmesi Gereken Yaygın Kalıplar
Navigasyon Okları ve Şevronslar
Yön belirten ok ikonları RTL'de çevrilmelidir:
/* Yalnızca yönsel ikonları çevir */
[dir="rtl"] .icon--arrow-right,
[dir="rtl"] .icon--chevron-right,
[dir="rtl"] .icon--next,
[dir="rtl"] .icon--forward {
transform: scaleX(-1);
}
ÇEVİRMEYİN: onay işaretleri, uyarı üçgenleri, logolar, kullanıcı avatarları, yükleme/indirme ikonları, medya kontrolleri (oynat/durdur). Bunlar yönsel değildir.
Breadcrumb'lar
Breadcrumb öğeleri arasındaki ayırıcı tersine çevrilmelidir:
.breadcrumb-separator::before {
content: "/";
}
[dir="rtl"] .breadcrumb-separator::before {
content: "\\";
/* Ya da • gibi uygun bir RTL-bağımsız ayırıcı kullanın */
}
Daha iyi: tarafsız bir ayırıcı karakter veya çevirebileceğiniz bir SVG kullanın.
İlerleme Çubukları
Dolum yönü görsel olarak önem taşır:
.progress-fill {
width: var(--progress);
/* LTR'de: soldan dolar */
/* RTL'de: sağdan dolmalıdır */
transform-origin: inline-start;
}
[dir="rtl"] .progress-fill {
margin-inline-start: auto;
/* Ya da: yansıtılmış bir gradyan kullanın */
}
Kutu Gölgeleri
Derinlik veya yüksekliği gösteren gölgeler çoğunlukla yönsel görünür:
/* LTR — sağda gölge */
.card {
box-shadow: 4px 0 8px rgba(0,0,0,0.1);
}
/* RTL — gölge solda olmalıdır */
[dir="rtl"] .card {
box-shadow: -4px 0 8px rgba(0,0,0,0.1);
}
React Uygulaması
Herhangi bir bileşenin tüketebilmesi için yön durumunu bir context olarak yapılandırın:
// direction-context.tsx
import { createContext, useContext, ReactNode } from "react";
type Direction = "ltr" | "rtl";
const DirectionContext = createContext<Direction>("ltr");
interface DirectionProviderProps {
direction: Direction;
children: ReactNode;
}
export function DirectionProvider({ direction, children }: DirectionProviderProps) {
return (
<DirectionContext.Provider value={direction}>
<div dir={direction} className={`dir-${direction}`}>
{children}
</div>
</DirectionContext.Provider>
);
}
export function useDirection(): Direction {
return useContext(DirectionContext);
}
Uygulama kökünde, locale yapılandırmanızdan yönü aktarın:
// app.tsx
import { DirectionProvider } from "./direction-context";
const RTL_LOCALES = new Set(["ar", "he", "fa", "ur"]);
export function App({ locale }: { locale: string }) {
const direction = RTL_LOCALES.has(locale) ? "rtl" : "ltr";
return (
<DirectionProvider direction={direction}>
<Router />
</DirectionProvider>
);
}
Yönü bilmesi gereken bileşenler hook'u tüketir:
function NavArrow() {
const direction = useDirection();
return (
<svg
style={{
transform: direction === "rtl" ? "scaleX(-1)" : "none"
}}
aria-hidden="true"
>
{/* ok yolu */}
</svg>
);
}
CSS Modules ile: bir data niteliği ekleyin ve üzerinde seçim yapın:
<div data-direction={direction} className={styles.container}>
/* component.module.css */
.container {
padding-inline-start: 1rem;
}
/* Yalnızca mantıksal özelliklerin yetersiz kaldığı durumları geçersiz kılın */
.container[data-direction="rtl"] .icon {
transform: scaleX(-1);
}
Better i18n gibi bir platform kullanılırken, locale yönü SDK'dan locale'in kendisiyle birlikte alınabilir; böylece ek bir kurulum yapmadan dir'i locale'i türettiğiniz noktada türetebilirsiniz.
Tailwind CSS RTL Desteği
Tailwind, rtl: ve ltr: varyantlarını kutudan çıkar çıkmaz içerir. Yapılandırmanızda etkinleştirin:
// tailwind.config.js
module.exports = {
// ...
future: {
hoverOnlyWhenSupported: true,
},
};
Varyantlar, bir üst öğede dir="rtl" veya dir="ltr" olduğunda etkinleşir.
Temel kullanım:
<!-- Margin yöne göre çevrilir --> <div class="ms-4 me-2"> <!-- ms- = margin-inline-start, me- = margin-inline-end --> <!-- Bunlar Tailwind'in mantıksal özellik yardımcı sınıflarıdır --> </div> <!-- Açık yönsel geçersiz kılmalar --> <button class="ltr:ml-4 rtl:mr-4">Gönder</button> <!-- İkon çevirme --> <svg class="rtl:scale-x-[-1]">...</svg>
Tailwind'in mantıksal özellik yardımcı sınıfları (ms-, me-, ps-, pe-, border-s, border-e, start-, end-) doğru varsayılan tercihtir — fiziksel yardımcı sınıfların yerini alır ve varyant kullanmadan RTL'yi yönetir:
<!-- Önce: fiziksel yardımcı sınıflar, RTL'de bozulur --> <nav class="pl-6 border-l-2 text-left"> <!-- Sonra: mantıksal yardımcı sınıflar, her ikisinde de çalışır --> <nav class="ps-6 border-s-2 text-start">
rtl: ve ltr: varyantlarını yalnızca mantıksal özelliklerin yetersiz kaldığı durumlar için kullanın — ikon dönüşümleri veya animasyon kökenleri gibi.
RTL Düzenlerini Test Etme
Chrome DevTools
RTL'yi önizlemenin en hızlı yolu: DevTools'u açın, Rendering sekmesine gidin ve "Emulate CSS media feature forced-colors" bulun — ancak daha kullanışlı olanı, Elements paneli aracılığıyla kök öğeye dir="rtl" eklemektir. Sayfa yenilemeye gerek yok.
Playwright
Her iki modda da düzeni doğrulayan yön odaklı testler yazın:
// rtl.spec.ts
import { test, expect } from "@playwright/test";
test.describe("RTL düzeni", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
await page.evaluate(() => {
document.documentElement.setAttribute("dir", "rtl");
});
});
test("navigasyon RTL'de doğru görüntülenir", async ({ page }) => {
const nav = page.locator("nav");
await expect(nav).toBeVisible();
// RTL'de menünün sağ tarafta olduğunu doğrulayın
const navBox = await nav.boundingBox();
const viewportWidth = page.viewportSize()?.width ?? 1280;
expect(navBox!.x).toBeGreaterThan(viewportWidth / 2);
});
test("form girişleri doğru hizalanır", async ({ page }) => {
const label = page.locator('label[for="email"]');
const input = page.locator("#email");
const labelBox = await label.boundingBox();
const inputBox = await input.boundingBox();
// RTL'de etiket girişin sağında veya üstünde olmalıdır
// Bu düzeninize bağlıdır, iddiayı buna göre ayarlayın
expect(labelBox).toBeTruthy();
expect(inputBox).toBeTruthy();
});
});
Görsel Regresyon
dir="rtl" varyantıyla görsel regresyon testleri çalıştırın. Playwright'ın yerleşik ekran görüntüsü karşılaştırmasıyla:
test("RTL ana sayfa anlık görüntüsü", async ({ page }) => {
await page.goto("/");
await page.evaluate(() => {
document.documentElement.setAttribute("dir", "rtl");
});
await expect(page).toHaveScreenshot("homepage-rtl.png");
});
Manuel KG Kontrol Listesi
- Navigasyon öğeleri sağdan sola akar
- Kenar çubuğu sağda
- Form etiketleri doğru hizalanmış
- Yönsel ikonlar (oklar, şevronslar) çevrilmiş
- İlerleme çubukları sağdan doluyor
- Açılır menüler doğru yönde açılıyor
- Modallar/çekmeceler doğru taraftan açılıyor
- Breadcrumb ayırıcıları doğru yönü gösteriyor
- Metin hizalaması boyunca doğru
- Kaydırma çubukları solda görünüyor (tarayıcılar bunu otomatik olarak yönetir)
- RTL içeriğinde sayılar ve Latin metni LTR olarak kalıyor
RTL İçin Yazı Tipleri ve Tipografi
Arapça ve İbranice uygun yazı tipleri gerektirir — varsayılan sistem yazı tipleri yetersiz görünebilir.
Önerilen yazı tipleri:
- Noto Sans Arabic — Google'ın kapsamlı desteği, ücretsiz, Noto ailesiyle eşleşir
- IBM Plex Arabic — Teknik/geliştirici araçları için mükemmel, IBM Plex Sans ile uyumlu
- Cairo — Modern, sade, UI için uygun
- Tajawal — Geometrik, sans-serif LTR yazı tipleriyle iyi uyum sağlar
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@400;500;600;700&display=swap");
:lang(ar) {
font-family: "Noto Sans Arabic", "Segoe UI", system-ui, sans-serif;
font-size: 1.05em; /* Arapça genellikle biraz daha büyük okunur */
line-height: 1.8; /* Arapça, Latin'den daha fazla dikey alan gerektirir */
}
:lang(he) {
font-family: "Noto Sans Hebrew", "Segoe UI", system-ui, sans-serif;
line-height: 1.6;
}
Temel tipografik ayarlamalar:
- Arapça metin, aynı boyuttaki eşdeğer Latin metniyle karşılaştırıldığında genellikle 1-2 piksel daha büyük yazı tipinden yararlanır
- Satır yüksekliği Arapça için 1,6–2,0 olmalıdır (Latin için 1,4–1,6'ya karşın), diyakritik işaretler nedeniyle
- Harf aralığı (
letter-spacing) Arapça için genellikle 0 veya hafif negatif olmalıdır — asla pozitif değil font-variant-numeric: ltrRTL metin içinde rakamların soldan sağa görüntülenmesini sağlar
Çift Yönlü Metin (Bidi)
RTL belgeler çoğunlukla LTR parçalar içerir: İngilizce marka adları, sayılar, URL'ler, kod. Unicode Çift Yönlü Algoritması çoğu durumu otomatik olarak yönetir, ancak karmaşık düzenler açık kontrol gerektirir.
<bdi> öğesi bir parçanın yön özelliğini çevreleyen metinden izole eder:
<p dir="rtl"> المستخدم <bdi>JohnDoe123</bdi> أرسل رسالة </p>
<bdi> olmadan kullanıcı adı, karakterlerine bağlı olarak yanlış yönde görüntülenebilir.
unicode-bidi: isolate CSS'te aynı şeyi yapar:
.username {
unicode-bidi: isolate;
}
Sayılar RTL metinde LTR kalır — Bidi algoritması bunu yönetir. Telefon numaraları, fiyatlar, tarihler okuma sırasında görüntülenir. Genellikle müdahale etmeniz gerekmez.
Kod blokları her zaman LTR olmalıdır:
pre, code {
direction: ltr;
unicode-bidi: isolate;
text-align: start; /* start = LTR'de sol */
}
Marka adları ve ürün adları Latin alfabesiyle yazılmışsa, RTL metin içinde doğal olarak LTR kalacaktır. Yanlış görüntüleme görüyorsanız, bunları <bdi> veya dir="ltr" içeren bir span ile sarın:
<span dir="ltr">Better i18n</span>
Better i18n gibi bir platform aracılığıyla çevirileri yönetirken, SDK çevirmenlerinizin eklediği satır içi yön işaretçileri de dahil olmak üzere locale dizelerini zaten hazır şekilde sunar; bu nedenle uygulama kodunda dizeleri sonradan işlemenize gerek kalmaz.
RTL ve Better i18n
LTR ve RTL locale'ler arasında çevirileri yönetiyorsanız, yön verisi locale yapılandırmasının yanında yer almalıdır — bileşenler arasında dağılmış şekilde değil. Better i18n, çeviri dizelerinizi sunan SDK'nın aynısı aracılığıyla metin yönü de dahil olmak üzere locale meta verilerini sağlar. Bir kullanıcıyı Arapça'ya geçirdiğinizde, yön otomatik olarak locale aktivasyonunun bir parçası olarak değişir — birinin ayrıca bağlamayı hatırlaması gereken ayrı bir adım olarak değil.
RTL Uygulama Kontrol Listesi
RTL desteğini göndermeden önce şunları doğrulayın:
CSS
- Fiziksel margin/padding/border mantıksal özelliklere geçirildi
-
left/rightkonumlandırmainset-inline-start/inset-inline-endile değiştirildi -
text-align: left/right,text-align: start/endile değiştirildi - Yönsel ikonlar
[dir="rtl"]seçici veyartl:Tailwind varyantıyla çevriliyor - Animasyonlar ve dönüşümler yönü hesaba katıyor
HTML
-
<html>öğesinedirniteliği eklenmiş -
langniteliği doğru ayarlanmış - Karma yönlü satır içi içerik için
<bdi>kullanılmış
React
- Yön context sağlayıcısı uygulamayı sarıyor
- Locale'den yöne eşleme tüm RTL locale'leri kapsıyor
- Yönü tüketen bileşenler hook kullanıyor, sabit kodlanmış değerler değil
Test
- Tüm anahtar sayfalar için RTL ekran görüntüleri incelendi
- Otomatik testler RTL düzenini kapsıyor
- KG kontrol listesi tamamlandı
Tipografi
- Arapça/İbranice/Farsça için uygun RTL yazı tipleri yüklendi
- RTL yazı sistemleri için satır yüksekliği ayarlandı
- Gerektiğinde yazı tipi boyutu düzenlendi
RTL desteği tek bir özellik değildir — tüm düzen sisteminin bir özelliğidir. Bunu doğru yapan ekipler, yönü tasarım sistemlerinin birinci sınıf bir boyutu olarak ele alır; başından itibaren mantıksal özellikleri seçer ve flexbox ile grid'in ağır işi yapmasına izin verir. Zorlanan ekipler ise CSS'lerinin her köşesine LTR varsayımları eklemiş ve şimdi bunları tek tek geçersiz kılmaları gereken ekiplerdir.
Mantıksal özelliklerle başlayın. HTML öğesinde yönü ayarlayın. Flexbox'ın geri kalanını otomatik olarak yönetmesine izin verin. Ardından yönsel farkındalık gerektiren belirli kalıpları — ikonlar, dönüşümler, yazı tipleri — ele alın. Dikkatli yapıldığında, RTL desteği çoğu ekibin beklediğinden çok daha az iş gerektirir.
Better i18n, modern frontend ekipleri için tasarlanmış, geliştirici odaklı bir yerelleştirme platformudur. Tip güvenli SDK'lar, Git tabanlı iş akışları, CDN dağıtımı ve sözlük uygulamasıyla AI çevirisi — deponuzda locale dosyaları olmadan.