{"id":"l-css-3-2","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"استبدل الخصائص الفيزيائية بالخصائص المنطقية لتعمل صفحة الجدول في اللغات التي تُكتب من اليمين إلى اليسار مثل العربية، وتعامل مع الأشياء القليلة التي لا تنعكس من تلقاء نفسها.","html":"<p>تضيف Waypoint نسخة عربية من الجدول لفعاليتها الفرعية في القاهرة. التغيير في الـ HTML سمة واحدة، <code dir=\"ltr\">&lt;html lang=&quot;ar&quot; dir=&quot;rtl&quot;&gt;</code>، وجاء التحميل الأول صحيحًا نصفه فقط. قائمة الجلسات انعكست كما ينبغي، لأنها صف flex. لكن كل بطاقة ظهر حدّها الملوّن على <em>اليسار</em>، وهو في العربية نهاية السطر لا بدايته، وعمود الوقت جاءت مسافته في الجهة الخاطئة، وسهم «Details →» أشار إلى الوراء.</p>\n<p>كان التخطيط مكتوبًا بالاتجاهات الفيزيائية: يسار ويمين وأعلى وأسفل. لكن النص لا يجري في اتجاهات فيزيائية؛ إنه يجري من بداية إلى نهاية. وأنت تقرأ هذا الدرس الآن من اليمين إلى اليسار، فالبداية عندك على اليمين، بينما هي على اليسار عند قارئ النسخة الإنجليزية.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">محورا الـ inline والـ block</h2>\n<p>الخصائص المنطقية (logical properties) تسمّي الجهات بحسب سير النص:</p>\n<ul>\n<li>محور الـ <strong>inline</strong> هو الاتجاه الذي يجري فيه النص داخل السطر الواحد. في الإنجليزية من اليسار إلى اليمين؛ وفي العربية من اليمين إلى اليسار.</li>\n<li>محور الـ <strong>block</strong> هو الاتجاه الذي تتراصّ فيه الأسطر: من الأعلى إلى الأسفل في اللغتين.</li>\n</ul>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 230\" role=\"img\" aria-labelledby=\"l-css-3-2-t1\"><defs><marker id=\"arrow-l-css-3-2-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-css-3-2-t1\">بطاقتان. في البطاقة من اليسار إلى اليمين تقع inline-start على اليسار وinline-end على اليمين. وفي البطاقة من اليمين إلى اليسار تقع inline-start على اليمين وinline-end على اليسار. وفي الحالتين تقع block-start في الأعلى وblock-end في الأسفل.</title>\n  <text class=\"d-label-strong\" x=\"40\" y=\"24\">dir=\"ltr\"</text>\n  <rect class=\"d-box\" x=\"40\" y=\"40\" width=\"260\" height=\"140\" rx=\"10\"/>\n  <rect class=\"d-box-primary\" x=\"40\" y=\"40\" width=\"10\" height=\"140\"/>\n  <text class=\"d-code\" x=\"60\" y=\"116\">inline-start</text>\n  <text class=\"d-code\" x=\"196\" y=\"116\">inline-end</text>\n  <text class=\"d-label-muted\" x=\"128\" y=\"62\">block-start</text>\n  <text class=\"d-label-muted\" x=\"132\" y=\"172\">block-end</text>\n  <text class=\"d-label-strong\" x=\"380\" y=\"24\">dir=\"rtl\"</text>\n  <rect class=\"d-box\" x=\"380\" y=\"40\" width=\"260\" height=\"140\" rx=\"10\"/>\n  <rect class=\"d-box-primary\" x=\"630\" y=\"40\" width=\"10\" height=\"140\"/>\n  <text class=\"d-code\" x=\"392\" y=\"116\">inline-end</text>\n  <text class=\"d-code\" x=\"522\" y=\"116\">inline-start</text>\n  <text class=\"d-label-muted\" x=\"468\" y=\"62\">block-start</text>\n  <text class=\"d-label-muted\" x=\"472\" y=\"172\">block-end</text>\n  <text class=\"d-label-muted\" x=\"40\" y=\"214\">الحدّ border-inline-start في بداية السطر في الحالتين</text>\n</svg><figcaption>البطاقة نفسها في LTR وRTL: inline-start تنتقل من جهة إلى أخرى، وblock-start تبقى في الأعلى</figcaption></figure>\n<p>لكل خاصية فيزيائية توأم منطقي:</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"جدول قابل للتمرير\" tabindex=\"0\"><table><thead>\n<tr>\n<th>فيزيائية</th>\n<th>منطقية</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code dir=\"ltr\">margin-left</code>، <code dir=\"ltr\">margin-right</code></td>\n<td><code dir=\"ltr\">margin-inline-start</code>، <code dir=\"ltr\">margin-inline-end</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">padding-top</code>، <code dir=\"ltr\">padding-bottom</code></td>\n<td><code dir=\"ltr\">padding-block-start</code>، <code dir=\"ltr\">padding-block-end</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">border-left</code></td>\n<td><code dir=\"ltr\">border-inline-start</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">left</code>، <code dir=\"ltr\">right</code>، <code dir=\"ltr\">top</code></td>\n<td><code dir=\"ltr\">inset-inline-start</code>، <code dir=\"ltr\">inset-inline-end</code>، <code dir=\"ltr\">inset-block-start</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">width</code>، <code dir=\"ltr\">height</code></td>\n<td><code dir=\"ltr\">inline-size</code>، <code dir=\"ltr\">block-size</code></td>\n</tr>\n<tr>\n<td><code dir=\"ltr\">text-align: left</code></td>\n<td><code dir=\"ltr\">text-align: start</code></td>\n</tr>\n</tbody>\n</table></div><p>وهناك اختصارات أيضًا: <code dir=\"ltr\">margin-inline: 1rem 2rem</code> تضبط البداية والنهاية، و<code dir=\"ltr\">padding-block: 1rem</code> تضبط جهتي الـ block معًا، و<code dir=\"ltr\">inset-inline: 0</code> تحلّ محلّ <code dir=\"ltr\">left: 0; right: 0</code>.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">تحويل بطاقة الجلسة</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">session-card.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Before: physical */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border-left</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--track-color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  padding</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 8</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 20</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-align</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">left</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .time</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">margin-right</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* After: logical */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--track-color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  padding-block</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  padding-inline</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">20</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 8</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-align</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .time</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">margin-inline-end</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p>في الإنجليزية النتيجة مطابقة حتى آخر بكسل. وفي العربية ينتقل الحدّ إلى اليمين، حيث تبدأ الأسطر، وتتبعه المسافات. تكتب البطاقة مرة واحدة.</p>\n<p>flexbox وgrid يفكّران بهذه الطريقة أصلًا. <code dir=\"ltr\">flex-direction: row</code> و<code dir=\"ltr\">justify-content: flex-start</code> والعمود 1 في grid كلها تتبع اتجاه السطر، لذا ينعكس صف flex في RTL دون أيّ CSS إضافية. ولهذا عملت قائمة Waypoint من المحاولة الأولى.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>تحويل الـ margins ونسيان المواضع</span></p>\n<p>تحوّل الفرق <code dir=\"ltr\">margin</code> و<code dir=\"ltr\">padding</code> وتنسى العناصر ذات التموضع المطلق (absolute). شارة «Live now» عند <code dir=\"ltr\">right: 8px</code> تبقى على اليمين في العربية، فوق نص العنوان تمامًا. ابحث في قاعدة الكود عن <code dir=\"ltr\">left:</code> و<code dir=\"ltr\">right:</code> أيضًا، واستبدلهما بـ <code dir=\"ltr\">inset-inline-start</code> و<code dir=\"ltr\">inset-inline-end</code>.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">الأحجام منطقية أيضًا</h2>\n<p><code dir=\"ltr\">inline-size</code> و<code dir=\"ltr\">block-size</code> هما الاسمان المنطقيان للعرض والارتفاع، و<code dir=\"ltr\">max-inline-size: 40ch</code> هي النسخة المنطقية من سقف عرض القراءة المريح الذي رأيته في درس التحجيم الذاتي. في العربية والإنجليزية تتصرّفان تمامًا مثل <code dir=\"ltr\">width</code> و<code dir=\"ltr\">height</code>، لأن الخطّين يُكتبان أفقيًا. ولا تختلفان إلا في أنماط الكتابة الرأسية، مثل <code dir=\"ltr\">writing-mode: vertical-rl</code> لليابانية أو لعنوان جدول مُدار، حيث يمتدّ محور الـ inline من الأعلى إلى الأسفل. استخدامهما لا يكلّف شيئًا اليوم، ويعني أن الـ component سيصمد إن تغيّر نمط الكتابة لاحقًا. وقاعدة معقولة للفريق: الخصائص المنطقية لكل ما يتعلّق بسير النص، والفيزيائية فقط لما هو فيزيائي بطبيعته، كظلّ يجب أن يسقط إلى الأسفل دائمًا.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">ما لا ينعكس من تلقاء نفسه</h2>\n<p>بعض الأشياء فيزيائية بطبيعتها وتحتاج إلى قاعدة RTL صريحة:</p>\n<ul>\n<li><strong>الـ transforms</strong>: <code dir=\"ltr\">translateX(8px)</code> تحرّك العنصر إلى اليمين دائمًا.</li>\n<li><strong>الأيقونات الاتجاهية</strong>: الأسهم، وعلامات «التالي»، واتجاه مؤشّر التقدّم.</li>\n<li><strong>مواضع الخلفيات والظلال</strong>: <code dir=\"ltr\">box-shadow: 4px 0 …</code> تلقي ظلّها إلى اليمين دائمًا.</li>\n</ul>\n<p>الـ pseudo-class <code dir=\"ltr\">:dir()</code> تطابق الاتجاه المحسوب للعنصر، الموروث من أقرب سمة <code dir=\"ltr\">dir</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.more</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .arrow</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">inline-block</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  margin-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.more</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .arrow:dir</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">rtl</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  scale</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">-1</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* mirror horizontally */</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p><code dir=\"ltr\">:dir(rtl)</code> أفضل من <code dir=\"ltr\">[dir=&quot;rtl&quot;] .arrow</code> لأنها لا تهتم بمكان السمة، ولا بما إذا كان عنصر متداخل قد عاد إلى LTR. وهي ضمن Baseline منذ ديسمبر 2023، ومتاحة على نطاق واسع منذ منتصف 2026.</p>\n<p>ليست كل أيقونة بحاجة إلى الانعكاس. زر التشغيل والساعة وعلامة الصح تعني الشيء نفسه في الاتجاهين؛ أما سهم «رجوع» أو اتجاه المنزلق (slider) فلا. اسأل أحد الناطقين باللغة حين لا تكون متأكّدًا.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">الخط العربي في قاعدتين</h2>\n<p>الأولى: <strong>لا تطبّق <code dir=\"ltr\">letter-spacing</code> على العربية أبدًا</strong>. الحروف العربية تتّصل بما يجاورها؛ وتبعيدها يقطع هذا الوصل ويجعل الكلمات صعبة القراءة. إن كان نظام التصميم لديك يضيف تباعدًا للتسميات بالأحرف الكبيرة، فأعده إلى الصفر بـ <code dir=\"ltr\">:lang(ar) { letter-spacing: 0; }</code>. والثانية: كثيرًا ما تحتاج العربية إلى حجم خط وارتفاع سطر أكبر قليلًا من النص اللاتيني لتظهر بالوزن البصري نفسه. اضبط ذلك لكل لغة بـ <code dir=\"ltr\">:lang(ar)</code> لا لكل component.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>محتوى مختلط الاتجاه</span></p>\n<p>المحتوى الذي يكتبه المستخدمون (نبذة عن متحدّث، أو عنوان جلسة كُتب بالإنجليزية في الصفحة العربية) قد يكون بأيّ من الاتجاهين. <code dir=\"ltr\">dir=&quot;auto&quot;</code> على العنصر تترك للمتصفّح أن يختار الاتجاه من أول حرف قوي الاتجاه، و<code dir=\"ltr\">&lt;bdi&gt;</code> يعزل اسمًا داخل جملة حتى لا تقفز علامات الترقيم إلى الجهة الخاطئة.</p>\n</aside>\n<h2 id=\"sec-6\" tabindex=\"-1\">دورك الآن</h2>\n<p>بطاقة التمرين مكتوبة بخصائص فيزيائية. حوّلها إلى خصائص منطقية واعكس السهم في RTL. تعرض الفحوصات البطاقة في الاتجاهين. وبعدها ستستبدل الألوان السداسية (hex) في البطاقة بـ <code dir=\"ltr\">oklch()</code>، وتبني لوحات ألوان المسارات بـ <code dir=\"ltr\">color-mix()</code>.</p>\n","toc":[{"id":"sec-1","text":"محورا الـ inline والـ block","level":2},{"id":"sec-2","text":"تحويل بطاقة الجلسة","level":2},{"id":"sec-3","text":"الأحجام منطقية أيضًا","level":2},{"id":"sec-4","text":"ما لا ينعكس من تلقاء نفسه","level":2},{"id":"sec-5","text":"الخط العربي في قاعدتين","level":2},{"id":"sec-6","text":"دورك الآن","level":2}],"takeaways":["الخصائص المنطقية تصف التخطيط نسبةً إلى اتجاه النص: <code dir=\"ltr\">margin-inline-start</code> هي الـ margin اليسرى في الإنجليزية واليمنى في العربية.","ضبط <code dir=\"ltr\">dir=&quot;rtl&quot;</code> على الجذر يعكس flexbox وgrid والخصائص المنطقية تلقائيًا؛ أما الخصائص الفيزيائية مثل <code dir=\"ltr\">padding-left</code> فتبقى حيث هي.","الـ transforms ومواضع الخلفيات والظلال والأيقونات الاتجاهية لا تنعكس، لذا تعامل معها صراحةً بـ <code dir=\"ltr\">:dir(rtl)</code>.","لا تضف <code dir=\"ltr\">letter-spacing</code> إلى النص العربي أبدًا؛ فهي تقطع الوصل بين الحروف."],"further":[{"title":"Basic concepts of logical properties and values (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Logical_properties_and_values/Basic_concepts"},{"title":"Logical properties (web.dev Learn CSS)","url":"https://web.dev/learn/css/logical-properties"},{"title":"Structural markup and right-to-left text in HTML (W3C)","url":"https://www.w3.org/International/questions/qa-html-dir"}],"quiz":[{"q":"<p>لبطاقة <code dir=\"ltr\">padding-left: 20px; border-left: 6px solid</code>. ضبطت <code dir=\"ltr\">dir=&quot;rtl&quot;</code> على <code dir=\"ltr\">&lt;html&gt;</code>. أين أصبح الـ padding والحدّ الآن؟</p>","options":[{"text":"على اليمين، لأن المتصفّح يعكس التخطيط كله.","why":"المتصفّح يعكس التخطيط الواعي بالاتجاه (flex وgrid والخصائص المنطقية)، لكن <code dir=\"ltr\">left</code> تعني دائمًا اليسار الفيزيائي."},{"text":"ما زالا على اليسار، الذي أصبح الآن نهاية كل سطر.","why":"صحيح. الخصائص الفيزيائية تتجاهل الاتجاه. استخدم <code dir=\"ltr\">padding-inline-start</code> و<code dir=\"ltr\">border-inline-start</code> لتتبع النص."},{"text":"أُزيلا، لأن الخصائص الفيزيائية تُتجاهل في RTL.","why":"ما زالت تنطبق؛ لكنها تنطبق على الجهة الفيزيائية التي سمّيتها."}],"answer":1},{"q":"<p>في صف flex له <code dir=\"ltr\">justify-content: flex-start</code> داخل صفحة <code dir=\"ltr\">dir=&quot;rtl&quot;</code>، من أين تبدأ العناصر؟</p>","options":[{"text":"من اليسار، لأن flex-start هي الحافة اليسرى.","why":"بداية flexbox تتبع اتجاه السطر (inline)، لذا فالبداية في RTL هي الحافة اليمنى."},{"text":"من المنتصف، لأن flexbox لا يستطيع أن يقرّر.","why":"يحسم flexbox البداية والنهاية دائمًا من اتجاه الكتابة؛ ولا يلجأ إلى التوسيط أبدًا."},{"text":"يعتمد على ضبط <code dir=\"ltr\">flex-direction: row-reverse</code> من عدمه.","why":"row-reverse ستبادلهما من جديد، لكن مع القيمة الافتراضية <code dir=\"ltr\">row</code> الجواب محسوم أصلًا."},{"text":"من اليمين، لأن flex-start تتبع اتجاه السطر.","why":"صحيح. flexbox وgrid واعيان بالاتجاه من الأساس؛ ولهذا ينعكس معظم تخطيط flex مجانًا."}],"answer":3},{"q":"<p>لرابط «Details →» أيقونة سهم يجب أن تشير إلى الاتجاه المعاكس في العربية. أيّ قاعدة تحقّق ذلك؟</p>","options":[{"text":"<code dir=\"ltr\">.arrow:dir(rtl) { scale: -1 1; }</code>","why":"صحيح. <code dir=\"ltr\">:dir(rtl)</code> تطابق العناصر التي اتجاهها المحسوب RTL، والتحجيم الأفقي السالب يعكس الأيقونة."},{"text":"<code dir=\"ltr\">.arrow { margin-inline-start: 4px; }</code>","why":"هذا ينقل المسافة إلى الجهة الصحيحة، وهذا جيد، لكنه لا يغيّر الاتجاه الذي يشير إليه السهم."},{"text":"<code dir=\"ltr\">.arrow { direction: rtl; }</code>","why":"<code dir=\"ltr\">direction</code> تغيّر اتجاه النص والتخطيط، لا طريقة رسم الحرف أو الأيقونة."}],"answer":0},{"q":"<p>أيّ تصريح يضبط عرض بطاقة الجلسة بطريقة تعمل أيضًا في أنماط الكتابة الرأسية؟</p>","options":[{"text":"<code dir=\"ltr\">width: 20rem</code>","why":"<code dir=\"ltr\">width</code> أفقية دائمًا؛ وفي نمط الكتابة الرأسي يمتدّ محور الـ inline من الأعلى إلى الأسفل."},{"text":"<code dir=\"ltr\">block-size: 20rem</code>","why":"حجم الـ block هو الارتفاع في الكتابة الأفقية، أي البُعد العابر للأسطر لا الممتدّ على طولها."},{"text":"<code dir=\"ltr\">inline-size: 20rem</code>","why":"صحيح. <code dir=\"ltr\">inline-size</code> هو الحجم على امتداد سير النص، فهو العرض في الإنجليزية والعربية، والارتفاع في النص الرأسي."}],"answer":2}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<div class=\"wrap\" dir=\"ltr\">\n  <article class=\"session-card\">\n    <span class=\"time\">09:30</span>\n    <h3>Logical Properties for Real Products</h3>\n    <a class=\"more\" href=\"#details\">Details <span class=\"arrow\" aria-hidden=\"true\">→</span></a>\n  </article>\n</div>","css":".wrap { width: 360px; }\n.session-card {\n  padding-top: 12px;\n  padding-bottom: 12px;\n  border-radius: 12px;\n  background: #f8fafc;\n}\n.session-card h3 { margin: 8px 0; }\n\n.session-card {\n  border-left: 6px solid #6d28d9;\n  padding-left: 20px;\n  padding-right: 8px;\n  text-align: left;\n}\n.time {\n  display: inline-block;\n  margin-right: 12px;\n  color: #6b7280;\n}\n.more {\n  display: block;\n  text-align: right;\n}\n.arrow {\n  display: inline-block;\n  margin-left: 4px;\n}\n"},"solution":{"html":"<div class=\"wrap\" dir=\"ltr\">\n  <article class=\"session-card\">\n    <span class=\"time\">09:30</span>\n    <h3>Logical Properties for Real Products</h3>\n    <a class=\"more\" href=\"#details\">Details <span class=\"arrow\" aria-hidden=\"true\">→</span></a>\n  </article>\n</div>","css":".wrap { width: 360px; }\n.session-card {\n  padding-top: 12px;\n  padding-bottom: 12px;\n  border-radius: 12px;\n  background: #f8fafc;\n}\n.session-card h3 { margin: 8px 0; }\n\n.session-card {\n  border-inline-start: 6px solid #6d28d9;\n  padding-inline: 20px 8px;\n  text-align: start;\n}\n.time {\n  display: inline-block;\n  margin-inline-end: 12px;\n  color: #6b7280;\n}\n.more {\n  display: block;\n  text-align: end;\n}\n.arrow {\n  display: inline-block;\n  margin-inline-start: 4px;\n}\n.arrow:dir(rtl) {\n  scale: -1 1;\n}\n"},"checks":[{"id":"ltr-unchanged","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('ltr'); return px('.session-card', 'border-left-width') === 6 && px('.session-card', 'border-right-width') === 0 && px('.session-card', 'padding-left') === 20 && px('.time', 'margin-right') === 12 && !flipped();"},{"id":"rtl-border","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('rtl'); let ok = false; try { ok = (px('.session-card', 'border-right-width') === 6 && px('.session-card', 'border-left-width') === 0 && style('.session-card', 'border-right-color') === 'rgb(109, 40, 217)'); } finally { await setDir('ltr'); } return ok;"},{"id":"rtl-padding","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('rtl'); let ok = false; try { ok = (px('.session-card', 'padding-right') === 20 && px('.session-card', 'padding-left') === 8); } finally { await setDir('ltr'); } return ok;"},{"id":"rtl-time-gap","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('rtl'); let ok = false; try { ok = (px('.time', 'margin-left') === 12 && px('.time', 'margin-right') === 0); } finally { await setDir('ltr'); } return ok;"},{"id":"rtl-link-aligned","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('rtl'); let ok = false; try { ok = (['end', 'left'].includes(style('.more', 'text-align')) && px('.arrow', 'margin-right') === 4); } finally { await setDir('ltr'); } return ok;"},{"id":"rtl-arrow-flips","test":"const setDir = async (d) => { $('.wrap').setAttribute('dir', d); await tick(16); }; const px = (sel, p) => parseFloat(style(sel, p)); const flipped = () => style('.arrow', 'scale') === '-1 1' || style('.arrow', 'transform').startsWith('matrix(-1'); await setDir('rtl'); let ok = false; try { ok = (flipped()); } finally { await setDir('ltr'); } return ok;"}],"title":"اجعل البطاقة تعمل من اليمين إلى اليسار","prompt":"<p>البطاقة مكتوبة بخصائص فيزيائية، لذا تنكسر حين يتحوّل الغلاف إلى <code dir=\"ltr\">dir=&quot;rtl&quot;</code>. دون تغيير الـ HTML:</p>\n<ul>\n<li>استبدل الحدّ الأيسر، والـ padding الأيسر والأيمن، والـ margin اليمنى للوقت، وقيم <code dir=\"ltr\">text-align</code>، والـ margin اليسرى للسهم بنظائرها <strong>المنطقية</strong>، بحيث تبدو النسخة الإنجليزية كما هي تمامًا.</li>\n<li>في RTL اعكس أيقونة السهم أفقيًا (استخدم <code dir=\"ltr\">:dir(rtl)</code>).</li>\n</ul>\n<p>تعرض الفحوصات البطاقة في الاتجاهين.</p>\n","hints":["<code dir=\"ltr\">border-left</code> تصبح <code dir=\"ltr\">border-inline-start</code>؛ و<code dir=\"ltr\">margin-right</code> تصبح <code dir=\"ltr\">margin-inline-end</code>.","<code dir=\"ltr\">text-align: left</code> تصبح <code dir=\"ltr\">start</code> و<code dir=\"ltr\">right</code> تصبح <code dir=\"ltr\">end</code>. و<code dir=\"ltr\">padding-inline</code> تأخذ قيمة للبداية وأخرى للنهاية.","للأيقونة: <code dir=\"ltr\">.arrow:dir(rtl) { scale: -1 1; }</code> (أو <code dir=\"ltr\">transform: scaleX(-1)</code>)."],"explanation":"<p>الخصائص المنطقية تُحسم بحسب اتجاه العنصر، فتكون <code dir=\"ltr\">border-inline-start</code> هي الحدّ الأيسر في الإنجليزية والأيمن في العربية، والأمر نفسه مع <code dir=\"ltr\">padding-inline</code> و<code dir=\"ltr\">margin-inline-end</code> و<code dir=\"ltr\">text-align: start/end</code>. يبقى العرض الإنجليزي كما هو، وتبديل <code dir=\"ltr\">dir</code> يعكس البطاقة دون أيّ قواعد إضافية. والأيقونات الاتجاهية هي الاستثناء: الرسم لا يعرف إلى أين يجب أن يشير، لذا تطابق <code dir=\"ltr\">:dir(rtl)</code> السهم حين يكون اتجاهه الموروث من اليمين إلى اليسار، و<code dir=\"ltr\">scale: -1 1</code> تعكسه.</p>\n","checkLabels":{"ltr-unchanged":"في الإنجليزية تبدو البطاقة تمامًا كما كانت","rtl-border":"في RTL يقع الحدّ الملوّن على اليمين","rtl-padding":"في RTL يتبع الـ padding اتجاه النص","rtl-time-gap":"في RTL تقع المسافة التي تلي الوقت على يساره","rtl-link-aligned":"في RTL يُحاذى الرابط إلى النهاية وتنعكس مسافة السهم","rtl-arrow-flips":"في RTL يُعكس السهم"}},"words":721,"readMinutes":4}