أطلق العنان لقوة CSS Flexbox من خلال فهم خوارزمية تحديد الحجم الجوهرية الخاصة بها. يشرح هذا الدليل الشامل تحديد الحجم المستند إلى المحتوى و flex-basis والنمو والتقلص وتحديات التخطيط الشائعة لجمهور المطورين العالميين.
تبسيط خوارزمية تحديد حجم Flexbox: نظرة متعمقة في التصميمات القائمة على المحتوى
هل سبق لك استخدام flex: 1
على مجموعة من العناصر، وتوقعت أعمدة متساوية تمامًا، لتجد أنها لا تزال ذات أحجام مختلفة؟ أو هل تصارعت مع عنصر flex يرفض بشدة أن يتقلص، مما يتسبب في تجاوز قبيح يكسر تصميمك؟ غالبًا ما تقود هذه الإحباطات الشائعة المطورين إلى دورة من التخمين والتغييرات العشوائية في الخصائص. ومع ذلك، فإن الحل ليس سحريًا؛ إنه منطق.
يكمن حل هذه الألغاز في عمق مواصفات CSS، في عملية تعرف باسم خوارزمية تحديد الحجم الجوهرية Flexbox. إنه المحرك القوي والواعي بالمحتوى الذي يدفع Flexbox، ولكن منطقه الداخلي غالبًا ما يبدو وكأنه صندوق أسود مبهم. إن فهم هذه الخوارزمية هو المفتاح لإتقان Flexbox وبناء واجهات مستخدم مرنة وقابلة للتنبؤ بها حقًا.
هذا الدليل مخصص للمطورين في جميع أنحاء العالم الذين يرغبون في الانتقال من "التجربة والخطأ" إلى "التصميم المتعمد" باستخدام Flexbox. سنقوم بتفكيك هذه الخوارزمية القوية خطوة بخطوة، وتحويل الالتباس إلى وضوح وتمكينك من بناء تخطيطات أكثر قوة ووعيًا عالميًا تعمل مع أي محتوى، بأي لغة.
ما وراء البكسلات الثابتة: فهم تحديد الحجم الجوهري مقابل تحديد الحجم الخارجي
قبل الخوض في الخوارزمية نفسها، من الضروري فهم مفهوم أساسي في تخطيط CSS: الفرق بين تحديد الحجم الجوهري والخارجي.
- تحديد الحجم الخارجي: هذا هو عندما تقوم أنت، المطور، بتحديد حجم العنصر صراحةً. خصائص مثل
width: 500px
أوheight: 50%
أوwidth: 30rem
هي أمثلة على تحديد الحجم الخارجي. يتم تحديد الحجم من خلال عوامل خارجية لمحتوى العنصر. - تحديد الحجم الجوهري: هذا هو عندما يحسب المتصفح حجم العنصر بناءً على المحتوى الذي يحتويه. الزر الذي ينمو بشكل طبيعي ليكون أعرض لاستيعاب تسمية نصية أطول يستخدم تحديد الحجم الجوهري. يتم تحديد الحجم من خلال عوامل داخلية للعنصر.
Flexbox هو سيد تحديد الحجم الجوهري القائم على المحتوى. بينما تقدم القواعد (خصائص flex)، يتخذ المتصفح قرارات تحديد الحجم النهائية بناءً على محتوى عناصر flex والمساحة المتاحة في الحاوية. هذا ما يجعله قويًا جدًا لإنشاء تصميمات مرنة ومتجاوبة.
الأركان الثلاثة للمرونة: تذكير بـ `flex-basis` و `flex-grow` و `flex-shrink`
تسترشد قرارات خوارزمية Flexbox بشكل أساسي بثلاث خصائص، غالبًا ما يتم تعيينها معًا باستخدام الاختصار flex
. الفهم القوي لهذه الأمور غير قابل للتفاوض لفهم الخطوات اللاحقة.
1. `flex-basis`: خط البداية
فكر في flex-basis
على أنه الحجم الأولي المثالي أو "الافتراضي" لعنصر flex على طول المحور الرئيسي قبل حدوث أي نمو أو تقلص. إنها خط الأساس الذي يتم إجراء جميع الحسابات الأخرى منه.
- يمكن أن يكون طولًا (على سبيل المثال،
100px
،10rem
) أو نسبة مئوية (25%
). - القيمة الافتراضية هي
auto
. عند التعيين علىauto
، ينظر المتصفح أولاً إلى خاصية الحجم الرئيسي للعنصر (width
لحاوية flex أفقية،height
لحاوية رأسية). - إليك الرابط الحاسم: إذا كانت خاصية الحجم الرئيسي أيضًا
auto
، فإنflex-basis
يتم حلها إلى حجم العنصر الجوهري المستند إلى المحتوى. هذه هي الطريقة التي يحصل بها المحتوى نفسه على صوت في عملية تحديد الحجم منذ البداية. - القيمة
content
متاحة أيضًا، والتي تخبر المتصفح صراحةً باستخدام الحجم الجوهري.
2. `flex-grow`: المطالبة بالمساحة الموجبة
خاصية flex-grow
هي رقم غير مُحدَّد الوحدات يملي مقدار المساحة الحرة الموجبة في حاوية flex التي يجب أن يمتصها العنصر، بالنسبة إلى إخوته. توجد مساحة حرة موجبة عندما تكون حاوية flex أكبر من مجموع قيم `flex-basis` لجميع عناصرها.
- القيمة الافتراضية هي
0
، مما يعني أن العناصر لن تنمو افتراضيًا. - إذا كانت جميع العناصر تحتوي على
flex-grow: 1
، فسيتم توزيع المساحة المتبقية بالتساوي بينها. - إذا كان أحد العناصر يحتوي على
flex-grow: 2
وكان لدى العناصر الأخرىflex-grow: 1
، فسيتلقى العنصر الأول ضعف المساحة الحرة المتاحة التي تتلقاها العناصر الأخرى.
3. `flex-shrink`: التنازل عن المساحة السلبية
خاصية flex-shrink
هي النظير لـ flex-grow
. إنه رقم غير مُحدَّد الوحدات يحكم كيفية تخلي العنصر عن المساحة عندما تكون الحاوية صغيرة جدًا بحيث لا يمكنها استيعاب `flex-basis` لجميع عناصرها. غالبًا ما يكون هذا هو الأكثر إساءة فهم من بين الثلاثة.
- القيمة الافتراضية هي
1
، مما يعني أنه يُسمح للعناصر بالتقلص افتراضيًا إذا لزم الأمر. - هناك مفهوم خاطئ شائع وهو أن
flex-shrink: 2
يجعل العنصر يتقلص "بضعف السرعة" بمعنى بسيط. الأمر أكثر دقة: المقدار الذي يتقلص به العنصر يتناسب مع عامل `flex-shrink` مضروبًا في `flex-basis`. سنستكشف هذه التفاصيل الحاسمة بمثال عملي لاحقًا.
خوارزمية تحديد حجم Flexbox: تفصيل خطوة بخطوة
الآن، دعنا نسحب الستار ونتجول في عملية تفكير المتصفح. في حين أن مواصفات W3C الرسمية تقنية ودقيقة للغاية، يمكننا تبسيط المنطق الأساسي إلى نموذج تسلسلي أكثر قابلية للهضم لخط flex واحد.
الخطوة 1: تحديد أحجام قاعدة Flex والأحجام الرئيسية المفترضة
أولاً، يحتاج المتصفح إلى نقطة انطلاق لكل عنصر. يحسب حجم قاعدة flex لكل عنصر في الحاوية. يتم تحديد هذا بشكل أساسي من خلال القيمة التي تم حلها لخاصية flex-basis
. يصبح حجم قاعدة flex هذا "الحجم الرئيسي الافتراضي" للعنصر للخطوات التالية. إنه الحجم الذي *يريد* أن يكون عليه العنصر قبل أي تفاوض مع إخوته.
الخطوة 2: تحديد الحجم الرئيسي لحاوية Flex
بعد ذلك، يكتشف المتصفح حجم حاوية flex نفسها على طول محورها الرئيسي. يمكن أن يكون هذا عرضًا ثابتًا من CSS الخاص بك، أو نسبة مئوية من الأصل، أو يمكن أن يكون حجمه جوهريًا من خلال محتواه الخاص. هذا الحجم النهائي والمحدد هو "ميزانية" المساحة التي يجب أن تعمل بها عناصر flex.
الخطوة 3: جمع عناصر Flex في خطوط Flex
ثم يحدد المتصفح كيفية تجميع العناصر. إذا تم تعيين flex-wrap: nowrap
(الافتراضي)، فسيتم اعتبار جميع العناصر جزءًا من سطر واحد. إذا كان flex-wrap: wrap
أو wrap-reverse
نشطًا، فسيوزع المتصفح العناصر عبر سطر واحد أو أكثر. ثم يتم تطبيق بقية الخوارزمية على كل سطر من العناصر بشكل مستقل.
الخطوة 4: حل الأطوال المرنة (المنطق الأساسي)
هذا هو قلب الخوارزمية، حيث يحدث تحديد الحجم والتوزيع الفعلي. إنها عملية من جزأين.
الجزء 4أ: حساب المساحة الحرة
يحسب المتصفح إجمالي المساحة الحرة المتاحة داخل خط flex. يفعل ذلك عن طريق طرح مجموع أحجام قاعدة flex لجميع العناصر (من الخطوة 1) من الحجم الرئيسي للحاوية (من الخطوة 2).
المساحة الحرة = الحجم الرئيسي للحاوية - مجموع أحجام قاعدة Flex لجميع العناصر
يمكن أن تكون هذه النتيجة:
- إيجابية: تحتوي الحاوية على مساحة أكبر مما تحتاجه العناصر. سيتم توزيع هذه المساحة الإضافية باستخدام
flex-grow
. - سلبية: العناصر بشكل جماعي أكبر من الحاوية. يعني هذا العجز في المساحة (التجاوز) أنه يجب على العناصر أن تتقلص وفقًا لقيم
flex-shrink
الخاصة بها. - صفر: العناصر تتناسب تمامًا. لا حاجة للنمو أو التقلص.
الجزء 4ب: توزيع المساحة الحرة
الآن، يقوم المتصفح بتوزيع المساحة الحرة المحسوبة. هذه عملية تكرارية، ولكن يمكننا تلخيص المنطق:
- إذا كانت المساحة الحرة موجبة (تنمو):
- يقوم المتصفح بتجميع جميع عوامل
flex-grow
للعناصر في السطر. - ثم يقوم بتوزيع المساحة الحرة الموجبة على كل عنصر بالتناسب. مقدار المساحة التي يتلقاها العنصر هو:
(flex-grow للعنصر / مجموع جميع عوامل flex-grow) * المساحة الحرة الموجبة
. - الحجم النهائي للعنصر هو
flex-basis
بالإضافة إلى حصته من المساحة الموزعة. هذا النمو مقيد بخاصيةmax-width
أوmax-height
للعنصر.
- يقوم المتصفح بتجميع جميع عوامل
- إذا كانت المساحة الحرة سلبية (تتقلص):
- هذا هو الجزء الأكثر تعقيدًا. لكل عنصر، يحسب المتصفح عامل تقلص مُرجَّح بضرب حجم قاعدة flex الخاص به في قيمة
flex-shrink
الخاصة به:عامل التقلص المُرجَّح = حجم قاعدة Flex * flex-shrink
. - ثم يقوم بتجميع جميع عوامل التقلص المرجحة هذه.
- يتم توزيع المساحة السلبية (مقدار التجاوز) على كل عنصر بالتناسب بناءً على هذا العامل المرجح. مقدار تقلص العنصر هو:
(عامل التقلص المُرجَّح للعنصر / مجموع جميع عوامل التقلص المرجحة) * المساحة الحرة السلبية
. - الحجم النهائي للعنصر هو
flex-basis
ناقص حصته من المساحة السلبية الموزعة. هذا الانكماش مقيد بخاصيةmin-width
أوmin-height
للعنصر، والتي تكون افتراضيًاauto
بشكل حاسم.
- هذا هو الجزء الأكثر تعقيدًا. لكل عنصر، يحسب المتصفح عامل تقلص مُرجَّح بضرب حجم قاعدة flex الخاص به في قيمة
الخطوة 5: محاذاة المحور الرئيسي
بمجرد تحديد الأحجام النهائية لجميع العناصر، يستخدم المتصفح خاصية justify-content
لمحاذاة العناصر على طول المحور الرئيسي داخل الحاوية. يحدث هذا *بعد* اكتمال جميع حسابات تحديد الحجم.
سيناريوهات عملية: من النظرية إلى الواقع
فهم النظرية شيء واحد؛ رؤيتها في العمل يرسخ المعرفة. دعنا نتناول بعض السيناريوهات الشائعة التي يسهل شرحها الآن من خلال فهمنا للخوارزمية.
السيناريو 1: أعمدة متساوية حقيقية والاختصار `flex: 1`
المشكلة: تقوم بتطبيق flex-grow: 1
على جميع العناصر ولكنها لا تنتهي بعرض متساوٍ.
الشرح: يحدث هذا عند استخدام اختصار مثل flex: auto
(الذي يتوسع إلى flex: 1 1 auto
) أو مجرد تعيين flex-grow: 1
مع ترك flex-basis
على قيمته الافتراضية auto
. وفقًا للخوارزمية، يتم حل flex-basis: auto
إلى حجم محتوى العنصر. لذلك، يبدأ عنصر يحتوي على المزيد من المحتوى بحجم قاعدة flex أكبر. على الرغم من توزيع المساحة الحرة المتبقية بالتساوي، إلا أن الأحجام النهائية للعناصر ستكون مختلفة لأن نقاط البداية الخاصة بها كانت مختلفة.
الحل: استخدم الاختصار flex: 1
. يتوسع هذا إلى flex: 1 1 0%
. المفتاح هو flex-basis: 0%
. هذا يجبر كل عنصر على البدء بحجم أساسي افتراضي قدره 0. يصبح العرض الكامل للحاوية "مساحة حرة موجبة". نظرًا لأن جميع العناصر تحتوي على flex-grow: 1
، يتم توزيع هذه المساحة بأكملها بالتساوي بينها، مما يؤدي إلى أعمدة ذات عرض متساوٍ حقًا بغض النظر عن محتواها.
السيناريو 2: لغز تناسب `flex-shrink`
المشكلة: لديك عنصران، كلاهما يحتوي على flex-shrink: 1
، ولكن عندما تتقلص الحاوية، يفقد أحد العناصر عرضًا أكبر بكثير من الآخر.
الشرح: هذا هو التوضيح المثالي للخطوة 4ب للمساحة السلبية. لا يعتمد الانكماش فقط على عامل flex-shrink
؛ بل إنه مُرجَّح بحجم flex-basis
للعنصر. عنصر أكبر لديه المزيد "ليتخلى عنه".
ضع في اعتبارك حاوية بحجم 500 بكسل تحتوي على عنصرين:
- العنصر أ:
flex: 0 1 400px;
(حجم أساسي 400 بكسل) - العنصر ب:
flex: 0 1 200px;
(حجم أساسي 200 بكسل)
إجمالي الحجم الأساسي هو 600 بكسل، وهو أكبر جدًا بمقدار 100 بكسل بالنسبة للحاوية (100 بكسل من المساحة السلبية).
- عامل التقلص المرجح للعنصر أ:
400 بكسل * 1 = 400
- عامل التقلص المرجح للعنصر ب:
200 بكسل * 1 = 200
- إجمالي العوامل المرجحة:
400 + 200 = 600
الآن، وزع 100 بكسل من المساحة السلبية:
- يتقلص العنصر أ بمقدار:
(400 / 600) * 100 بكسل = ~66.67 بكسل
- يتقلص العنصر ب بمقدار:
(200 / 600) * 100 بكسل = ~33.33 بكسل
على الرغم من أن كلاهما كان لديه flex-shrink: 1
، إلا أن العنصر الأكبر فقد ضعف العرض لأن حجمه الأساسي كان ضعف الحجم. تصرفت الخوارزمية تمامًا كما هو مصمم.
السيناريو 3: العنصر غير القابل للانكماش وحل `min-width: 0`
المشكلة: لديك عنصر يحتوي على سلسلة نصية طويلة (مثل عنوان URL) أو صورة كبيرة، ويرفض الانكماش إلى ما دون حجم معين، مما يؤدي إلى تجاوزه للحاوية.
الشرح: تذكر أن عملية الانكماش مقيدة بالحد الأدنى لحجم العنصر. افتراضيًا، تحتوي عناصر flex على min-width: auto
. بالنسبة لعنصر يحتوي على نص أو صور، يتم حل هذه القيمة auto
إلى الحد الأدنى للحجم الجوهري الخاص به. بالنسبة للنص، غالبًا ما يكون هذا هو عرض أطول كلمة أو سلسلة غير قابلة للكسر. ستقوم خوارزمية flex بتقليص العنصر، ولكنها ستتوقف بمجرد وصولها إلى هذا الحد الأدنى المحسوب للعرض، مما يؤدي إلى التجاوز إذا لم تكن هناك مساحة كافية.
الحل: للسماح لعنصر بالتقلص أصغر من حجم محتواه الجوهري، يجب عليك تجاوز هذا السلوك الافتراضي. الإصلاح الأكثر شيوعًا هو تطبيق min-width: 0
على عنصر flex. هذا يخبر المتصفح، "لديك إذني لتقليص هذا العنصر وصولاً إلى عرض الصفر إذا لزم الأمر،" وبالتالي منع التجاوز.
جوهر تحديد الحجم الجوهري: `min-content` و `max-content`
لفهم تحديد الحجم المستند إلى المحتوى بالكامل، نحتاج إلى تحديد كلمتين رئيسيتين ذات صلة بسرعة:
max-content
: العرض المفضل الجوهري للعنصر. بالنسبة للنص، هو العرض الذي سيشغله النص إذا كان لديه مساحة غير محدودة ولم يضطر أبدًا إلى الالتفاف.min-content
: الحد الأدنى للعرض الجوهري للعنصر. بالنسبة للنص، هو عرض أطول سلسلة غير قابلة للكسر (على سبيل المثال، كلمة طويلة واحدة). هذا هو الأصغر الذي يمكن أن يحصل عليه دون أن يفيض محتواه الخاص.
عندما يكون flex-basis
هو auto
ويكون width
للعنصر أيضًا auto
، فإن المتصفح يستخدم بشكل أساسي حجم max-content
كحجم قاعدة flex الأولي للعنصر. هذا هو السبب في أن العناصر التي تحتوي على المزيد من المحتوى تبدأ أكبر قبل أن تبدأ خوارزمية flex في توزيع المساحة الحرة.
الآثار العالمية والأداء
لهذا النهج القائم على المحتوى اعتبارات مهمة للجمهور العالمي وللتطبيقات الهامة للأداء.
الأهمية تكمن في تدويل (i18n)
يعد تحديد الحجم المستند إلى المحتوى سلاحًا ذا حدين للمواقع الدولية. من ناحية، إنه رائع للسماح للتخطيطات بالتكيف مع اللغات المختلفة، حيث يمكن أن تختلف تسميات الأزرار والعناوين اختلافًا كبيرًا في الطول. من ناحية أخرى، يمكن أن يقدم فواصل تخطيط غير متوقعة.
ضع في اعتبارك اللغة الألمانية، المشهورة بكلماتها المركبة الطويلة. كلمة مثل "Donaudampfschifffahrtsgesellschaftskapitän" تزيد بشكل كبير من حجم min-content
للعنصر. إذا كان هذا العنصر عنصر flex، فقد يقاوم الانكماش بطرق لم تكن تتوقعها عندما صممت التخطيط بنص إنجليزي أقصر. وبالمثل، قد لا تحتوي بعض اللغات مثل اليابانية أو الصينية على مسافات بين الكلمات، مما يؤثر على كيفية حساب الالتفاف وتحديد الحجم. هذا مثال مثالي على سبب أهمية فهم الخوارزمية الجوهرية لبناء تخطيطات قوية بما يكفي للعمل للجميع، في كل مكان.
ملاحظات الأداء
نظرًا لأن المتصفح يحتاج إلى قياس محتوى عناصر flex لحساب أحجامها الجوهرية، فهناك تكلفة حسابية. بالنسبة لمعظم مواقع الويب والتطبيقات، تكون هذه التكلفة ضئيلة ولا تستحق القلق بشأنها. ومع ذلك، في واجهات المستخدم المعقدة للغاية والمتداخلة بعمق التي تحتوي على آلاف العناصر، يمكن أن تصبح حسابات التخطيط هذه عنق الزجاجة في الأداء. في مثل هذه الحالات المتقدمة، قد يستكشف المطورون خصائص CSS مثل contain: layout
أو content-visibility
لتحسين أداء العرض، ولكن هذا موضوع ليوم آخر.
رؤى قابلة للتنفيذ: ورقة الغش الخاصة بتحديد حجم Flexbox
لتلخيص ذلك، إليك النقاط الرئيسية التي يمكنك تطبيقها على الفور:
- للحصول على أعمدة ذات عرض متساوٍ حقًا: استخدم دائمًا
flex: 1
(وهو اختصار لـflex: 1 1 0%
).flex-basis
للصفر هو المفتاح. - إذا لم يتقلص العنصر: فإن الجاني الأكثر احتمالية هو
min-width: auto
الضمني الخاص به. قم بتطبيقmin-width: 0
على عنصر flex للسماح له بالتقلص إلى ما دون حجم محتواه. - تذكر أن `flex-shrink` مُرجَّح: ستتقلص العناصر ذات
flex-basis
الأكبر من حيث القيمة المطلقة أكثر من العناصر الأصغر بنفس عاملflex-shrink
. - `flex-basis` هو الملك: فهو يحدد نقطة البداية لجميع حسابات تحديد الحجم. تحكم في
flex-basis
لتحقيق أكبر تأثير على التخطيط النهائي. يؤدي استخدامauto
إلى تأجيل حجم المحتوى؛ يمنحك استخدام قيمة محددة تحكمًا صريحًا. - فكر مثل المتصفح: تصور الخطوات. أولاً، احصل على الأحجام الأساسية. ثم احسب المساحة الحرة (إيجابية أو سلبية). أخيرًا، وزع تلك المساحة وفقًا لقواعد النمو/الانكماش.
الخلاصة
إن خوارزمية تحديد حجم CSS Flexbox ليست سحرًا تعسفيًا؛ إنه نظام منطقي ومحدد جيدًا وقوي بشكل لا يصدق وواعٍ بالمحتوى. من خلال تجاوز أزواج قيمة الخاصية البسيطة وفهم العملية الأساسية، فإنك تكتسب القدرة على التنبؤ بالتخطيطات وتصحيحها وتصميمها بثقة ودقة.
في المرة القادمة التي يسيء فيها عنصر flex التصرف، لن تحتاج إلى التخمين. يمكنك أن تخطو ذهنيًا عبر الخوارزمية: تحقق من flex-basis
، وفكر في الحجم الجوهري للمحتوى، وحلل المساحة الحرة، وطبق قواعد flex-grow
أو flex-shrink
. لديك الآن المعرفة لإنشاء واجهات مستخدم ليست أنيقة فحسب، بل أيضًا مرنة، وتتكيف بشكل جميل مع الطبيعة الديناميكية للمحتوى، بغض النظر عن مكان وجوده في العالم.