المحتوى عن 'web design'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • الإدارة والقيادة
  • السلوك التنظيمي
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
    • React
  • HTML
    • HTML5
  • CSS
  • SQL
  • لغة C#‎
  • لغة C++‎
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • ASP.NET
    • ASP.NET Core
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
    • منصة Xamarin
  • سهولة الوصول
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 2 نتائج

  1. يوجد في مجال تصميم الوِب الكثير من الأسعار، والمهارات، ومستويات الاحتراف، والاختلاف في المُخرجات؛ وهي أمور يصعب على أي عميل فهمها جميعًا، أو حتى معرفة من أين يبدأ. نحن نعيش و نعمل في مجال دائم التغيير، و كما هو صعب بالنسبة لنا أن نواكب التقنية، وهو أكثر صعوبة على العملاء. حصلت على الاتصال سأفترض أنك قمت سلفًا بالاتصال بالعميل المحتمل. وستكون هذه المقالة عونًا لك في المرحلة الموالية تحديدًا. وبما أنك الآن أجريت الاتصال، فلا بد أنك سترتب اجتماعًا معه لتناقشه في ما يتطلع إليه وما تستطيع تقديمه له. توجد عدة نقاط يجب أن تلاحظها و تبقيها في ذهنك عند لقاء العميل، و التي أرى أنها تناقض الكثير من المعلومات “التقليدية” المنتشرة: لقد سمعت بمقولة “وافق على المشروع، ثم حاول أن تعرف كيف تقوم به لاحقًا“؛ و هي - غالبًا - ليست الفكرة الأفضل في مجال عملنا؛ لأن القيام بمثل ذلك سيؤدي - غالبًا - إلى جعل المشروع غير مربح ماليًا، أو يسبب لك خسارة أموال لا تمتلكها على الأغلب. توجد بعض الحالات التي يمكن فيها لهذه الطريقة أن تنجح ربما في حالات HTML أوCSS حيث لا تعرف كيف تنفذها، ولكنك رأيت أنه سبق تنفيذها. لا تتورط في لغات لا تعرفها، و تفترض أن بإمكانك “إنجاز العمل” أو “إيجاد حل”. اقبل المشروع بغض النظر عن الميزانية. إن كنت جديدًا على العمل الحرّ، فغالبًا ستضطر للقبول بميزانية قليلة، ولكن لا تجعلها عادة. إن العملاء الذين لا يقدمون ميزانية هم: إما لا يريدون دفع المال لمحترف، ولكن يتوقعون عملاً احترافيًا. أو يريدون “إنجاز العمل فقط” بغض النظر عن شكله أو أدائه. وكلتا الحالتين سيئتان، فإما سيكون لديك عميل دون المستوى، أو أنك لن تحصُل على مشاريع ذات قيمة ماديّة معتبرة، و بالتالي لن تكون نافعة لك بكل المقاييس. انطباعك الأولي عن العميل يستمر طويلاً .لا يتطلب أخذ انطباع أولي عن أحد ما وقتا طويلاً، و العملاء لا يختلفون عن ذلك. لا تقحم نفسك بعمل ما إن ظننت بأن النتيجة النهائية للمشروع ستكون قليلة. أعلم إنه من السهل قول ذلك عكس فعله، وخاصة عندما تكون بحاجة للمال. و لكن ثق بحدسك وتصرف وِفقه، واترك المشروع إن كان لديك إحساس سيئ تجاهه. أنت كذلك تجري مقابلة للعميل يظن الكثيرون أنّ مقابلة العملاء هي بغرض التأثير عليهم ليختاروك من بين بقية المستقلين أو الوكلاء. تذكّر بأنك تجري المقابلة لتعمل معهم أيضًا. ركز جيدًا على البند المذكور أعلاه، و لا تعمل معهم إن لم يعجبك أسلوبهم. إن اللقاء الأوّلي، كما قلت سابقًا، هو مقابلة يجريها العميل لك، وتجريها أنت للعميل. لا تعطهم السلطة هنا لأن هذا سيقودك للفشل في نهاية الطريق. ماذا تأخذ معك إن كنت تقابل العميل عبر الهاتف أو سكايب، تأكد من أنك تفحصت موقعهم بدقة، وأنك أجريت بعض البحوث حول مجال عملهم ومنافسيهم. ولكن إن كنت تلتقي بهم شخصيًّا، فهناك لائحة بسيطة من الأشياء التي أنصحك بأن تأخذها إلى الاجتماع: دفتر الرسومات. سأفصّل هذا البند لاحقًا. قلم تخطيط. إن كانت لديك فكرة وأردت رسمها، استخدم قلم التخطيط كي لا تخوض كثيرًا في التفاصيل. قلم. لأخذ الملاحظات. لا تستخدمه في رسم وتخطيط الأفكار. بطاقات العمل. و هذا كل شيء. لا آخذ الحاسب معي إلا بطلب خاص من العميل. يظهرك ذلك كشخص مبدع، و ليس مجرد شخص يجيد استخدام برامج التصميم الحاسوبية. إن كلاً من دفتر الرسومات و قلم التخطيط هما أفضل أصدقائك في هذه المرحلة. كن مطلعًا هذه نقطة هامة. و هي ربما أهم من معرفة ما يحتاجه المشروع. يجب أن تكون هناك صلة بينك والعميل، وفي حال عدم وجودها ستشعر كأن المشروع جامد، وسيقل شغفك به. أعلم الآن أن الكثيرين سيختلفون معي عندما أقول أننا بحاجة أن نرتبط بعملنا وأن نكون شغوفين به. ولكن بنفس الوقت أظن بأن العاملين المحترفين في المجال الإبداعي سيتفقون معي هنا، إن لم تكن شغوفًا بعملك ، فإن إبداعك سيخبو. لن تكون لديك رغبة أو شغف أو ارتباط. يكسر المجال الإبداعي كل الروابط التقليدية التي تمتلكها المجالات الأخرى. نحن لا نرتدي البدلات الرسمية ولا أحذية رياضية، ولا نحمل حقائب إلى كل مكان نذهب إليه. اكتشفت أنني أحظى باهتمام أكبر من العملاء عندما أقابلهم و أنا أرتدي ثيابًا عادية (ولكنها أنيقة) وأنا أحمل دفتر الرسومات وقلم التخطيط في يدي. إنهم يوظّفونك كي تكون مبدعًا. بما أني لا أرتدي بذلة في مكتبي فأنا لا أرتديها في اجتماعاتي أيضًا. لا أزعم أن هذا الأمر سينفع مع كل العملاء، لكن الشركات الصغيرة و المتوسطة لا تهتم عادة بشكلك بقدر ما تهتم بكيفية أدائك لعملك. وكي أكون صادقًا، إن كانوا سيحكمون علي من مظهري بدلاً من شخصيتي أو مهاراتي فلن أكون راغبًا بالعمل معهم على أية حال. و بعد أن قلت ما سبق، كن أنيقًا لكن على سجيتك وستحظى باهتمام أكبر، وعلى الأرجح سيتذكرونك. على أية حال قيمة الشكل والثياب أخذت تقل هذه الأيام. يبحث العملاء عن شخص يستطيعون الوثوق به، شخص سيكون صادقًا معهم، وسيسلمهم العمل بالوقت والشكل المطلوبين. في النهاية، يجب أن تقدّم نفسك على أنك الشخص الأكثر كفاءة وجدارة بالثقة من بين من قابلوهم لأداء هذا العمل. وهذا هو مضمون الاطلاع. أن ترى إن كنت مناسبًا للعميل، و إن كان العميل مناسبًا لك. معرفة حاجات العميل لن تتطلب جميع المواقع رابطًا إلى كل موقع من مواقع الشبكات الاجتماعية المتاحة، ولن تتطلب جميع المواقع وسائل تواصل اجتماعية. وهنا يظهر مدى براعتك. إن كنت واضحًا و صريحًا مع العميل، أخبرهم بما تظن أنه الأفضل لهم ولمستخدمي موقعهم، سيختارونك على الأغلب في كل مرة. و إن لم يختاروك فهم ينتمون للمجموعة الموصوفة سابقًا. و عليك ألا تعمل معهم بأية حال. اللقاء الأوّلي أساسي من أجل تقييم حاجات (و بعض رغبات) العميل. أنا لا أقول إنه ليس بإمكانك إعطاءهم كل ما يريدونه، ولكن كن منطقيًا.. لا تضع ضفادع راقصة على الصفحة الرئيسية.. إلا إن كانوا يربون الضفادع أو شيئا غريبًا كهذا. تحدّث معهم عمّا يرغبون تحقيقه من موقعهم. في ما يلي بعض الأسئلة التي يجب مراعاتها أثناء التحدث معهم حول مشروعهم: من سيستخدم الموقع برأيك، وما هي المعلومات التي سيبحثون عنها؟ و سبب سؤالنا عمّن سيستخدم الموقع هو، وببساطة، أن بعض العملاء يستخدمون مواقعهم للاستخدام الداخلي بدل تقديمه للعملاء. هل تعتقد أن مستخدمي موقعك من خبراء التقنية، أم أنهم مستخدمون عاديون؟ تستطيع معرفة ذلك غالبًا من خلال نمط العمل لديهم، لكن لا ضير في أن تسأل. ما هي المعلومات الرئيسية التي تود إيصالها لمستخدمي موقعك؟ ماهي المواقع التي تعجبك ضمن مجال عملك ولماذا؟ ماهي المواقع التي تعجبك خارج مجال عملك ولماذا؟ ماهي ميزانيتك لهذا الموقع؟ و سأورد المزيد من التفاصيل حول هذه النقطة لاحقًا. توجد أسئلة أخرى كثيرة يمكن أن تُسأل أو تطرح خلال النقاش، وما سبق بعض منها، ستتعلم عبر الزمن أن كل عميل مختلف عن الآخر، و سيكون لديك أسئلة مختلفة لكل منهم. اعتدت أن تكون معي لائحة من عشرين سؤالاً أسألها لكل عملائي. لقد ساعدتني في تقصي المعلومات التي أحتاجها منهم، لكنني اكتشفت أن الكثير من الأسئلة لن تنفع مع كل العملاء، و أن ما نفع منها مع عميل لم ينفع مع الآخر. لذا لا حاجة للقول، لقد تخليت عنها. خذ الوقت الكافي لمعرفة المشروع والعميل، افهم احتياجاتهم، وسجلها، دوّن ملاحظات حول كل ما يقولونه. سيتذكرون ما يرغبون به، وسيتوقعون ذلك منك أيضًا. تحدث عن الكلمة المخيفة التي تبدأ بحرف الميم نعلم كلنا، أنه لا أحد يرغب بالتحدث عن كلفة الموقع. ستسألهم عن الميزانية المرصودة ، وسيخبرونك بعدم وجود واحدة، أو أنهم يرغبون منك أن تقدم لهم السعر أولاً. يمكنك أن توضح لهم أنه كي تتمكن من اتخاذ القرار إن كنت قادرًا على القيام بالمهمة أم لا، فأنت بحاجة لمعرفة ما يتوقعون إنفاقه. إذ لدى الجميع فكرة أولية في رأسهم. إن أصروا على عدم إخبارك، ضع عرضك وكأن لديهم ميزانية مفتوحة. حتى هذه النقطة، لقد قمت بكل ما باستطاعتك القيام به، فإن قالوا إن السعر مرتفع، فهذا يعني أنهم بدأوا العلاقة معك بكذبة لأنهم يعلمون تقريبًا ماهي كلفة المشروع. ضع في اعتبارك أن لدى معظم الشركات ميزانية، وإن لم ينفقوا الميزانية المخصصة لشيء ما كاملة، فإنهم يفقدونها في نهاية العام. كنت أظن في السابق، أنه لا يتوجب عليك إعطاء السعر مقدمًا لأنه سيقيّدك. لكنني اكتشفت مع مرور الوقت أن ذلك غير صحيح. سيختارك العملاء على الأغلب لأنك كنت الوحيد الذي تحدثوا معه، ولديه فكرة عن التكلفة. وهذا يبين أنك تملك ما يكفي من الخبرة لتخبرهم الرقم. ويبين أيضًا أنك أجريت أبحاثك مسبقًا عن مجال عملهم (الأمر الذي ينبغي عليك القيام به قبل الاجتماع)، وبأنك على دراية أكبر مما تحدثت به في الاجتماع. بعد كل ما ذكرناه، يتطلب الأمر وقتًا لتحديد سعرك النهائي. لذا إن كنت مبتدئًا في العمل الحرّ، يفضل أن تُبقِيَ السعر لنفسك حتى تكون قد حسبته جيدًا على الورق وقدمت العرض. و الآن أصبحت جاهزًا الآن وبعد أن أنهيت الاجتماع الأوّلي، وأصبح لديك حدس برغبتك في العمل مع ذاك الشخص، و حددت الميزانية (آمل ذلك)، حان وقت الانتقال إلى المرحلة التالية. من الأفضل منحهم إطارًا زمنيًا لبضعة أيام لتقديم العرض ، وكن حريصًا على تسليمه لهم خلال ذاك الوقت. إن تأخرت فقد يعتبرون ذلك عاملاً أساسيًا لما سيحدث لاحقًا للمشروع. ترجمة - بتصرّف - للمقال Tips for Getting Through the Initial Web Design Client Meeting.
  2. لعلّ من أقوى ميّزات Sass الدّوالّ (mixins) ﻷنّها تسمح بتحديد نمط مُتكرِّر وعزله في صورة قطعة برمجيّة يمكن إعادة استخدامها مرارًا. مثال ذلك: عزل كلّ الخصائص المسؤولة عن تنسيق زرّ في صفحة الويب ثمّ —بدل الحاجة لتذكّر كل هذه الخصائص— جمعها في قطعة منفصلة يمكن استدعاؤها في مُحدِّد آخر (selector). هذا يحفظ أنماط الزرّ في موضع واحد ممّا يجعل تعديلها وتحديثها أسهل. المشكلة في هذا أنّ كثيرًا من دوّال Sass هذه تُكتب بأسلوب يجعل الخصائص مُكرّرة، وهذا قد يؤدي إلى حدوث أخطاء في عدة مواضع عند تحويلها إلى CSS بالإضافة إلى زيادة حجم الملفّ النّهائي دون طائل. صحيح أنّ استخدام Sass هو خطوةٌ على الطّريق الصّحيح لإنتاج CSS أخفّ حجمًا وأكثر اختصارًا ممّا قد يكتبه مبرمج متوسّط المستوى، لكنّك إن كنت مهووسًا بتحسين الأداء مثلي، فلن ترضى بوجود أدنى مقدار من التّكرار الّذي لا مُبرِّر له. سأدلكّ في هذه المقالة على كيفيّة تحسين مستوى CSS النّاتج عن دوالّ Sass الّتي تكتبها. مقدّمة سريعة عن Sassيمكن وصف Sass بأنّها مرحلة وسيطة بين ورقة الأنماط الّتي يكتبها مُصمّم الموقع وناتج CSS النّهائي الّذي يطلبه المتصفّح، وتفيد Sass في هذه المرحلة بإضافة العديد من الميّزات الّتي تُسهلّ كتابة CSS وصيانتها. واحدة من فوائد Sass أنّها تُساعِد الُمصمّمين في تجنّب التّكرارات في CSS، ممّا يجعل صيانتها أكثر سهولة. اصطلح على مبدأ "لا تُكرِّر نفسك" (Don't Repeat Yourself أو اختصارًا DRY) في كتاب "المُبرمج البراغماتيّ"، والذي نصّ على التّالي: لا تُساعِدنا CSS كثيرًا في تطبيق هذا المبدأ، لأنّها تُضطرّنا إلى تكرار كتابة الكثير من الخصّائص (كما في مثال الأزرار الذي ضربناه). فلو احتجت إلى إنشاء أنماط لثلاثة أنواع من الأزرار، فستضطر إلى كتابة هذه الأنماط مرّة لكلّ نوع من الأزرار، أو تجزئة الأنماط على أكثر من مُحدّد. وهما أمران أحلاهما مُرٌّ. فالأوّل يعني نسخ الخصائص ولصقها (وزيادة حجم الملفّ بالنتيجة) وتكرار مواضع الأخطاء، وغياب مصدر واحدٍ للحقيقة، وبنية هشّة في حصيلة الأمر؛ وأمّا الثاني فيعني غياب تمثيل مُفرد ومُوحَّد لكلّ نوع من الأزرار في النّظام، لأنّه يُجبرك على تجزئة الأنماط على عدّة مُحدِّدات، وهو ما يجعل البنية هشّة أيضًا، لأنّ تكوينها غير واضح. لو أردنا تحرّي المثاليّة، فعلينا إيجاد طريقة لتعريف الأنماط الأساسيّة في موضع واحد دون تكرار، ثمّ تعريف مُحدِّد مُفرد يمكن استخدامه لتطبيق كلّ الأنماط. لماذا قد أرغب باتّباع مبدأ "لا تُكرِّر نفسك"؟قد تسأل نفسك: لم كلّ هذا التّعقيد؟ الجواب باختصار: لأنّ اتّباع مبدأ DRY يُحسّن من أداء الموقع. فعندما تؤسّس هيكل الموقع، سيكون الأداء عاملًا مُهمًّا، بدءًا من صيغ الصّور الّتي نختارها ومرورًا بطريقة كتابة مُحدِّدات CSS. وهذا العاملّ يُصبح أكثر أهمّية عندما نتحدّث عن الأجهزة المحمولة، ففي هذه الأجهزة قد يفرض مُجرّد طلب HTTP بسيط تحدّيات كبيرةً في الأداء، وخطأ الاعتقاد الشّائع بعدم أهمّيّة حجم ملفّ CSS في أداء الموقع يظهر أكثر وضوحًا في الأجهزة المحمولة الّتي لا تسمح بأكثر من 100 ميغابايت من الحجم الكلّي للتّخزين المؤقّت لكلّ المواقع، وعندها يجب استغلال أكبر مقدار ممكن من مساحة التّخزين المؤقّت بأفضل صورة. الهدف من ذلك إذن هو إنشاء مُحدِّدات يمكن صيانتها في Sass وفي HTML، ويمكن تمثيلها في CSS بأقصر أسلوبٍ ممكن لتقليل حجم التّخزين المؤقّت. الدّوال (mixins) والتّوسعة (extends): حلّان غير كاملينتٌقدّم دوالّ Sass حلًّا لإحدى هاتين المُشكلتين، فهي تسمح بإنشاء موضع واحد يمكن فيه تعريف الأنماط الأساسيّة والرّجوع إليها. يمكن لهذه الدّوال أن تقبل مُعاملات (arguments) كذلك، مما يسمح باختلافات طفيفة بين استدعاء وآخر للدّالة وإنشاء أشكال مختلفة لنفس النّمط. لكن الأمر لا يخلو من مُشكلات: فقد تُسبّب هذه الدّوال تكرارًا غير مُبرّر للخصائص لأنّها ستكتب الخصائص الّتي تحويها في كلّ موضع استدعيت فيه. فالدّوالّ إذن تحل مشكلة التُمثيل المُفردّ في مبدأ DRY، لكنّها تترك خصائص متكرّرة في النّاتج النّهائيّ من CSS. ولهذا تُقدّم Sass مفهومًا آخر يُساعِد في تطبق مبدأ DRY: التّوسعة (extends)، والّتي يمكن استخدامها بكتابة الكلمة ‎@extend، والّتي تسمح لمُصمّم CSS أن يقول: "أريد للُمحدّد A أن يظهر كما يظهر المُحدّد B"، وعندها تقوم Sass بإنشاء نمط جديد يجمع بين A وB (مفصول بينهما بفاصلة)، ثمّ كتابة الخواصّ غير المشتركة بالأسلوب العاديّ. لا يمكن تمرير مُعاملات للتّوسعة (خلافًا للدّوالّ)، فهي حلّ من نوع "الكلّ أو لا شيء". .couch { padding: 2em; height: 37in; width: 88in; z-index: 40; } .couch-leather { @extend .couch; background: saddlebrown; } .couch-fabric { @extend .couch; background: linen; } .couch, .couch-leather, .couch-fabric { padding: 2em; height: 37in; width: 88in; z-index: 40; } .couch-leather { background: saddlebrown; } .couch-fabric { background: linen; } تحلّ التّوسعة مشكلة تكرار الخصائص والمُحدِّد المُفرّد في CSS النّاتج، لكنّها لا تُخلّص مُصمّمي المواقع من الحاجة لصيانة مجموعتين منفصلتين من الأنماط في ملفّات Sass، ولا من الحاجة لتذكّر أيّ الخصائص ينطبق على أيّ نوع—فالأمر لا يختلف كثيرًا فيما لو كتبنا محدّدين منفصلين في الأساس. كما نرى، فكلا الحّلين (الدّوالّ والتّوسعة) غير كاملين، ولكن عند جمعهما معًا ثمّ اعتماد بنيّة ذكيّة في تصميم مشروعنا، مع الاستفادة من بعض ميّزات Sass سنحصل على دالّة نهائيّة تخضع لمبدأ DRY تمامًا، وتجمع نصفي الحلّ في صيغة موحّدة سواءٌ في ملفّات Sass الأصليّة أو في ناتج CSS. المكوّنات الأساسيّة لمبدأ "لا تُكرِّر نفسك"تضع المُكوّنات الأربعة التّالية حجر الأساس لبناء دوالّ موافقة لمبدأ DRY في Sass: المُحدّدات بالنّيابة (placeholder selectors)، والجداول (maps)، والكلمة ‎@at-root، والدّالة unique-id()‎. المُحدّدات بالنّيابةوهي نوعٌ خاصّ من المُحدّدات يُستخدم مع الكلمة ‎@extend في Sass. تُكتب هذه المُحدّدات كما تُكتب الأصناف التّقليديّة (classes)، ولكنّها تبدأ بالرّمز % بدل النّقطة .، وتتصرّف عند توسعتها بصورة عاديّة، ولكنّها لا تُضاف إلى النّاتج النّهائيّ إلّا عند توسعتها. وكما في التّوسعة العاديّة، تُضاف خواصّ المحدّدات في الموضع الّذي عُرّف فيه المُحدّد. %foo { color: red; } .bar { @extend %foo; background: blue; } .baz { @extend %foo; background: yellow; } .bar, .baz { color: red; } .bar { background: blue; } .baz { background: yellow; } الجداول (maps)وهي نوعٌ من أنواع البيانات في Sass ‎3.3 (مثلها مثل الأرقام والسلاسل النّصيّة والقوائم) تتصرّف بطريقة مُشابهة للكائنات في JavaScript. تتألّف الجداول من أزواج مفتاح/قيمة (key/value)، حيث يمكن للمفتاح والقيمة أن يكونا أي نوع من أنواع البيانات في Sass (بما في ذلك الجداول نفسها). المفاتيح فريدة دومًا ويمكن الوصول إليها باسمها، ممّا يجعلها مثاليّة لتخزين البيانات المُميّزة واسترجاعها. $properties: ( background: red, color: blue, font-size: 1em, font-family: (Helvetica, arial, sans-serif) ); .foo { color: map-get($properties, color); }الكلمة ‎@at-rootقُدّمت هذه الكلمة في Sass ‎3.3، وهي تقوم بنقل الخواصّ المُعرّفة ضمنها إلى جذر ورقة الأنماط (أعلى مستوىً فيها)، بغض النّظر عن الموضع الّذي استخدمت فيه. الدّالّة unique-id()‎قدّمت في Sass ‎3.3 كذلك، وهي تُعيد مُعرّف CSS يُضمن كونُه فريدًا في كلّ عمليّة تحويل من Sass إلى CSS. كتابة دالّة بسيطةيتطلّب تحويل نمط مُتكرِّر إلى دالّة النّظرَ في الأنماط الأساسيّة المُكوّنة لها ثم تحديد ما المشترك بينها وما الذي يختلف بحسب مُدخَلات المستخدم. سنستخدم زرًّا بسيطًا كمثال في حالتنا: .button { background-color: #b4d455; border: 1px solid mix(black, #b4d455, 25%); border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; background-color: mix(black, #b4d455, 15%); border-color: mix(black, #b4d455, 40%); } }لتحويل هذا إلى دالّة، اختر الخصائص الّتي يتحكّم بها المستخدم (الديناميكيّة)، والخصائص الثّابتة. يُتحكّم بالخصائص الدّيناميكيّة عبر مُعامِلات تُمرّر إلى الدّالة، أمّا الخصائص الثّابتة فتكتب بالأسلةب العاديّ. في حالة الزّرّ الذي نُصمّمه، لا نريد سوى أن يتغيّر اللّون، ولهذا نستدعي الدّالّة بمُعامل اللّون، لُينتَج CSS كما نتوقّع: @mixin button($color) { background-color: $color; border: 1px solid mix(black, $color, 25%); border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; background-color: mix(black, $color, 15%); border-color: mix(black, $color, 40%); } } .button { @include button(#b4d455); }لا بأس بهذا الحلّ، ولكنّه سيؤدّي إلى تكرار خصائص كثيرة، افترض مثلًا أنّنا نريد إنشاء زرّ آخر بلون مختلف، عندها ستبدو شيفرة Sass كما يلي (دون تعريف الدّالّة): .button-badass { @include button(#b4d455); } .button-coffee { @include button(#c0ffee); }وستبدو شيفرة CSS كما يلي: .button-badass { background-color: #b4d455; border: 1px solid #879f3f; border-radius: 5px; padding: .25em .5em; } .button-badass:hover { cursor: pointer; background-color: #99b448; border-color: #6c7f33; } .button-coffee { background-color: #c0ffee; border: 1px solid #90bfb2; border-radius: 5px; padding: .25em .5em; } .button-coffee:hover { cursor: pointer; background-color: #a3d8ca; border-color: #73998e; }هناك الكثير من الخصائص المُكرَّرة هنا، لا نريد هذا! لذا سنلجأ إلى استخدام المُحدِّدات بالنّيابة. إزالة التّكرار من دالّةإزالة التّكرار من الدّالة يقتضي تجزئتها إلى أجزاء ثابتة وأخرى ديناميكيّة. الأجزاء الدّيناميكيّة هي ما سيستدعيه المستخدم، وأمّا الثّابتة فتحوي الأجزاء الّتي ستكون مُكرّرة فيما لو لم نجمعها في دالّة. @mixin button($color) { @include button-static; background-color: $color; border-color: mix(black, $color, 25%); &:hover { background-color: mix(black, $color, 15%); border-color: mix(black, $color, 40%); } } @mixin button-static { border: 1px solid; border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; } }الآن وقد فصلنا دالّتنا على جزأين، نريد أن نُوسِّع العناصر في button-static لتجنّب التّكرار. يمكن إنجاز ذلك باستخدام مُحدّد بالنّيابة بدل الدّالة، ولكن هذا يعني نقل المُحدّدات في ورقة الأنماط، لذا سنقوم بإنشاء مُحدّد بالنّيابة في الموضع ذاته ديناميكيًّا، بحيث يُنشأ حالما يُحتاج إليه ويبقى بترتيبه الأصليّ كما نتوقّع. لفعل ذلك، سنقوم أوّلًا بإنشاء مُتغيّر في النّطاق العامّ لحفظ أسماء المُحدّدات الدّيناميكيّة: $Placeholder-Selectors: ();ثمّ نتحرّى وجود مفتاح يُطابق محدّدنا في button-static، وسندعو هذا المفتاح "button" في الوقت الحالي. باستخدام الدّالّة map-get، سنحصل على قيمة المفتاح المطلوب أو القيمة null إن لم يُوجد، وفي الحالة الأخية سنُعيّن قيمته إلى مُتغيّر فريد (unique ID) باستخدام map-merge. سنستخدم الوسم ‎!global كوننا نريد كتابة قيمة متغيّر عُرِّف في النّطاق العامّ: $Placeholder-Selectors: (); // ... @mixin button-static { $button-selector: map-get($Placeholder-Selectors, 'button'); @if $button-selector == null { $button-selector: unique-id(); $Placeholder-Selectors: map-merge($Placeholder-Selectors, ('button': $button-selector)) !global; } border: 1px solid; border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; } }بعد معرفة وجود مُعرّف لمُحدّدنا، نُريد إنشاء هذا المُحدّد، ونفعل هذا باستخدام الكلمة ‎@at-root وصياغة تعويض القيم في النّصوص (‎#{}‎) لإنشاء مُحدّد بالنّيابة في جذر ورقة الأنماط اسمه هو المُعرِّف الفريد الّذي حصلنا عليه. محتويات هذا المُحدِّد ستكون استدعاء للدّالة الثّابتة (لاحظ الاستدعاءات المتداخلة! يا للرّوعة!). ثمّ نُوسّع هذا المُحدّد بالنّيابة ذاته، ممّا يُفعّله ويؤديّ لكتابة خواصّه إلى CSS. باستخدام مُحدّد بالنّيابة في هذه الحالة بدل توسعة مُحدّد تقليديّ كصنف (class)، فإنّ محتويات المُحدّد ستُضاف إلى CSS النّهائي فقط إن وُسِّع المُحدِّد، ممّا يسمح بتقليص حجم الملفّ. وباستخدام التّوسعة بدل كتابة الخصائص مباشرةً، نكون قد تجنّبنا تكرار الخصائص في الوقت ذاته. في النّهاية سيمنع هذا هشاشة النّاتج النّهائي من CSS، لأنّه في كلّ مرّة تُستدعى هذه الدّالة، فستكون الخصائص المُشتركة ضمنها مُشاركة بالفعل ضمن ناتج CSS، وليس فقط مرتبطة مع بعضها في مرحلة المُعالجة المسبقة لـCSS فحسب. $Placeholder-Selectors: (); // ... @mixin button-static { $button-selector: map-get($Placeholder-Selectors, 'button'); @if $button-selector == null { $button-selector: unique-id(); $Placeholder-Selectors: map-merge($Placeholder-Selectors, ('button': $button-selector)) !global; @at-root %#{$button-selector} { @include button-static; } } @extend %#{$button-selector}; border: 1px solid; border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; } }لكن مهلًا، فلم ننتهِ بعدُ. ستبقى هناك محتويات مُكرّرة في النّاتج النّهائي، وهذا شيء لا نريده (حيث سنخصل على مُحدّد يوسّع نفسه، وهذا لا نريده أيضًا). لتجنّب هذا، سُنضيف مُعاملًا إلى button-static يُحدّد إن كان يجب المُضيّ بعمليّة التّوسعة أم لا. سُنضيفه هذا إلى دالّتنا الدّيناميكيّة أيضًا، ونمرّره إلى دالّتنا الثّابتة، وفي النّهاية ستكون لدينا الدّوالّ التّالية: $Placeholder-Selectors: (); @mixin button($color, $extend: true) { @include button-static($extend); background-color: $color; border-color: mix(black, $color, 25%); &:hover { background-color: mix(black, $color, 15%); border-color: mix(black, $color, 40%); } } @mixin button-static($extend: true) { $button-selector: map-get($Placeholder-Selectors, 'button'); @if $extend == true { @if $button-selector == null { $button-selector: unique-id(); $Placeholder-Selectors: map-merge($Placeholder-Selectors, ('button': $button-selector)) !global; @at-root %#{$button-selector} { @include button-static(false); } } @extend %#{$button-selector}; } @else { border: 1px solid; border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; } } }بعد كلّ هذا العناء، أنشأنا لأنفسنا طريقة لتسهيل صيانة أنماط Sass وتوفير مُحدِّد مُفرد في HTML، وإبقاء حجم CSS في أدنى الحدود. فهمها بلغ عدد استدعاءات دالّة button في شيفرتنا، لن تُكرَّر الخصائص الثّابتة فيها. عند استدعاء دالّتنا لأوّل مرّة، سُتنشأ الأنماط الّتي فيها ضمن CSS في الموضع الّذي استدعيت فيه، ممّا يُحافظ على تراكب الأنماط بالتّرتيب المُتوقّع، ويقلّل هشاشة البنية. وبما أنّنا نسمح بعدّة استدعاءات للدّالّة نفسها، فبإمكاننا إنشاء "نكهات" مُختلفة بسهولة وصيانتها في كلا Sass وHTML. في هذه المرحلة سيكون لدينا مصدر Sass وناتج CSS كما يلي: .button-badass { @include button(#b4d455); } .button-coffee { @include button(#c0ffee); } .button-decaff { @include button(#decaff); } .button-badass { background-color: #b4d455; border-color: #879f3f; } .button-badass, .button-coffee, .button-decaff { border: 1px solid; border-radius: 5px; padding: .25em .5em; } .button-badass:hover, .button-coffee:hover, .button-decaff:hover { cursor: pointer; } .button-badass:hover { background-color: #99b448; border-color: #6c7f33; } .button-coffee { background-color: #c0ffee; border-color: #90bfb2; } .button-coffee:hover { background-color: #a3d8ca; border-color: #73998e; } .button-decaff { background-color: #decaff; border-color: #a697bf; } .button-decaff:hover { background-color: #bcabd8; border-color: #857999; } لاحظ كيف يُفصل بين الخصائص الثّابتة بفواصل في موضع تعريفها، ممّا يجعل تتبّع الأخطاء أسهل، ويحافظ على ترتيب النّصّ المصدريّ، ويقلّل حجم ملف CSS، وبحيث لا تُنشأ مُحدّدات جديدة إلّا للخصائص الّتي تتغيّر. أليس هذا رائعًا؟ المتابعةالحقيقة أنّ كتابة النّمط نفسه لكلّ دالّة لا يتوافق مع مبدأ DRY على الإطلاق؛ بل على العكس تمامًا فهو WET (اختصارًا لـWrite Everything Twice، هل لاحظت ظرافة المبرمجين؟!). لا نريد هذا، بل يجب أن نُفكّر في كتابة دالّة لتوليد المُحدّدات بالنّيابة، يمكننا استدعاءها بدل ذلك. أو في حال استخدام إضافة Toolkit لـSass (إما من خلال Bower أو كإضافة لـCompass)، فيمكن في هذه الحالة استخدام الدّالة dynamic-extend لإيجاد وإنشاء وتوسعة مُحدّد ديناميكيّ بالنّيابة. كلّ ما عليك فعله إرسال سلسلة نصيّة للبحث عنها (مثل "button"): @import "toolkit"; @mixin button($color, $extend: true) { @include button-static($extend); background-color: $color; border-color: mix(black, $color, 25%); &:hover { background-color: mix(black, $color, 15%); border-color: mix(black, $color, 40%); } } @mixin button-static($extend: true) { $button-selector: map-get($Placeholder-Selectors, 'button'); @if $extend == true { @include dynamic-extend('button') { @include button-static(false); } } @else { border: 1px solid; border-radius: 5px; padding: .25em .5em; &:hover { cursor: pointer; } } }وهكذا يمكن القضاء على أي تكرار في دالّتنا، مما يقلّل حجم ملفّات Sass الأصلية وملفّات CSS النّهائيّة معًا، ممّا يدفعنا خطوة على طريق إعادة استخدام مكوّناتنا في مشاريع أخرى. ترجمة (بشيء من التصرف) للمقال ‎DRY-ing out Your Sass Mixins‎ لصاحبه Sam Richard.