التفاعلات الدقيقة: هندسة تجربة اللاوعي
لماذا تبدو أفضل التطبيقات "حية"؟ دليل تقني للرسوم المتحركة بمعدل 60 إطارًا في الثانية، ومنطق XState، والتحديثات المتفائلة، وسيكولوجية التعليقات.
الرسوم المتحركة الكبيرة تبيع العلامة التجارية. التفاعلات الدقيقة تبيع المنتج.
في قطاع المنتجات الفاخرة، غالبًا ما يكون الفرق بين حقيبة بقيمة 500 يورو وحقيبة بقيمة 5000 يورو في عملية الخياطة. في البرمجيات، يكمن الفرق بين SaaS العامة والمنصة المتميزة في التفاعلات الدقيقة. طريقة الضغط على الزر عند الضغط عليه. الطريقة التي ينزلق بها عنصر القائمة عند حذفه. ردود الفعل اللمسية لمفتاح التبديل.
هذه ليست “المبهجة”. إنها متطلبات وظيفية للجودة المدركة. واجهة المستخدم التي تفتقر إلى الفيزياء والتعليقات تبدو “ميتة”. يبدو الأمر وكأنه ملف PDF.
في Maison Code Paris، نهتم بهذه المللي ثانية. نحن لا نبني فقط البرمجيات التي تعمل؛ نحن نبني البرمجيات التي تبدو لا مفر منها. ومع ذلك، فهذه هندسة صعبة ومخادعة.
لماذا تتحدث Maison Code عن هذا
في Maison Code Paris، نعمل كضمير معمari لعملائنا. غالبًا ما نرث حزمًا “حديثة” تم بناؤها دون فهم أساسي للحجم.
نناقش هذا الموضوع لأنه يمثل نقطة تحول حاسمة في النضج الهندسي. التنفيذ الصحيح يميز MVP الهش عن منصة مؤسسية مرنة يمكنها التعامل مع حركة مرور الجمعة السوداء.
لماذا تناقش Maison Code التفاعلات الدقيقة؟
يتعامل معظم المطورين مع الرسوم المتحركة كفكرة لاحقة، حيث يقومون برش بعض انتقالات CSS في نهاية السباق. يؤدي هذا إلى حدوث “خلل” (إطارات مسقطة) و”حالات مستحيلة” (الأزرار عالقة في التحميل). نحن نتعامل مع التفاعلات الدقيقة باعتبارها نظامًا هندسيًا أساسيًا، حيث نجمع بين أجهزة الحالة للمنطق وتسريع الأجهزة للعرض.
فيزياء الكائنات الرقمية
في العالم الحقيقي، لا شيء يتحرك بشكل خطي. إذا رميت كرة، فإنها تتسارع وتتباطأ. لديها كتلة. في تطوير الويب، يكون الانتقال الافتراضي هو “الخطي”. هذا يبدو آليًا ورخيصًا.
فيزياء الربيع مقابل تخفيف المنحنيات
يعد تسهيل CSS القياسي (“سهولة الدخول”) أفضل من الخطي، ولكنه لا يزال يعتمد على الوقت. ينص على أن الرسوم المتحركة يجب أن تستغرق 300 مللي ثانية. فيزياء الربيع، المستخدمة في نظام التشغيل iOS/Android الأصلي، تحاكي التوتر والاحتكاك. إذا تمت مقاطعة الرسوم المتحركة (على سبيل المثال، قام المستخدم بإلغاء السحب)، فإن الزنبرك يتعامل مع نقل السرعة بشكل طبيعي. قد ينكسر المنحنى القياسي أو يُعاد ضبطه بشكل غريب.
بالنسبة للويب، نستخدم Framer Motion أو React Spring لاستخدام محركات فيزيائية موثوقة.
// إحساس "نقرة لايكا".
استيراد {motion} من "framer-motion"؛
const PrimaryButton = ({ الأطفال، عند النقر }) => (
<motion.button
بينما تحوم = {{ مقياس: 1.02 }}
whileTap={{ مقياس: 0.95 }}
الانتقال = {{ النوع: "الربيع"، الصلابة: 400، التخميد: 17 }}
عندالنقر={onClick}
اسم الفئة = "btn-الابتدائي"
>
{أطفال}
</motion.button>
);
يضيف هذا الكود البسيط كتلة للزر. يبدو الأمر “ثقيلًا” وجوهريًا، ومناسبًا للإجراءات ذات القيمة العالية مثل “الخروج” أو “النشر”.
أداء العرض: الوصول إلى 60 إطارًا في الثانية
“المعيار الذهبي” للرسوم المتحركة لواجهة المستخدم هو معدل ثابت 60 إطارًا في الثانية (FPS). وهذا يمنح المتصفح 16.6 مللي ثانية لعرض كل إطار. ولتحقيق ذلك، يجب عليك فقط تحريك الخصائص التي لا تؤدي إلى تشغيل دورات التخطيط أو الرسام في المتصفح. يجب عليك البقاء في مؤشر الترابط.
العقارات الرخيصة
- “التحويل” (الترجمة، القياس، التدوير)
- “التعتيم”.
الخصائص باهظة الثمن (تجنبها)
- “العرض” / “الارتفاع”.
أعلى/يسار/الهامش- “صندوق الظل” (أحيانًا)
مثال على سحق التخطيط
إذا قمت بتحريك “ارتفاع” الأكورديون لفتحه، فيجب على المتصفح إعادة حساب موضع كل عنصر أسفله في كل إطار. وهذا يسبب خردة على الأجهزة المحمولة. الحل: تقنية “المقياس العكسي”.
- قم بعرض العنصر بالحجم الكامل ولكن مخفيًا.
- استخدم “التحويل: مقياس Y” لتحريكه عند الفتح.
- قم بضبط حجم الأطفال حتى لا يبدوا مسحوقين.
- أو بشكل أبسط: استخدم خاصية “layout” الخاصة بـ “framer-motion”، والتي تتعامل مع حسابات FLIP (أول تشغيل معكوس أخيرًا) تلقائيًا.
المنطق: آلة الدولة (XState)
الرسوم المتحركة السلسة تكون عديمة الفائدة إذا تم كسر المنطق الكامن وراءها. الخطأ الأكثر شيوعًا في تطوير الواجهة الأمامية هو “الانفجار المنطقي”.
// ممارسة سيئة
const [isLoading, setIsLoading] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
ماذا يحدث إذا كان كل من “isLoading” و”isError” صحيحين؟ لديك زر دوار ورسالة خطأ متداخلة. هذه الدولة المستحيلة.
نحن نستخدم أجهزة الحالة المحدودة (FSM) عبر XState لضمان الصلاحية رياضيًا. يمكن أن يكون الزر في حالة واحدة فقط في كل مرة.
استيراد { createMachine } من 'xstate'؛
تصدير زر constMachine = createMachine({
المعرف: "زر"،
الأولي: "خاملاً" ،
تنص على: {
خامل: {on: {انقر: "جارٍ التحميل" } }،
التحميل: {
استدعاء: {
src: "إرسال النموذج"،
تم: "النجاح"،
أونيرور: "خطأ"
}
},
النجاح: {
after: { 2000: 'idle' } // إعادة التعيين التلقائي
},
خطأ: { عند: { إعادة المحاولة: 'التحميل' } }
}
});
عندما تقوم بتوصيل هذا إلى واجهة المستخدم الخاصة بك، فإنك تتوقف عن التحقق من if (isLoading && !isError). ما عليك سوى العرض استنادًا إلى “state.value”. هذه المتانة تجعل التفاعل الجزئي يبدو متينًا وخاليًا من الأخطاء.
واجهة المستخدم المتفائلة: وهم السرعة
التفاعلات الدقيقة هي المسؤولة عن الأداء المتصور. أقوى أسلوب هو التحديث المتفائل. عندما يقوم أحد المستخدمين “بالإعجاب” بمنشور ما، فإننا لا ننتظر تأكيد الخادم. نصبغ القلب باللون الأحمر على الفور. ثم نرسل الطلب في الخلفية.
- النجاح: لا تفعل شيئًا (واجهة المستخدم صحيحة بالفعل).
- الفشل: التراجع عن واجهة المستخدم (تحويل لون القلب إلى اللون الرمادي) وإظهار خطأ نخب.
وهذا يجعل التطبيق يبدو محليًا أولاً، مما يؤدي إلى إزالة زمن استجابة الشبكة من حلقة التفاعل.
// الرد على تحديث الاستعلام المتفائل
ثابت { تحور } = useMutation({
طفرة Fn: likePost،
onMutate: غير متزامن (postId) => {
في انتظار queryClient.cancelQueries(['post', postId]);
const PreviousPost = queryClient.getQueryData(['post', postId]);
// تحديث متفائل
queryClient.setQueryData(['post', postId], (old) => ({
...قديم،
أعجب: صحيح،
الإعجابات: إعجابات قديمة + 1،
}));
العودة {المشاركة السابقة}؛
},
onError: (خطأ، معرف ما بعد، سياق) => {
// التراجع عن الخطأ
queryClient.setQueryData(['post', postId], context.previousPost);
},
});
علم النفس: حلقات ردود الفعل والانتظار
قاعدة الـ 100 مللي ثانية
- < 100 مللي ثانية: فوري. يشعر المستخدم أنه تسبب في الإجراء مباشرة.
- 100 مللي ثانية - 300 مللي ثانية: الجهاز يعمل.
- > 1000 مللي ثانية: يتجول عقل المستخدم.
تفاصيل صناعية
في بعض الأحيان، تكون أجهزة الكمبيوتر سريعة جدًا. إذا قمت بالنقر فوق “التحقق من نقاط الائتمان” وتم إرجاعها خلال 50 مللي ثانية، فإن المستخدم يثق في النتيجة أقل. “لم يتم التحقق في الواقع، بل خمنت فقط.” بالنسبة للعمليات عالية القيمة (المدفوعات، الشيكات الأمنية)، نقوم بإدخال تأخير مصطنع (على سبيل المثال، 800 مللي ثانية - 1.5 ثانية) مع رسم متحرك معقد (“الاتصال بالبنك…”، “رمز التحقق…”). هذا “المسرح الأمني” يبني الثقة.
اللمس والصوت
المرئيات هي مجرد حاسة واحدة. التفاعلات الدقيقة التفصيلية تعمل على إشراك اللمس والسمع.
ردود الفعل اللمسية
على الهاتف المحمول، يحجب الإصبع الزر. استخدم Vibration API للتأكيد.
navigator.vibrate(10): علامة خفية (شريط التمرير المفاجئ).navigator.vibrate([50, 20, 50]): خطأ / تحذير.
تصميم الصوت
تعد “أصوات واجهة المستخدم” خطيرة إذا تم إجراؤها بشكل سيئ، ولكنها سحرية إذا تم تنفيذها بشكل جيد (فكر في “النقر” على Nintendo Switch).
- التردد: تبدو الأصوات عالية التردد “خفيفة” و”دقيقة”. التردد المنخفض يبدو “ثقيلاً” و”تحذيراً”.
- الصوت: يجب أن يكون مسموعًا بالكاد.
- السياق: لا تقم مطلقًا بتشغيل الصوت عند تحميل الصفحات البسيطة. فقط على الإجراءات التي يبدأها المستخدم (النجاح، الحذف).
إمكانية الوصول
يجب ألا تستبعد التفاعلات الدقيقة المستخدمين.
- الاضطرابات الدهليزية: يصاب بعض المستخدمين بدوار الحركة بسبب اختلاف المنظر أو الرسوم المتحركة ذات التكبير الكبير.
- المتطلبات: احترام
الحركة المفضلة المخففة. - التنفيذ: قم بتعطيل الرسوم المتحركة العامة أو قم بالتبديل إلى التلاشي البسيط للعتامة.
- المتطلبات: احترام
- قارئات الشاشة: هل يعرف قارئ الشاشة أن الزر “جاري التحميل”؟
- استخدم مناطق
aria-live="polite"للإعلان عن تغييرات الحالة دون تغيير التركيز.
- استخدم مناطق
@media (يفضل الحركة المخفضة: تقليل) {
* {
مدة الرسوم المتحركة: 0.01 مللي ثانية! مهم؛
مدة الانتقال: 0.01 مللي ثانية! مهم؛
}
}
الخلاصة
التفاعلات الدقيقة هي الغراء الذي يربط واجهة المستخدم معًا. إنهم ينقلون الحالة ويمنعون الأخطاء من خلال تعليقات واضحة ويخلقون إحساسًا بالتلاعب المباشر. في التعاملات التجارية بين الشركات (B2B) الراقية والمعاملات التجارية بين الشركات (B2C) الفاخرة، تنقل هذه التفاعلات كفاءة العلامة التجارية.
إذا تجاهلتها، فستكون لديك واجهة أمامية لقاعدة بيانات وظيفية. إذا أتقنتها، فلديك منتج رقمي.
**[قم بتوظيف مهندسينا](/contact)**.