بطاقات Magic Flip: حل مشكلة تغيير الحجم الشائعة
نشرت: 2022-03-10ما هي احتمالات أن يستخدم عميلك التالي كلمة تفاعلي أثناء تقديم مشروعه؟ من واقع خبرتي ، فإن الإجابة هي 100٪ ، لذلك أبحث دائمًا عن تقنيات CSS قوية لمساعدتي في تقديم الميزات والتأثيرات المختلفة التي تظهر عند مناقشة هذا الهدف.
جزء صغير من التفاعل الذي طُلب مني تنفيذه مرارًا وتكرارًا هو بطاقات الوجه - كتل من المحتوى تتحول عند تحريك الماوس أو النقر عليها للكشف عن المحتوى على الجانب الخلفي. إنه تأثير أنيق يشجع على التصفح الممتع ، وطريقة أخرى لإظهار المزيد من المعلومات دون التنقل بعيدًا عن الصفحة. لكن الطريقة القياسية تواجه مشكلة عندما يتعلق الأمر باستيعاب أطوال محتوى البطاقة المختلفة.
في هذا البرنامج التعليمي ، سنقوم ببناء شبكة بطاقات فليب التي تحل هذه المشكلة ببعض أساسيات CSS - التحويلات والمرن والشبكة. ستحتاج إلى أن تكون على دراية بهذه الأمور ، وسيساعد ذلك في الحصول على فهم جيد لتقنيات تحديد المواقع في CSS. سوف نغطي:
- كيف يتم تنفيذ أوراق التقليب عادةً باستخدام تحديد المواقع المطلق ؛
- مشكلة التحجيم التي يقدمها الوضع المطلق ؛ و
- حل عام للتحجيم التلقائي للمحتوى المتراكب.
إنشاء بطاقة فليب أساسية
مع دعم المستعرض الحديث الجيد للتحويلات ثلاثية الأبعاد ، يكون إنشاء بطاقة قلب أساسية أمرًا بسيطًا نسبيًا. الطريقة المعتادة هي وضع وجهي البطاقة الأمامية والخلفية في حاوية رئيسية ، ووضع الوجه الخلفي تمامًا بحيث يمكن أن يتطابق مع حجم الوجه الأمامي. أضف تحويل المحور x إلى الوجه الخلفي لجعله يظهر معكوسًا ، وأضف آخر إلى البطاقة نفسها عند المرور فوقها ، ونحن في مجال الأعمال.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; } .card-back { position: absolute; top: 0; right: 0; bottom: 0; left: 0; transform: rotateX(-180deg); }
ما الخطأ الذي يمكن أن يحدث؟
ومع ذلك ، فإن حلنا القياسي به مشكلة كبيرة: فهو لا يعمل عندما يحتاج الوجه الخلفي إلى مساحة أكبر مما يوفره الوجه الأمامي. يُعد إعطاء البطاقة حجمًا كبيرًا وثابتًا أحد الحلول ، ولكن هذا النهج مضمون أيضًا للفشل في مرحلة ما لمجموعة من أحجام الشاشات.
تتميز تركيبات التصميم بشكل طبيعي بالمربعات ذات المظهر الأنيق مع النص الذي يناسب تمامًا. ولكن عند بدء التطوير ، قد يكون من الصعب الحصول على تخطيط للصفحة والبطاقة يتناسب مع المحتوى الحقيقي. وعند عرض محتوى ديناميكي من CMS ، قد يكون ذلك مستحيلًا! حتى مع وجود قيود على الكلمات أو الأحرف ، لا يوجد غالبًا حل يعمل بشكل موثوق عبر جميع الأجهزة.
يجب أن نسعى دائمًا إلى إنشاء تطبيقات تخطيط تتسامح مع نطاق واسع من أطوال المحتوى. لكنها ليست سهلة! غالبًا ما أتيحت لي الفرصة للعودة إلى استخدام الحجم والموضع الثابت ، سواء كان ذلك بسبب قيود الوقت ، أو دعم المتصفح غير الكافي ، أو التصميم المرجعي الضعيف ، أو مجرد قلة خبرتي.
على مر السنين ، تعلمت أن العملية التكرارية الجيدة والحوار الصحي مع المصمم يمكن أن يساعد كثيرًا عند الخوض في هذه المشكلات ، وغالبًا ما يمكنك الالتقاء في مكان ما في الوسط للحصول على تخطيط قوي مع بعض التفاعل. لكن بالعودة إلى المهمة المطروحة - هل يمكن إنجازها؟
التفكير خارج الصندوق
في الواقع ، من الممكن تغيير حجم البطاقات بناءً على المحتوى الأمامي والخلفي ، وهو ليس بالصعوبة التي يبدو عليها في البداية. نحن فقط بحاجة إلى أن نكون منهجيين ومثابرين!
تقييد المشكلة
لنبدأ بإعداد قائمة بمتطلبات التصميم الخاصة بنا. قد تبدو محاولة كتابة ما تريده بدقة وكأنه عمل روتيني ، لكنها طريقة رائعة للكشف عن القيود التي يمكن تبسيطها لحل مشكلة ما. دعنا نقول:
- نريد أن نرى بطاقة مستطيلة واحدة أو أكثر ، مرتبة في شبكة ذات عمود واحد أو شبكة متعددة الأعمدة ؛
- نريد أن تنقلب البطاقات عند التمرير أو النقر للكشف عن مجموعة ثانية من المحتوى على الوجه الخلفي ؛
- نريد أن تكون البطاقات دائمًا كبيرة بما يكفي لإظهار كل محتوياتها الأمامية والخلفية ، بغض النظر عن طول المحتوى أو النمط ؛ و
- في حالة وجود أعمدة متعددة ، من الناحية المثالية ، نريد أن تكون جميع البطاقات بنفس الحجم بحيث تتم محاذاة الصفوف بشكل جيد.
بالتفكير في هذه المتطلبات ، يمكننا ملاحظة أمرين يبسطان المشكلة:
- إذا كان سيتم تقديم البطاقات في شبكة ، فلدينا قيود على عرضها - أي أن عرضها عبارة عن وظائف لإطار العرض أو حاوية الشبكة بدلاً من المحتوى الخاص بها ؛
- نظرًا لأننا نعرف عرض البطاقة (كنسبة مئوية من أصلها على الأقل) ، فقد توصلنا إلى البعد الأفقي ونحتاج فقط إلى توسيع ارتفاع البطاقة ليناسب ارتفاع وجهها الأمامي أو الخلفي ؛ و
- إذا تمكنا من القيام بذلك وكل بطاقة ذات حجم ذاتي عموديًا ، فيمكننا استخدام
grid-auto-rows
CSS لجعل جميع صفوف البطاقات بطول أطول بطاقة.
اكتشاف خدعة البطاقة
لذا ، كيف يمكننا تحديد حجم البطاقات بأنفسنا؟ لقد قمنا الآن بتبسيط مشكلتنا ، وأصبحنا في متناول الحل.
انسَ ، للحظة ، فكرة وضع المحتوى في مقدمة المحتوى الآخر ، وركز على مطلبنا الجديد: والد يبلغ طوله مثل أطول طفل له. هذا سهل! باستخدام الأعمدة ، يمكننا أن نتسبب في توسيع أحد الوالدين إلى ارتفاع أطول طفل له. بعد ذلك ، نحتاج فقط إلى استخدام القليل من خفة اليد لجعل الأطفال يتماشون مع:
- اضبط الأطفال ليكونوا بنفس عرض والديهم
- اسمح للطفل الثاني بالفيضان إلى اليمين
- حوله إلى اليسار إلى مكانه الصحيح
.cards { display: grid; } .card-body { display: flex; } .card-front, .card-back { min-width: 100%; mix-blend-mode: multiply; // Preview both faces } .card-back { transform: translate(-100%, 0); }
إذا كان هذا النهج يبدو واضحًا ، فكن مطمئنًا لأنني قضيت ساعات عديدة في التفكير في بعض الأفكار الرهيبة حقًا قبل التفكير في الأمر. في البداية ، كنت قد خططت لطباعة نسخة مكررة مخفية من نص الوجه الخلفي داخل الوجه الأمامي لتوسيع البطاقة إلى الحجم الصحيح. وعندما فكرت في استخدام التدفق الزائد للعمود ، كنت أقوم في الأصل بقص العمود الأيمن باستخدام overflow:hidden
، وتحويله فقط في اللحظة الأخيرة عندما بدأ التمرير ، لأنني لم أدرك بعد أنني أستطيع الاحتفاظ به متغيرًا من البداية واستخدم طريقة أخرى مثل opacity
أو backface-visibility
لتشغيلها وإيقافها حسب الحاجة.
بمعنى آخر ، الحلول الواضحة هي نتيجة العمل الجاد! إذا كنت تشعر وكأنك تضرب رأسك على مكتبك لساعات بسبب مشكلة في التخطيط ، فمن المهم أن تتراجع خطوة إلى الوراء وتقرر ما إذا كنت تقضي وقت عميلك بحكمة: ما إذا كنت ستقترح عليه تغيير التصميم ، وما إذا كان لمتابعة الحل في وقتك الخاص كتمرين تعليمي عندما ينتهي الضغط. لكن عندما تبتكر طرقًا بسيطة ، لا تشعر أبدًا بالغباء لأن الأمر استغرق وقتًا طويلاً . الآن ، دعنا نراجع حلنا الكامل.
.cards { display: grid; } .card { perspective: 40rem; } .card-body { display: flex; transform-style: preserve-3d; transition: var(--time) transform; .card:hover & { transform: rotateX(-180deg); } } .card-front, .card-back { backface-visibility: hidden; min-width: 100%; } .card-back { transform: rotateX(-180deg) translate(-100%, 0); }
هل هناك أي محاذير؟
يعمل الحل جيدًا بشكل عام ، مع بعض التحذيرات البسيطة التي يجب وضعها في الاعتبار:
- يجب أن تكون البطاقات موجودة في تخطيط شبكة أو في سياق آخر حيث لا يعتمد عرضها على المحتوى.
- تتطلب البطاقات غلافًا للمحتوى من نوع ما (
card-body
) بحيث لا تتغير منطقة التمرير أثناء الرسوم المتحركة. إذا كانت البطاقة نفسها متحركة ، فسترى بعض الخلل حيث تتوقف الرسوم المتحركة وتعيد تشغيلها بسرعة. - من الأفضل وضع الأنماط مثل الخلفيات والظلال المربعة مباشرة على الوجوه الأمامية والخلفية ، حيث لن يتم تحريك أي تأثيرات على البطاقة نفسها. احذر من التصميم مثل الظلال الصندوقية على جسم البطاقة ، فمن الطبيعي أن تنقلب رأسًا على عقب.
- تحتاج الوجوه الأمامية والخلفية للبطاقات إلى ضبط خاصية
box-sizing
border-box
إذا كان لديهم حشوة خاصة بهم ، نظرًا لمتطلبات الحدmin-width
، وإلا فسوف يفيضون. - لا يزال Safari يتطلب
-webkit-backface-visibility
، في شكل مقدم من البائع.
مضيفا بعض البولندية
لقد حللنا الآن المشكلة الصعبة ، فلنلقِ نظرة على بعض التعديلات التي يمكننا إجراؤها لجعل التفاعل بأكمله يعمل بسلاسة قدر الإمكان.
أولاً ، تحقق مما إذا كانت البطاقات تتداخل أثناء التقليب. سيعتمد هذا على ما إذا كنت تستخدم أعمدة متعددة ، وعرض هامش العمود ، واتجاه الوجه ، وقيمة منظور البطاقة ، ولكن من المحتمل أن يحدث ذلك. يمكنك زيادة مدة الرسوم المتحركة لرؤية الأشياء بشكل أكثر وضوحًا. عند التمرير ، يبدو من غير الطبيعي أن تنقلب البطاقة التي تم تحريكها أسفل جيرانها اللاحقين ، لذلك نحتاج إلى وضعها في المقدمة باستخدام z-index
. سهل بما فيه الكفاية ، لكن احترس! نحتاج إلى الانتظار حتى اكتمال الرسوم المتحركة الصادرة قبل استعادة z-index
. أدخل transition-delay
:
.card { transition: z-index; transition-delay: var(--time); z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } }
بعد ذلك ، ضع في اعتبارك إنشاء حالة نشطة للبطاقات. عادةً ما أحاول إنشاء بطاقات مثل هذه مرتبطة بمكان ذي صلة - حتى لو لم يحددها المصمم - كعناصر ذات تأثيرات تحوم مثل هذه تبدو قابلة للنقر ، لذا من الجيد توفير وجهة للقراء الذين يجربون حظهم. أحب إجراء تحويل قصير ودقيق للمقياس ، لأنه يعمل بشكل جيد بشكل معقول سواء تم قطع النصف الثاني من الرسوم المتحركة عن طريق تحميل صفحة الوجهة (أحب أن تكمل المتصفحات الرسوم المتحركة أثناء الرحلة بشكل نظيف قبل التنقل ، على الرغم من أنا متأكد من أنه سيكون من الصعب تنفيذه عمليًا أكثر مما يبدو).
هذه أيضًا فرصة رائعة للتفكير في مدى سهولة الوصول إلى المحتوى الخلفي لبطاقاتنا. ترميزنا موجز ومنظم جيدًا ، لذلك قمنا بتغطية قارئات الشاشة وحالات الاستخدام الأخرى التي تتجاهل التصميم ، ولكن ماذا عن مستخدمي لوحة المفاتيح؟ إذا أردنا أن نجعل البطاقات نفسها مثبتة ، فسوف يتم التركيز عليها عندما يقوم مستخدمو لوحة المفاتيح بتبويبها من خلال الصفحة. دعنا نعيد استخدام حالة التمرير على البطاقة كحالة تركيز ، وسيظهر المحتوى الخلفي بشكل طبيعي أثناء تصفح لوحة المفاتيح.
.card { transition: z-index, transform calc(var(--time) / 4); transition-delay: var(--time), 0s; z-index: 0; &:hover { transition-delay: 0s; z-index: 1; } &:active { transform: scale(0.975); } } .card-body { .card:hover &, .card:focus & { transform: rotateX(-180deg); } }
أخيرًا ، لا تنسَ أنه الآن يتم تغيير حجم البطاقة تلقائيًا لتلائم محتواها ، يمكنك استخدام أي تقنيات محاذاة وتباعد تريدها داخل الحاويات الأمامية والخلفية. استخدم المحاذاة المرنة للعناوين المركزية ، وأضف حشوة ، بل ضع شبكة أخرى داخل البطاقة. هذا هو جمال حلول التخطيط الجيدة التي تتناسب مع محتواها - تقليل اقتران الأطفال بالآباء ، والنمطية التي تتيح لك التركيز على شيء واحد في كل مرة.
.card-front, .card-back { display: flex; align-items: center; background-color: white; box-shadow: 0 5px 10px black; border-radius: 0.25rem; padding: 1.5rem; }
تغليف
آمل أن تجد تقنية CSS مفيدة! لماذا لا تجرب بعض الاختلافات في الرسم المتحرك ، مثل تأثير المقياس أو الخبو التبادلي البسيط؟ لا يقتصر الأسلوب على شكل البطاقات أيضًا. يمكن استخدامه في أي مكان حيث تقع مسؤولية التحجيم الرأسي على أكثر من عنصر واحد. تخيل موقعًا إلكترونيًا لمجلة يعرض صورًا كبيرة مع تسميات توضيحية متراكبة - يمكنك استخدامه لاستيعاب كلتا الصورتين بنسب عرض إلى ارتفاع طويلة ونص ديناميكي طويل.
قبل كل شيء ، تذكر فوائد قضاء بعض الوقت في التفكير بجدية حول ما إذا كانت هناك طريقة لتنفيذ تصميم يبدو كما لو أنه سيعمل فقط مع الحجم والموضع الثابت. في كثير من الأحيان ، وبغض النظر عن مدى صعوبة المشكلة في البداية ، فإن تدوين جميع متطلباتك ، وتخصيص بعض الوقت لإنشاء حالة اختبار بسيطة ، والتخطي بشكل منهجي هو أفضل رهان دائمًا.