توسعه فرانت‌اند

CSS Logical Properties؛ طراحی با جهت RTL و LTR

نگاشت جهت‌های منطقی، تفاوت dir و writing-mode، متن ترکیبی با bdi و نمونه مستقل کارت برای تغییر RTL و LTR با HTML و CSS کامل.

1404/12/14 3 دقیقه مطالعه 1,400 بازدید

شروع سطر همیشه سمت چپ نیست

در کارت فارسی، علامت وضعیت معمولاً نزدیک ابتدای سطر قرار می‌گیرد و لینک ادامه ممکن است در انتهای آن باشد. اگر فاصله‌ها را با margin-left و margin-right ثبت کنیم، نسخهٔ انگلیسی همان کارت به اصلاح جدا احتیاج پیدا می‌کند. Logical Properties نام فاصله را به جریان نوشتار وصل می‌کنند: آغاز محور inline، پایان آن و محور block. این شیوه برای component چندزبانه مفید است، چون قصد طراحی را بیان می‌کند. با این حال، قرار نیست همهٔ سمت‌های فیزیکی بدون بررسی به منطقی تبدیل شوند؛ جهت واقعی برخی عناصر مستقل از زبان است.

مثلاً یک نشانگر روی نقشه ممکن است باید در سمت غرب تصویر بماند. جابه‌جا کردن آن با تغییر زبان، معنی را عوض می‌کند. اما فاصلهٔ میان آیکون و عنوان معمولاً به جریان خواندن وابسته است. تصمیم درست از معنای عنصر می‌آید. راهنمای Logical Properties رابطهٔ نام‌های منطقی و جهت نوشتار را توضیح می‌دهد. این قابلیت ابزار ثبت همان معناست و به تنهایی کل رابط را برای هر زبان آماده نمی‌کند.

Inline و block دو محور نسبی‌اند

در نوشتار افقی، محور inline در امتداد سطر و block در جهت قرار گرفتن سطرهای بعدی است. برای فارسی و انگلیسی افقی، inline معمولاً افقی و block عمودی است. در writing mode عمودی این نگاشت عوض می‌شود؛ بنابراین inline-size همیشه معادل width نیست. جملهٔ block-size یعنی height فقط با فرض نوشتار افقی درست است. نام منطقی به جریان متن وابسته است و نام فیزیکی به صفحه. همین تفاوت برای فهمیدن اندازه، حاشیه و موقعیت ضروری است.

ویژگی writing-mode تعیین می‌کند خطوط چگونه جریان پیدا کنند. direction هم جهت پایهٔ نوشتار را بیان می‌کند. تغییر direction به تنهایی صفحه را به نوشتار عمودی نمی‌برد. مستندات writing-mode حالت‌ها را جدا توضیح داده است. در نمونهٔ این مقاله writing mode افقی داریم و فقط جهت کارت را تغییر می‌دهیم. این محدودیت مشخص کمک می‌کند اثر inline-start و inline-end بدون وارد کردن سناریوی دیگری دیده شود.

Direction را در HTML هم ثبت کنید

برای محتوای فارسی، dir روی HTML یا محدودهٔ مناسب، اطلاعات معنایی جهت را همراه متن نگه می‌دارد. صرف گذاشتن direction در stylesheet ممکن است هنگام نبود CSS این معنا را منتقل نکند. زبان با lang ثبت می‌شود و lang به تنهایی تضمین انتخاب RTL نیست. همچنین جهت یک component می‌تواند با صفحه فرق داشته باشد. در صفحهٔ فارسی، قطعهٔ کد یا شناسهٔ انگلیسی ممکن است جهت مستقل بخواهد. راهنمای dir گزینه‌های rtl، ltr و auto را توضیح می‌دهد.

Auto برای متن با جهت نامعلوم کاربرد دارد، اما نباید بی‌دلیل روی همهٔ containerهای ساختاری گذاشته شود. اگر اولین محتوای معنی‌دار تغییر کند، جهت پایه هم ممکن است عوض شود. برای یک کارت محصول فارسی شناخته‌شده، direction روشن ساده‌تر است. برای نام کاربر که می‌تواند فارسی یا انگلیسی باشد، محدودهٔ جداگانه مناسب‌تر است. جهت متن و جهت layout را کنار هم بخوانید؛ تغییر یک مقدار ممکن است Flexbox، تراز متن و محل فاصله‌ها را هم تحت تأثیر قرار دهد.

فاصله، حاشیه و اندازه با نام روشن

margin-inline-start فاصله در ابتدای محور inline را ثبت می‌کند. padding-inline با یک مقدار هر دو طرف inline و با دو مقدار، آغاز و پایان را مشخص می‌کند. border-inline-start برای حاشیهٔ معنایی آغاز component مناسب است. margin-block فاصلهٔ میان بلوک‌ها را بیان می‌کند. این نام‌ها در stylesheet به خواننده می‌گویند فاصله برای جریان متن است. مرجع margin-inline-start نگاشت آن و رفتار مقدارها را بیان می‌کند.

هنگام مهاجرت، قاعدهٔ فیزیکی قبلی را هم پیدا کنید. باقی ماندن margin-left و اضافه کردن margin-inline-start می‌تواند در یک جهت به همان سمت و در جهت دیگر به سمت متفاوت اثر بگذارد. نتیجه به cascade و ترتیب قواعد وابسته است. تبدیل کامل یک component کوچک و خواندن همهٔ قواعدش معمولاً از جایگزینی سراسری نام‌ها قابل فهم‌تر است. به‌خصوص shorthandهای margin و padding را بررسی کنید؛ ممکن است بعداً مقدار منطقی قبلی را برای همان سمت بازنویسی کنند.

نمونهٔ مستقل با دو دکمهٔ جهت

کد زیر را با نام logical-card.html ذخیره کنید و در مرورگر باز کنید. package، build و فایل بیرونی لازم نیست. HTML، CSS و JavaScript کامل در یک فایل‌اند. دکمه‌های RTL و LTR فقط dir کارت را تغییر می‌دهند؛ متن فارسی به انگلیسی ترجمه نمی‌شود. بنابراین حالت LTR آزمایشی برای دیدن نگاشت layout است و ادعای نسخهٔ کامل انگلیسی محصول نیست. آیکون، محتوای کارت، دکمه و لینک همگی ساختار متناظر در HTML دارند و تصویر استفاده نشده است.

<!doctype html>
<html lang="fa" dir="rtl">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>جهت منطقی</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; padding-block: 2rem; padding-inline: 1rem; background: #eef3f4; color: #1d333c; font-family: system-ui,sans-serif; }
  main { max-inline-size: 44rem; margin-inline: auto; }
  .toolbar { margin-block-end: 1rem; display: flex; gap: .6rem; flex-wrap: wrap; }
  button,a { font: inherit; }
  button { padding-block: .6rem; padding-inline: .9rem; border: 1px solid #4c6973; border-radius: .4rem; background: white; color: #1d333c; cursor: pointer; }
  button[aria-pressed=true] { background: #075c55; color: white; }
  :focus-visible { outline: 3px solid #bd6800; outline-offset: 3px; }
  .card { display: flex; gap: 1rem; align-items: flex-start; padding-block: 1.2rem; padding-inline: 1.2rem 1.5rem; border-inline-start: .35rem solid #075c55; background: white; border-radius: .6rem; }
  .badge { flex: 0 0 auto; inline-size: 2.4rem; block-size: 2.4rem; display: grid; place-items: center; border-radius: 50%; background: #d9eee7; }
  .content { flex: 1; min-inline-size: 0; text-align: start; }
  h2 { margin-block: 0 .5rem; }
  p { line-height: 1.8; margin-block: .5rem; overflow-wrap: anywhere; }
  .actions { display: flex; margin-block-start: 1rem; }
  .actions a { margin-inline-start: auto; color: #075c55; padding-block: .3rem; }
</style></head>
<body><main><h1>یک کارت با دو جهت</h1><p>دکمه‌ها جهت کارت را تغییر می‌دهند؛ متن نمونه ثابت می‌ماند.</p>
<div class="toolbar" aria-label="جهت کارت"><button id="rtl" type="button" aria-pressed="true">RTL</button><button id="ltr" type="button" aria-pressed="false">LTR</button></div>
<article class="card" id="card" dir="rtl"><span class="badge" aria-hidden="true">۱</span><div class="content"><h2>سفارش نمونه</h2><p>شناسه: <bdi dir="ltr">ORDER-2048</bdi></p><p>این کارت تنها نمونهٔ چینش است و سفارش واقعی ثبت نمی‌کند.</p><div class="actions"><a href="#details">خواندن توضیح</a></div></div></article>
<section id="details"><h2>توضیح کارت</h2><p>حاشیهٔ رنگی در آغاز محور inline و لینک در انتهای آن قرار می‌گیرد.</p></section>
<script>
  const card = document.getElementById('card');
  for (const direction of ['rtl', 'ltr']) {
    document.getElementById(direction).addEventListener('click', () => {
      card.dir = direction;
      document.getElementById('rtl').setAttribute('aria-pressed', String(direction === 'rtl'));
      document.getElementById('ltr').setAttribute('aria-pressed', String(direction === 'ltr'));
    });
  }
</script></main></body></html>

حاشیهٔ رنگی با border-inline-start در آغاز کارت قرار می‌گیرد. فاصلهٔ داخلی آغاز و پایان متفاوت است تا اثر padding-inline دیده شود. لینک با margin-inline-start:auto در انتهای محور inline قرار می‌گیرد. در نوشتار افقی RTL، آغاز سمت راست و در LTR سمت چپ است. جهت base کارت روی ترتیب Flexbox هم اثر دارد. لینک به بخش واقعی details در همان فایل می‌رود و نشانی ساختگی ندارد. دکمه‌ها با aria-pressed وضعیت انتخاب را بیان می‌کنند.

CSS عرض محتوا را با max-inline-size محدود می‌کند و min-inline-size:0 به بخش انعطاف‌پذیر اجازهٔ کوچک شدن می‌دهد. متن بلند با overflow-wrap در محدودهٔ کارت می‌ماند. این قواعد جای طراحی responsive کامل یک محصول را نمی‌گیرند، ولی وابستگی نمونه به عرض ثابت صفحه را کم می‌کنند. هیچ نتیجهٔ اندازه‌گیری یا اجرای تست برای این فایل گزارش نشده است؛ روش اجرا برای خواننده ارائه شده و تطابق نام‌ها در کد روشن است.

متن ترکیبی به محدودهٔ جدا نیاز دارد

شناسهٔ ORDER-2048 در bdi با جهت ltr قرار گرفته است. این عنصر به جدا شدن اثر جهت قطعهٔ متن از اطرافش کمک می‌کند. چسبیدن شماره، علامت و متن فارسی بدون محدودهٔ مناسب می‌تواند ترتیب دیداری گیج‌کننده‌ای بسازد. مرجع bdi نقش جداسازی متن دوطرفه را شرح می‌دهد. برای کد، شماره تلفن و دادهٔ کاربر، هم جهت و هم نحوهٔ خواندن و کپی کردن باید به نوع داده وابسته باشد.

Logical Properties مشکل الگوریتم متن دوطرفه را به تنهایی حل نمی‌کنند. آن‌ها فاصله و layout را نسبت به جریان تعریف می‌کنند، اما رشتهٔ ترکیبی هنوز قواعد متن خودش را دارد. همین‌طور تراز start در text-align به جهت متن وابسته است و با left ثابت فرق دارد. مستندات text-align تفاوت مقدارهای نسبی و فیزیکی را نشان می‌دهد. در کارت نمونه از start استفاده شده تا قصد تراز با آغاز متن روشن باشد.

ترتیب دیداری را جای ترتیب خواندن نگذارید

استفاده از row-reverse برای جبران جهت، ممکن است بعداً با dir همان container دو بار اثر بگذارد. تغییر order در Flexbox هم ترتیب DOM را عوض نمی‌کند؛ keyboard و ابزار خواندن صفحه ممکن است مسیر دیگری دنبال کنند. بهتر است ترتیب معنایی در HTML درست باشد و layout روی آن ساخته شود. مقالهٔ دسترس‌پذیری از روز اول همین ارتباط ساختار و تعامل را توضیح می‌دهد. هر اصلاح RTL باید کنار مسیر focus و ترتیب اطلاعات خوانده شود.

جهت آیکون را از معنی آن انتخاب کنید

فلش ادامهٔ مسیر معمولاً با جریان ناوبری مرتبط است و ممکن است نیاز به معکوس شدن داشته باشد. لوگو، علامت برند یا تصویر یک ابزار واقعی معمولاً با تغییر زبان آینه نمی‌شود. همچنین Logical Properties همهٔ transformها و سایه‌ها را خودکار بازنویسی نمی‌کنند. یک translateX مثبت همچنان مقدار فیزیکی خودش را دارد. اگر انیمیشن به جهت وابسته است، آن قرارداد را جدا بنویسید. نوشتهٔ Motion و حرکت رابط برای انتخاب رفتار حرکت مرتبط است.

مهاجرت را component به component انجام دهید

ابتدا componentی با مرز روشن، مثل کارت یا input همراه آیکون را انتخاب کنید. همهٔ فاصله‌ها، ترازها و موقعیت‌های آن را بخوانید و مشخص کنید کدام معنا به متن وابسته است. سپس نسخهٔ RTL، LTR و محتوای بلند را در همان قرارداد طراحی در نظر بگیرید. قابلیت هر property را برای مرورگرهای هدف جدا بررسی کنید؛ حمایت از یک property به معنی حمایت کامل از تمام خانواده نیست. باقی ماندن چند property فیزیکیِ عمدی، نقص طراحی محسوب نمی‌شود.

برای نگهداری، tokenهای فاصله و رنگ را جدا از جهت نگه دارید؛ نمونهٔ Custom Properties این تفکیک را توضیح می‌دهد. فایل جداگانهٔ RTL ممکن است پس از مهاجرت کوچک‌تر شود، اما حذف کامل آن نتیجهٔ تضمین‌شده نیست. هدف عملی این است که stylesheet قصد فاصله و جایگاه را واضح بیان کند و تغییر زبان، اصلاح‌های تصادفی و تکراری کمتری بخواهد. رابط چندزبانه علاوه بر CSS، به متن، ساختار و معنای درست جهت نیاز دارد.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!