
في هذا المقال، سنتناول مشكلة شائعة في تصميم واجهات المستخدم لتطبيقات React.js: كيفية منع التمرير في الشريط الجانبي (Sidebar) أو التحكم فيه بفعالية. يعد الشريط الجانبي مكونًا أساسيًا في العديد من التطبيقات، وتوفير تجربة مستخدم سلسة عند التفاعل معه أمر بالغ الأهمية. سنقدم حلولًا عملية تعتمد على CSS و React State لمعالجة هذه المشكلة.
فهم المشكلة الأساسية
غالبًا ما تواجه التطبيقات التي تحتوي على أشرطة جانبية مشكلات في التمرير عندما يكون المحتوى الرئيسي للصفحة قابلاً للتمرير أيضًا. قد يؤدي ذلك إلى ظهور أشرطة تمرير متعددة، أو تداخل في المحتوى، أو تجربة مستخدم مربكة. الهدف هو جعل الشريط الجانبي ثابتًا أو التحكم في تمريره بشكل مستقل عن المحتوى الرئيسي، أو حتى منعه تمامًا في سياقات معينة، مثل عند فتح نافذة منبثقة (Modal).
الحلول المستندة إلى CSS
تعتبر خصائص CSS مثل position: fixed; و position: sticky; من الأدوات القوية للتحكم في سلوك التمرير للعناصر.
استخدام position: fixed;
تعد خاصية position: fixed; الحل الأكثر شيوعًا لجعل الشريط الجانبي ثابتًا في مكانه بغض النظر عن تمرير الصفحة. يتم وضع العنصر بالنسبة لإطار العرض (viewport).
ملاحظة: عند استخدام position: fixed;، يخرج العنصر من تدفق المستند العادي، مما قد يتطلب تعديل هوامش أو حشوات المحتوى الرئيسي لتجنب التداخل.
.sidebar {
position: fixed;
top: 0;
left: 0; /* أو right: 0; إذا كان الشريط الجانبي على اليمين */
width: 250px; /* عرض الشريط الجانبي */
height: 100vh; /* يمتد على كامل ارتفاع إطار العرض */
background-color: #f0f0f0;
overflow-y: auto; /* يسمح بالتمرير داخل الشريط الجانبي إذا كان محتواه طويلاً */
z-index: 1000; /* يضمن ظهوره فوق المحتوى الآخر */
}
.main-content {
margin-left: 250px; /* يعوض عرض الشريط الجانبي لتجنب التداخل */
padding: 20px;
}
في مكون React، يمكنك تطبيق هذه الفئات:
import React from 'react';
import './Sidebar.css';
function App() {
return (
<div>
<div className="sidebar">
<h3>قائمة الشريط الجانبي</h3>
<ul>
<li>الرئيسية</li>
<li>المنتجات</li>
<li>الخدمات</li>
<li>اتصل بنا</li>
{/* أضف المزيد من العناصر لجعلها قابلة للتمرير */}
<li>عن الشركة</li>
<li>المدونة</li>
<li>الدعم</li>
<li>الإعدادات</li>
<li>الملف الشخصي</li>
<li>الخروج</li>
</ul>
</div>
<div className="main-content">
<h1>المحتوى الرئيسي للصفحة</h1>
<p>هنا يظهر المحتوى الرئيسي الذي يمكن أن يكون طويلاً جدًا وقابلاً للتمرير بشكل مستقل عن الشريط الجانبي.</p>
{/* أضف المزيد من المحتوى لجعل الصفحة قابلة للتمرير */}
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
</div>
</div>
);
}
export default App;
استخدام position: sticky;
تسمح خاصية position: sticky; للعنصر بأن يتصرف كـ position: relative; حتى يصل إلى عتبة تمرير معينة، ثم يصبح position: fixed;. هذا مفيد إذا كنت تريد أن يظل الشريط الجانبي جزءًا من تدفق المستند حتى يبدأ التمرير، ثم يلتصق بالجزء العلوي (أو السفلي) من إطار العرض.
تحذير! لكي يعمل position: sticky;، يجب أن يكون للعنصر الأصل (parent) الذي يحتوي على الشريط الجانبي خاصية overflow غير visible، ويجب تحديد إزاحة (offset) مثل top أو bottom.
.sidebar-container {
/* يجب أن يكون العنصر الأصل قابلاً للتمرير أو يحتوي على ارتفاع محدد */
height: 100vh; /* مثال */
overflow-y: auto; /* مثال */
display: flex; /* مثال لتخطيط مرن */
}
.sidebar {
position: sticky;
top: 0; /* يلتصق بالجزء العلوي من إطار العرض عند التمرير */
width: 250px;
height: fit-content; /* أو ارتفاع محدد */
background-color: #e0e0e0;
padding: 20px;
flex-shrink: 0; /* يمنع الشريط الجانبي من التقلص في flex container */
}
.main-content {
flex-grow: 1; /* يسمح للمحتوى الرئيسي بشغل المساحة المتبقية */
padding: 20px;
}
التحكم الديناميكي باستخدام React State
في بعض السيناريوهات، قد تحتاج إلى منع التمرير في الشريط الجانبي (أو حتى الصفحة بأكملها) بناءً على حالة التطبيق، مثل عند فتح نافذة منبثقة أو قائمة جانبية (off-canvas menu). يمكن تحقيق ذلك باستخدام React State و useEffect لتعديل خصائص CSS ديناميكيًا.
منع تمرير الصفحة بأكملها
لإيقاف تمرير الصفحة بأكملها (بما في ذلك الشريط الجانبي إذا كان جزءًا من تدفق المستند أو كان قابلاً للتمرير بشكل مستقل)، يمكنك تطبيق overflow: hidden; على عنصر <body>.
import React, { useState, useEffect } from 'react';
import './Sidebar.css'; // تأكد من وجود CSS للشريط الجانبي
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
useEffect(() => {
if (isModalOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset'; // أو 'auto'
}
// تنظيف التأثير عند إلغاء تحميل المكون أو تغيير isModalOpen
return () => {
document.body.style.overflow = 'unset';
};
}, [isModalOpen]);
return (
<div>
<div className="sidebar">
<h3>قائمة الشريط الجانبي</h3>
<ul>
<li>الرئيسية</li>
<li>المنتجات</li>
<li>الخدمات</li>
</ul>
<button onClick={() => setIsModalOpen(true)}>افتح النافذة المنبثقة</button>
</div>
<div className="main-content">
<h1>المحتوى الرئيسي للصفحة</h1>
<p>هذا هو المحتوى الرئيسي.</p>
{/* أضف محتوى طويلاً هنا */}
</div>
{isModalOpen && (
<div className="modal-overlay">
<div className="modal-content">
<h2>نافذة منبثقة</h2>
<p>هذا هو محتوى النافذة المنبثقة.</p>
<button onClick={() => setIsModalOpen(false)}>إغلاق</button>
</div>
</div>
)}
</div>
);
}
export default App;
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 2000;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
max-width: 500px;
width: 90%;
}
معلومة!
عند استخدام document.body.style.overflow = 'hidden';، قد تلاحظ "قفزة" في المحتوى إذا كان هناك شريط تمرير مرئي في الأصل، لأن إزالته قد تغير عرض المحتوى. يمكن معالجة ذلك بإضافة padding-right مكافئ لعرض شريط التمرير.
أفضل الممارسات والاعتبارات
- الاستجابة (Responsiveness): تأكد من أن الشريط الجانبي يعمل بشكل جيد على مختلف أحجام الشاشات. قد تحتاج إلى إخفاء الشريط الجانبي تمامًا على الأجهزة المحمولة أو تحويله إلى قائمة "هامبرغر".
- إمكانية الوصول (Accessibility): عند منع التمرير، تأكد من أن المستخدمين الذين يعتمدون على لوحة المفاتيح أو قارئات الشاشة لا يزال بإمكانهم التنقل في التطبيق. ركز على إدارة التركيز (focus management) عند فتح وإغلاق النوافذ المنبثقة.
- الأداء (Performance): تجنب التغييرات المتكررة على خصائص CSS التي تؤثر على التخطيط (layout) أو الرسم (paint) لتحسين الأداء.
ما الفرق الرئيسي بين position: fixed; و position: sticky; للشريط الجانبي؟
position: fixed; يثبت العنصر بالنسبة لإطار العرض (viewport) بشكل دائم، بغض النظر عن التمرير. أما position: sticky; فيجعل العنصر يتبع تدفق المستند حتى يصل إلى عتبة تمرير معينة (مثل top: 0;)، ثم يصبح ثابتًا بالنسبة لإطار العرض.
كيف يمكنني منع تمرير الصفحة بأكملها عند فتح نافذة منبثقة في React؟
يمكنك استخدام useEffect في مكون React لتعديل خاصية overflow لعنصر document.body. عندما تكون النافذة المنبثقة مفتوحة، قم بتعيين document.body.style.overflow = 'hidden';، وعند إغلاقها، أعدها إلى 'unset' أو 'auto'.
المشاركات ذات الصلة
المقال الأصلي:
إيقاف التمرير في الشريط الجانبي في React.js: حلول عملية
المصدر: صِوان AI
شكر خاص لـ GEMINI و جمال الحزازي.