محمد قتيبة شيخانيأبني. أستكشف. أشارك

10من 22

تطوير الويب

التصميم المتجاوب: موقعٌ يليق بكل شاشة

صفحة مدوّنةٍ تجريبيّة مصوّرة مرّتين. في اليسار على شاشةٍ عرضها 1280 بكسلًا: عنوانٌ وفقرات وقائمة، وتحتها ثلاث بطاقات HTML وCSS وJavaScript في صفٍّ واحد. وفي اليمين على هاتفٍ عرضه 390 بكسلًا: البطاقات الثلاث بعضها فوق بعض. وتحت الصورتين عنوان المقالة «التصميم المتجاوب».

في آب 2026 جاءت 60.4% من زيارات الويب في سوريا من الهاتف، و59.7% في السعوديّة، ونحو 51% في ألمانيا. أمّا في الولايات المتّحدة فما زال الحاسوب في المقدّمة بـ55.6%، وفي العالم كلّه يتقاسم الجهازان الزيارات تقريبًا بالتساوي.[1] فالزائر الذي تكتب له قد يفتح صفحتك على شاشةٍ عرضها 390 بكسلًا في حلب، أو على شاشة مكتبٍ عريضة في برلين، وعلى صفحتك أن تعمل في الحالتين.

والصفحة التي كسوتها في مقال CSS جميلةٌ على الحاسوب، لكنّك لم تسأل بعد كيف تبدو على الهاتف. هذا المقال يجيب: ستعرف فكرة التصميم المتجاوب وأركانه الثلاثة، والسطر الذي لا يعمل شيءٌ على الهاتف من دونه. ثمّ تعرف أدوات 2026 التي لا تذكرها أكثر الشروح العربيّة، مثل استعلامات الحاوية والدالّة clamp()، وكيف يتصرّف كلّ ذلك في صفحةٍ عربيّة تُقرأ من اليمين.

ما هو التصميم المتجاوب؟

حين انتشرت الهواتف الذكيّة الأولى كانت المواقع مبنيّةً لشاشات المكتب، فكان الزائر يقرّب بإصبعين ليقرأ سطرًا ثمّ يبعّد ليجد الرابط التالي. وكان الحلّ الشائع يومها موقعين منفصلين، واحدٌ للحاسوب وآخر للهاتف على عنوانٍ مثل m.example.com، يحوّل إليه الخادم كلّ من يأتي من هاتف. فتضاعفت الصيانة، إذ يُكتب كلّ مقالٍ ويُصلَح كلّ خطأ مرّتين، وصار للصفحة الواحدة عنوانان.

وفي 25 أيّار 2010 نشر المصمّم إيثان ماركوت مقالًا في مجلّة A List Apart سمّاه «Responsive Web Design»، واقترح فيه موقعًا واحدًا يتكيّف مع الشاشة التي يُعرض عليها. وحدّد له ثلاثة مكوّنات تقنيّة: شبكةٌ مرنة، وصورٌ مرنة، واستعلامات وسائط، وقال إنّها تحتاج معها طريقة تفكيرٍ مختلفة أيضًا.[2] فالصفحة هي نفسها بعنوانها وملفّاتها، وCSS هي التي تغيّر ترتيبها بحسب عرض الشاشة.

واليوم تعدّ Google ثلاث طرقٍ لموقعٍ يناسب الهاتف: التصميم المتجاوب، والخدمة الديناميكيّة التي ترسل HTML مختلفة على العنوان نفسه، والعناوين المنفصلة، وتوصي بالأولى صراحةً لأنّها الأسهل تنفيذًا وصيانة.[3] وفي 31 تشرين الأوّل 2023 أعلنت أنّ انتقالها إلى الفهرسة بعين الهاتف قد اكتمل، أي أنّها تقرأ صفحتك كما يراها زائر الهاتف.[4] فإن نقص شيءٌ من نسخة الهاتف، فقد نقص من صفحتك في نظر محرّك البحث أيضًا.

السطر الأوّل: وسم viewport

ابدأ بالسطر الذي يعطّل كلّ ما بعده إن غاب. فحين يفتح متصفّح الهاتف صفحةً لا تقول شيئًا عن نفسها، يفترض أنّها صُمّمت للحاسوب، فيرسمها في منطقة عرضٍ افتراضيّة عرضها 980 بكسلًا ثمّ يصغّرها لتدخل الشاشة. وتنبّه MDN إلى النتيجة: استعلامات الوسائط التي كتبتها للشاشات الضيّقة لا تعمل أبدًا، لأنّ المتصفّح يخبرها أنّ العرض 980.[5]

والحلّ سطرٌ واحد في head، وهو موجودٌ في صفحتك منذ مقال HTML:

<meta name="viewport" content="width=device-width, initial-scale=1">

الجزء width=device-width يقول للمتصفّح: اجعل عرض الصفحة عرض الجهاز الفعليّ، 390 بكسلًا مثلًا. والجزء initial-scale=1 يبدأ بلا تكبيرٍ ولا تصغير. والصورة التالية الصفحة نفسها على هاتفٍ واحد، مرّةً من دون السطر ومرّةً معه.

صفحة المدوّنة نفسها مرّتين على شاشة هاتفٍ بعرض 390 بكسلًا. في اليمين من دون وسم viewport: الصفحة كلّها مصغّرة كأنّها شاشة حاسوب، والنصّ صغيرٌ لا يُقرأ، والبطاقات الثلاث متجاورة. وفي اليسار مع الوسم: العنوان والروابط والفقرات بحجمٍ مقروء في عمودٍ واحد، وأوّل بطاقةٍ تبدأ تحت القائمة.
صفحة المشروع على هاتفٍ بعرض 390 بكسلًا. في اليمين من دون وسم viewport: رسمها المتصفّح بعرض 980 ثمّ صغّرها، فالنصّ لا يُقرأ والبطاقات متجاورة. وفي اليسار مع الوسم: عمودٌ واحد بخطٍّ مقروء. صورة من جهازي بمحاكاة هاتفٍ في Chrome.

وستجد في بعض الشيفرات القديمة إضافاتٍ مثل user-scalable=no أو maximum-scale=1 لمنع التكبير. لا تنسخها. فهي تمنع الزائر من تكبير النصّ بإصبعيه، وتقول MDN إنّ هذا يحرم ضعاف البصر من قراءة الصفحة وفهمها.[5]

الركن الأوّل: تخطيطٌ مرن

كان كثيرٌ من مواقع العقد الأوّل من الألفيّة يُبنى صندوقًا بعرضٍ ثابت، width: 960px مثلًا، لأنّ شاشات المكاتب كانت متقاربة. فإذا فُتح الصندوق على هاتفٍ عرضه 390، إمّا صغّره المتصفّح حتّى يضيع النصّ، وإمّا فاض خارج الشاشة، فاحتاج الزائر أن يمرّر أفقيًّا ليقرأ كلّ سطر. والتمرير الأفقيّ في صفحة مقالٍ علامةٌ على أنّ شيئًا فيها مكسور.

والتخطيط المرن يبدأ بأن تترك العرض الثابت. فالقاعدة التي كتبتها في مقال CSS، max-inline-size: 46rem، تقول: لا تتجاوز هذا العرض، وإن ضاقت الشاشة فاضق معها. ثمّ تأتي أداتا التخطيط اللتان تعرّفت إليهما هناك، ففي Flexbox تسمح flex-wrap: wrap للعناصر بأن تنزل إلى سطرٍ جديد حين لا يتّسع لها السطر، فلا تنضغط ولا تفيض.

وفي Grid سطرٌ واحد يكاد يغنيك عن استعلامات الوسائط في قوائم البطاقات:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1rem;
}

اقرأه من الداخل. الدالّة minmax() تقول إنّ العمود لا يضيق عن 12rem، وإن زادت المساحة تقاسمها مع جيرانه بالتساوي. والكلمة auto-fit تجعل المتصفّح يضع من الأعمدة ما يتّسع له العرض، ثمّ يطوي الأعمدة الفارغة.[6] فعلى شاشةٍ واسعة تقف البطاقات الثلاث في صفّ، وعلى الهاتف تنزل كلّ بطاقةٍ تحت أختها، من غير أيّ شرطٍ تكتبه أنت.

وإن أردت هيكل صفحةٍ كاملًا بمحتوًى وشريطٍ جانبيّ، فاكتب له عمودًا واحدًا للهاتف، ثمّ عمودين للشاشة الواسعة مثل grid-template-columns: 3fr 1fr. وهنا يظهر ما تعلّمته في مقال CSS عن الاتّجاه. فتقول MDN إنّ خطّ الشبكة الأوّل يقع على اليمين حين يكون الاتّجاه rtl، فيقف المحتوى في العمود الأوّل على اليمين والشريط الجانبيّ على اليسار.[7] ولا تحتاج صفحتك العربيّة لذلك أيّ سطرٍ إضافيّ.

شكل 1 الشبكة نفسها على شاشتين صفحةٌ واحدة بعرضين. في اليمين الهاتف بعمودٍ واحد 1fr: الترويسة ثمّ المحتوى المميّز ثمّ الجانب ثمّ التذييل، بعضها فوق بعض. وفي اليسار شاشةٌ واسعة بعمودين 3fr 1fr في صفحةٍ عربيّة: الترويسة والتذييل بعرض الصفحة، والمحتوى المميّز في العمود الأوّل على اليمين، والجانب في العمود الثاني على اليسار. الهاتف الترويسة المحتوى الجانب التذييل 1fr شاشةٌ واسعة الترويسة المحتوى الجانب التذييل 3fr 1fr العمود الأوّل على اليمين الشبكة نفسها على شاشتين صفحةٌ واحدة بعرضين. في الأعلى الهاتف بعمودٍ واحد 1fr: الترويسة ثمّ المحتوى المميّز ثمّ الجانب ثمّ التذييل. وفي الأسفل شاشةٌ واسعة بعمودين 3fr 1fr في صفحةٍ عربيّة: المحتوى المميّز في العمود الأوّل على اليمين، والجانب على اليسار. الهاتف الترويسة المحتوى الجانب التذييل 1fr شاشةٌ واسعة الترويسة المحتوى الجانب التذييل 3fr 1fr العمود الأوّل على اليمين
هيكلٌ واحد بعرضين: على الهاتف عمودٌ واحد، وعلى الشاشة الواسعة عمودان 3fr 1fr، والمحتوى في العمود الأوّل على اليمين لأنّ الصفحة عربيّة.

الركن الثاني: وسائط مرنة

النصّ يلتفّ من تلقاء نفسه، أمّا الصورة فلها عرضٌ ثابت. فصورةٌ عرضها 1200 بكسل في عمودٍ عرضه 342 تفيض خارج الشاشة وتعيد إليك التمرير الأفقيّ. والعلاج قاعدةٌ قصيرة تضعها مرّةً واحدة في ملفّك:

img, video {
  max-inline-size: 100%;
  block-size: auto;
}

القيمة max-inline-size: 100% تقول: لا تتجاوز عرض حاويتك. فالصورة الكبيرة تصغر لتدخل العمود، والأيقونة الصغيرة تبقى بحجمها ولا تُمطّ. وهذا هو الفرق بينها وبين width: 100% التي تمطّ كلّ صورةٍ إلى عرض حاويتها ولو كانت صغيرة. أمّا block-size: auto فيحسب الارتفاع من العرض الجديد، فتبقى نسبة الصورة كما هي ولا تبدو مضغوطة.

لكنّ القاعدة لا تمنع مشكلةً ثانية. فإن لم يعرف المتصفّح أبعاد الصورة قبل تنزيلها، رسم الصفحة من دونها، ثمّ دفع كلّ ما تحتها إلى الأسفل حين وصلت، فيفقد القارئ السطر الذي كان يقرؤه. وتضع Google الصور والفيديو بلا أبعاد في أوّل أسباب هذا القفز، وتنصحك بأن تكتب السمتين width وheight على كلّ صورةٍ دائمًا، أو أن تحجز المساحة بالخاصّيّة aspect-ratio.[8] والسمتان لا تثبّتان حجم الصورة، فقاعدة CSS ما زالت تصغّرها، لكنّهما تخبران المتصفّح بنسبتها مسبقًا.

وهذا القفز يقيسه مؤشّر CLS الذي شرحته سلسلة تحسين الظهور في مقال مؤشّرات أداء الويب، فهو يمسّ تجربة القارئ وتقييم الصفحة معًا.

وتبقى مسألة الحجم الذي ينزّله الهاتف، فالقاعدة السابقة تصغّر الصورة على الشاشة، لكنّ المتصفّح ينزّل الملفّ الكبير نفسه، فيدفع زائر الهاتف ثمن صورةٍ صُمّمت لشاشةٍ لن يراها. والسمتان srcset وsizes تعطيان المتصفّح عدّة نسخٍ ومعلومةً عن عرض الصورة في الصفحة، فيختار أصغر نسخةٍ تكفي.[9]

<img src="photo-800.jpg"
     srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
     sizes="(min-width: 48rem) 46rem, 100vw"
     width="1600" height="900"
     alt="وصف الصورة">

في srcset ثلاث نسخٍ بعروضها الحقيقيّة، وفي sizes تقول للمتصفّح: على الشاشات التي عرضها 48rem أو أكثر تُعرض الصورة بعرض 46rem، وعلى ما دونها بعرض النافذة كلّها. فيحسب هو العرض الفعليّ بالبكسل، ويضيف إليه كثافة شاشة الهاتف، ثمّ يختار. ولا تنسَ alt، فهو ما يسمعه مستخدم قارئ الشاشة بدل الصورة.

الركن الثالث: استعلامات الوسائط

الركنان السابقان يجعلان الصفحة تتمدّد وتنكمش، واستعلامات الوسائط تجعلها تغيّر ترتيبها عند عرضٍ تختاره أنت. والاستعلام شرطٌ في CSS: إن تحقّق طُبّقت القواعد التي داخله، وإلّا تجاهلها المتصفّح. هكذا يُكتب اليوم:

@media (width >= 48rem) {
  body {
    padding: 2.5rem;
  }
}

وستقرأ في أكثر الشيفرات الصيغة الأقدم (min-width: 48rem)، وهي تعني الشيء نفسه. أمّا صيغة المدى الجديدة فتقرؤها كما تقرأ المعادلة، وتذكر MDN أنّ (width <= 1250px) مثلًا مكافئةٌ تمامًا لـ(max-width: 1250px).[10]

والطريقة التي أنصحك بها اسمها «الهاتف أوّلًا». تكتب القواعد الأساسيّة للشاشة الضيّقة، فتكون هي الافتراض، ثمّ تضيف بشرط width >= ما تحتاجه الشاشات الأوسع فقط. والطريقة المعاكسة تبدأ بتصميم الحاسوب ثمّ تنتزع منه للهاتف بشرط width <=، فتكتب قواعد تلغي قواعد، ويكبر الملفّ بلا داعٍ. وللطريقة الأولى أثرٌ أعمق من ترتيب الشيفرة: الشاشة الصغيرة تجبرك على أن تقرّر ما الأهمّ في صفحتك، ثمّ تضيف للشاشة الكبيرة ولا تحشر.

أمّا الأرقام فلا تبحث عن قائمة أجهزة. فالهواتف تتغيّر كلّ عام، ومحتواك وحده ثابت. وسّع النافذة ببطء، وحين يبدأ تخطيطك يبدو سيّئًا، ضع هناك نقطة توقّف، أي العرض الذي يتغيّر عنده الترتيب. واكتب هذه النقاط بوحدة rem لا بالبكسل، فتتحرّك مع حجم الخطّ الذي يختاره الزائر في متصفّحه.

والاستعلامات تسأل عن أكثر من العرض. فالشرط prefers-color-scheme: dark يعرف أنّ الزائر اختار الوضع الداكن في نظامه، فتعطيه ألوانًا داكنة تلقائيًّا، والشرط hover: hover يعرف أنّ الجهاز فيه مؤشّرٌ يمرّ فوق العناصر. والشرط prefers-reduced-motion: reduce يعرف أنّ الزائر طلب من نظامه حركةً أقلّ، لأنّ الحركة الكثيرة تسبّب الدوار لبعض الناس، فتخفّف فيه حركاتك أو توقفها. والشروط الثلاثة متاحةٌ في المتصفّحات كلّها منذ سنوات: المؤشّر منذ كانون الأوّل 2018، واللون والحركة منذ كانون الثاني 2020.[11]

استعلامات الحاوية: المكوّن يقرأ مكانه

استعلامات الوسائط تسأل عن الشاشة كلّها، وهذا لا يكفي أحيانًا. خذ بطاقة مقالٍ فيها صورةٌ ونصّ. في عمود المحتوى العريض تريد الصورة بجانب النصّ، وفي الشريط الجانبيّ الضيّق تريدها فوقه، والشاشة في الحالتين واحدة. فالسؤال الصحيح هنا عن عرض المكان الذي وُضعت فيه البطاقة، واستعلامات الحاوية تسأله:

.card-slot {
  container-type: inline-size;
}

@container (width >= 30rem) {
  .card {
    display: flex;
    gap: 1rem;
  }
}

السطر الأوّل يجعل العنصر الأب حاويةً تُقاس، والشرط الثاني يسأل عن عرضها هي. فإن كانت الحاوية 30rem أو أكثر وقفت الصورة بجانب النصّ، وإلّا بقيت فوقه. وكانت الشروح القديمة تصف هذه الميزة بأنّها المستقبل، لكنّها متاحةٌ في المتصفّحات كلّها منذ شباط 2023.[12]

شكل 2 المكوّن يقرأ حاويته البطاقة نفسها في حاويتين. في اليمين حاويةٌ عريضة، والصورة في البطاقة المميّزة على اليمين بجانب أسطر النصّ، وتحتها الشرط ‎@container (width >= 30rem). وفي اليسار حاويةٌ ضيّقة، والصورة فوق أسطر النصّ. حاويةٌ عريضة: الصورة بجانب النصّ @container (width >= 30rem) حاويةٌ ضيّقة: الصورة فوقه المكوّن يقرأ حاويته البطاقة نفسها في حاويتين. في الأعلى حاويةٌ عريضة، والصورة على اليمين بجانب أسطر النصّ، بشرط ‎@container (width >= 30rem). وفي الأسفل حاويةٌ ضيّقة، والصورة فوق أسطر النصّ. حاويةٌ عريضة: الصورة بجانب النصّ @container (width >= 30rem) حاويةٌ ضيّقة: الصورة فوقه
البطاقة نفسها في حاويتين: في الحاوية العريضة الصورة على اليمين بجانب النصّ، وفي الضيّقة الصورة فوقه. الشرط يسأل عن الحاوية، لا عن الشاشة.

والقاعدة العمليّة: استعمل استعلام الوسائط لهيكل الصفحة، واستعلام الحاوية للمكوّن الذي يتكرّر في أماكن مختلفة، مثل البطاقة والنموذج وصندوق البحث.

الخطوط والارتفاعات المرنة

في مقال CSS كتبت أحجام الخطوط بوحدة rem، لأنّها تتبع حجم الخطّ الذي يختاره الزائر، ويبقى أن يكبر العنوان الرئيس على الشاشة الواسعة ويصغر على الهاتف. وقد تغريك وحدة vw، وهي جزءٌ من مئة من عرض النافذة، لكنّها وحدها تجعل العنوان ضئيلًا على الهاتف وضخمًا على شاشة المكتب. والدالّة clamp() تحلّ هذا بثلاث قيم، أدنى ومفضّلة وأقصى:[13]

h1 {
  font-size: clamp(1.75rem, 1.25rem + 2vw, 2.5rem);
}

فالعنوان لا يصغر عن 1.75rem ولا يكبر عن 2.5rem، وبينهما ينمو مع عرض النافذة. وجمعت القيمة الوسطى rem مع vw عن قصد، فجزء rem يتبع إعداد الزائر، وجزء vw يتبع الشاشة. والدالّة متاحةٌ في المتصفّحات كلّها منذ تموز 2020.

وللارتفاع مشكلةٌ تخصّ الهاتف. فقسمٌ ترتفعه 100vh ليملأ الشاشة يختفي أسفله تحت شريط العنوان في متصفّح الهاتف، لأنّ هذا الشريط يظهر ويختفي أثناء التمرير. ولهذا جاءت ثلاث وحدات: svh للنافذة وهي في أصغر حالاتها، وlvh لأكبرها، وdvh التي تتغيّر معها. وتذكر MDN أنّ vh نفسها تساوي lvh.[14] وهذه الوحدات متاحةٌ في المتصفّحات كلّها منذ كانون الأوّل 2022، فإن أردت قسمًا يملأ شاشة الهاتف تمامًا فاكتب min-block-size: 100svh.

اللمس والمحتوى العنيد

التجاوب الحقيقيّ لا يقف عند العرض. فالهاتف يُستعمل بالإصبع، والإصبع أعرض من مؤشّر الفأرة بكثير. ويطلب معيار WCAG 2.2 في المستوى AA أن يكون الهدف الذي يُنقر 24 في 24 بكسل CSS على الأقلّ، أو أن يُترك حوله فراغٌ يكفي. ويرفع المستوى AAA الحدّ إلى 44 في 44.[15] فأعطِ الروابط والأزرار حشوةً تكفي، وباعد بين الروابط المتجاورة.

وتذكّر ما قلته في مقال CSS عن :hover، فالهاتف لا مؤشّر فيه يمرّ فوق شيء. فلا تخبّئ معلومةً لا تظهر إلّا عند التمرير، وإن احتجت تأثيرًا للمؤشّر فضعه داخل شرط @media (hover: hover)، فيظهر حيث يوجد مؤشّرٌ فقط.

ويبقى محتوًى لا يصغر مهما فعلت، مثل جدولٍ بأعمدةٍ كثيرة، أو سطر شيفرةٍ طويل. لا تضغطه ولا تتركه يفيض بالصفحة كلّها. ضعه في حاويةٍ عليها overflow-x: auto، فتتمرّر الحاوية وحدها أفقيًّا، ويبقى جسم الصفحة ثابتًا، وهذه الحيلة الصغيرة تنقذك من أكثر ما يكسر الصفحات على الهاتف.

قائمة التنقّل على الهاتف

في صفحة مشروعك ثلاثة روابط، وflex-wrap: wrap يكفيها: إن ضاق السطر نزل الرابط الأخير إلى سطرٍ ثانٍ. أمّا الموقع الذي في قائمته ثمانية روابط أو عشرة فيحتاج على الهاتف زرًّا يُظهر القائمة ويخفيها. ويسمّي دليل ممارسات ARIA في W3C هذا النمط «الإفصاح»، ويشترط أن يكون الزرّ عنصر button. وتحمل سمته aria-expanded القيمة true حين تظهر القائمة وfalse حين تختفي، فيعرف مستخدم قارئ الشاشة حالها.[16]

<nav>
  <button type="button" aria-expanded="false" aria-controls="main-menu">القائمة</button>
  <ul id="main-menu">
    <li><a href="/">الرئيسة</a></li>
    <li><a href="/about/">عن المدوّنة</a></li>
  </ul>
</nav>

واكتب على الزرّ كلمةً تُقرأ مثل «القائمة»، فالأيقونة وحدها لا تُقرأ لمن لا يرى الشاشة، ولا يفهمها كلّ زائر. ثمّ تخفي CSS القائمة على الشاشة الضيّقة، وتُظهرها بشرط width >= وتخفي الزرّ.

nav ul { display: none; }
nav button[aria-expanded="true"] + ul { display: block; }

@media (width >= 48rem) {
  nav button { display: none; }
  nav ul { display: flex; }
}

فالقاعدة الثانية تُظهر القائمة حين تصير قيمة aria-expanded ‏true، فتكون السمة نفسها مصدر الحقيقة للقارئ الآليّ وللتصميم معًا. ويبقى أن يبدّل شيءٌ هذه القيمة عند النقر، وهذا عمل JavaScript، وهو أوّل ما تكتبه في مقال JavaScript.

كيف تختبر من غير عشرة هواتف

في أدوات المطوّر التي عرفتها في مقال المتصفّح زرٌّ لوضع الجهاز، يعرض صفحتك بعرض هاتفٍ أو لوحٍ تختاره، ويحاكي اللمس ويغيّر العرض بالسحب. وتصفه Google نفسها بأنّه تقريبٌ أوّليّ، فهو لا يشغّل شيفرتك على معالج هاتف، ولا يريك بطء شبكة الهاتف الحقيقيّ كما هو.[17] فاختبر به وأنت تكتب، ثمّ افتح الصفحة على هاتفٍ حقيقيّ مرّةً قبل أن تنشر، وجرّب النقر على كلّ رابطٍ بإصبعك.

والفحص الأسرع من هذا كلّه أن تضيّق نافذة المتصفّح على حاسوبك ببطءٍ من أعرض عرضٍ إلى أضيقه، وتراقب الصفحة. فإن ظهر شريط تمريرٍ أفقيّ في أسفلها، فابحث عن العنصر الذي فاض، وغالبًا ستجده صورةً بلا قاعدة، أو جدولًا بلا حاوية، أو عنصرًا كُتب له عرضٌ بالبكسل.

التطبيق: صفحة المشروع على كلّ شاشة

افتح مجلّد my-first-site، وأضف إلى index.html داخل main، تحت المقالة، قسمًا فيه ثلاث بطاقات:

<section class="cards">
  <article class="card">
    <h3>HTML</h3>
    <p>الهيكل: ما في الصفحة.</p>
  </article>
  <article class="card">
    <h3>CSS</h3>
    <p>المظهر: كيف تبدو الصفحة.</p>
  </article>
  <article class="card">
    <h3>JavaScript</h3>
    <p>السلوك: ما تفعله الصفحة.</p>
  </article>
</section>

ثمّ أضف هذه القواعد في آخر style.css، تحت ما كتبته في المقال السابق:

nav ul {
  flex-wrap: wrap;
}

h1 {
  font-size: clamp(1.75rem, 1.25rem + 2vw, 2.5rem);
}

img {
  max-inline-size: 100%;
  block-size: auto;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 1rem;
  margin-block-start: 2rem;
}

.card {
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 0.5rem;
  background-color: #fff;
}

@media (width >= 48rem) {
  body {
    padding: 2.5rem;
  }
}

القاعدة الأولى تضيف إلى قاعدة nav ul القديمة سطرًا واحدًا، وهذا من الانسياب الذي عرفته: قاعدتان للمحدِّد نفسه تجتمعان، والتصريح الجديد يضاف إلى القديم. والثانية تجعل العنوان الرئيس ينمو مع الشاشة بين حدّين، والثالثة تحمي الصفحة من أيّ صورةٍ تضيفها لاحقًا. وقاعدة ‎.cards هي سطر Grid الذي قرأته في الركن الأوّل، والأخيرة تزيد الفراغ حول الصفحة على الشاشات الأوسع فقط.

احفظ الملفّين، وافتح الصفحة في المتصفّح، ثمّ ضيّق النافذة ببطء. ستقف البطاقات الثلاث في صفٍّ على الشاشة الواسعة، ثمّ تنزل واحدةً بعد أخرى كلّما ضاق العرض عن ثلاثة أعمدةٍ من 12rem، حتّى تصير عمودًا واحدًا على الهاتف.

صفحة المدوّنة بملفّ CSS واحد على شاشتين. في اليمين هاتفٌ بعرض 390 بكسلًا: البطاقات الثلاث HTML وCSS وJavaScript بعضها فوق بعض. وفي اليسار شاشةٌ بعرض 1280 بكسلًا: البطاقات الثلاث في صفٍّ واحد، والمحتوى في عمودٍ متوسّط.
صفحة المشروع بملفّ CSS واحد على شاشتين. في اليمين هاتفٌ بعرض 390 بكسلًا والبطاقات الثلاث بعضها فوق بعض، وفي اليسار شاشةٌ بعرض 1280 والبطاقات في صفٍّ واحد. صورة من جهازي، والهاتف بمحاكاة Chrome.

ولاحظ أنّك لم تكتب في هذا كلّه كلمة left ولا right، ولم تكتب لأعمدة البطاقات أيّ شرط. فالبطاقة الأولى تقف على اليمين لأنّ الصفحة عربيّة، والشبكة تقرّر عدد الأعمدة بنفسها، واستعلام الوسائط الوحيد في الملفّ يزيد فراغًا لا أكثر.

خلاصة عمليّة

ضع وسم viewport في كلّ صفحة، ولا تمنع التكبير. اكتب للهاتف أوّلًا، ثمّ أضف للشاشات الأوسع بشرط width >=، وضع نقاط التوقّف حيث ينكسر محتواك لا حيث تقول قائمة أجهزة، واكتبها بوحدة rem. اجعل الصور لا تتجاوز حاويتها، واكتب لها width وheight، وأعطها srcset وsizes إن كانت كبيرة. واستعمل Grid بالصيغة auto-fit وminmax للبطاقات، واستعلام الحاوية للمكوّن الذي يتنقّل، وclamp() للعناوين، وsvh للأقسام التي تملأ الشاشة. ثمّ اختبر بإصبعك على هاتفٍ حقيقيّ.

وصفحتك الآن تتكيّف مع كلّ شاشة، لكنّها لا تستجيب لشيءٍ يفعله الزائر غير التمرير. فزرّ القائمة الذي كتبته في هذا المقال ما زال ينتظر من يبدّل قيمته عند النقر، وهذا ما تبدأ به في مقال JavaScript.

المصادر

  1. موقع StatCounter، «Desktop vs Mobile vs Tablet Market Share»، آب 2026: العالم (الهاتف 49.34%، الحاسوب 49.11%)، وسوريا (60.39%)، والسعوديّة (59.67%)، وألمانيا (50.91%)، والولايات المتّحدة (الحاسوب 55.59%، الهاتف 42.26%).
  2. إيثان ماركوت، «Responsive Web Design»، مجلّة A List Apart، العدد 306، 25 أيّار 2010: الشبكات المرنة والصور المرنة واستعلامات الوسائط هي المكوّنات التقنيّة الثلاثة للتصميم المتجاوب.
  3. شركة Google، «Mobile site and mobile-first indexing best practices»: ثلاث طرق لموقعٍ يناسب الهاتف، التصميم المتجاوب والخدمة الديناميكيّة والعناوين المنفصلة، وتوصي Google بالأولى لأنّها الأسهل تنفيذًا وصيانة.
  4. شركة Google، «Mobile-first indexing has landed»، مدوّنة Search Central، 31 تشرين الأوّل 2023: اكتمل الانتقال إلى الفهرسة بعين الهاتف.
  5. موسوعة MDN، «The viewport meta tag»: قد يرسم متصفّح الهاتف الصفحة في منطقة عرضٍ افتراضيّة عرضها 980 بكسلًا ثمّ يصغّرها، فلا تعمل استعلامات الشاشات الضيّقة، ومنع التكبير بالقيمة user-scalable=no يحرم ضعاف البصر من قراءة الصفحة.
  6. موسوعة MDN، «repeat()»: الكلمة auto-fit تكرّر الأعمدة لتملأ المساحة ثمّ تطوي الأعمدة الفارغة.
  7. موسوعة MDN، «Grids, logical values, and writing modes»: مع direction: rtl يقع خطّ الشبكة الأوّل على الجانب الأيمن.
  8. موقع web.dev من Google، «Optimize Cumulative Layout Shift»: الصور والفيديو بلا أبعاد من أشيع أسباب قفز التخطيط، فضع السمتين width وheight دائمًا، أو احجز المساحة بالخاصّيّة aspect-ratio.
  9. موسوعة MDN، «Using responsive images in HTML»: السمتان srcset وsizes ووسم picture مدعومةٌ في متصفّحات الحاسوب والهاتف الحديثة.
  10. موسوعة MDN، «Using media queries»: صيغة المدى، و(width <= 1250px) مكافئةٌ لـ(max-width: 1250px).
  11. موسوعة MDN، «prefers-color-scheme» و«prefers-reduced-motion» (متاحتان منذ كانون الثاني 2020)، و«hover» (منذ كانون الأوّل 2018).
  12. موسوعة MDN، «Container size and style queries» و«@container»: container-type: inline-size، واستعلامات الحاوية متاحةٌ في المتصفّحات كلّها منذ شباط 2023.
  13. موسوعة MDN، «clamp()»: متاحةٌ منذ تموز 2020.
  14. موسوعة MDN، «<length>»: وحدات svh وlvh وdvh لمنطقة العرض الصغرى والكبرى والمتغيّرة، وvh تساوي lvh. وموقع webstatus.dev: متاحةٌ منذ كانون الأوّل 2022، وعلى نطاقٍ واسع منذ حزيران 2025.
  15. اتّحاد W3C، «Understanding SC 2.5.8: Target Size (Minimum)» (المستوى AA: 24 في 24 بكسل CSS على الأقلّ) و«SC 2.5.5: Target Size (Enhanced)» (المستوى AAA: 44 في 44).
  16. اتّحاد W3C، «Disclosure (Show/Hide) Pattern»، دليل ممارسات ARIA: زرٌّ يُظهر المحتوى ويخفيه، وسمته aria-expanded بالقيمة true حين يظهر المحتوى وfalse حين يختفي.
  17. شركة Google، «Simulate mobile devices with device mode»، توثيق Chrome DevTools: وضع الجهاز تقريبٌ أوّليّ لشكل الصفحة على الهاتف، ولا يشغّل شيفرتك على معالج هاتفٍ حقيقيّ.

اترك تعليقاً

الحقول المميّزة بـ مطلوبة