المحتوى عن 'واجهة'.



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

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

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

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 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

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

  1. نتابع عملنا في سلسلة تعلّم برمجة تطبيقات أندرويد باستخدام Xamarin.Forms. سنتعلّم في هذا الدرس تقنيّات جديدة لبناء واجهات متقدّمة أكثر باستخدام رماز XAML. كما سنتعلّم كيفيّة عرض رسائل تنبيه للمستخدم. يُعتبر هذا الدرس مساعدًا للدرس السابق في فهم كيفية التعامل مع رماز XAML. سنتناول في هذا الدرس تطبيقًا عمليًا مفيدًا، الهدف منه هو حل معادلة من الدرجة الثانيّة Quadratic Equation في مجموعة الأعداد الحقيقية R. كيفيّة حل معادلة من الدرجة الثانية للمعادلة من الدرجة الثانية الشكل العام التالي: لكي نحل هذه المعادلة في المجموعة R نحتاج إلى معرفة قيم المعاملات a وb وc وهي عبارة عن ثوابت حقيقيّة سنطلب من المستخدم أي يزوّد البرنامج بها. بعد ذلك سنطبّق القانون التالي لحساب مميّز هذه المعادلة: من خلال قيمة هذا المميّز نكون أمام ثلاث حالات: الحالة الأولى عندما يكون فيوجد عندئذ حلّين مختلفين للمعادلة المفروضة يمكن الحصول عليهما من العلاقتين التاليتين: الحالة الثانية عندما فيوجد عندئذ حل مضاعف يُعطى بالعلاقة التالية: الحالة الثالثة عندما فلا يكون للمعادلة عندها أي حل في المجموعة R. بناء تطبيق حل المعادلات من الدرجة الثانية ابدأ بإنشاء مشروع جديد من النوع Blank App (Xamarin.Forms Portable) وسمّه SDESolverApp، ثم أبق فقط على المشروعين SDESolverApp (Portable) و SDESolverApp.Droid كما وسبق أن فعلنا في هذا الدرس. بعد ذلك سنضيف صفحة محتوى تعتمد على رماز XAML كما وسبق أن فعلنا في الدرس السابق سنسمّها SDESolverPage. سنقسّم الواجهة إلى ثلاثة أقسام. القسم الأوّل العلوي سيحتوي على رسالة ترحيبيّة، أمّا القسم الأوسط فسيضم المنطقة الخاصّة بإدخال قيم المعاملات a وb وc الذين تحدثنا عنهم قبل قليل مع لصيقة توضيحيّة. أمّا القسم الأخير السفلي فسيحوي زرًا عند نقره سيتم حل المعادلة. انظر الشكل التالي لمعرفة الشكل العام لهذا التطبيق: في البداية أقترح وضع الواجهة السابقة ضمن مخطّط مكدّس يحيط بها بشكل كامل وذلك على الشكل التالي: <StackLayout> <StackLayout.Children> … </StackLayout.Children> </StackLayout> تمثّل النقاط الثلاث التي تظهر في الرماز السابق، المكان المفترض لرماز الواجهة الذي سنتحدّث عنه بعد قليل، حيث ستقع أي عناصر مرئيّة أخرى ضمن العنصر StackLayout.Children كما هو معلوم. لنجهّز الرسالة الترحيبيّة التي ستظهر في الأعلى. في الحقيقة تتألّف هذه الرسالة من عنصر إطار Frame يحوي لصيقة تعرض النص الترحيبي. يمكن استخدام الرماز التالي لتحقيق هذا الشكل: <Frame Padding="5" OutlineColor="Accent" BackgroundColor="#300000FF" VerticalOptions="StartAndExpand"> <Frame.Content> <Label Text="تطبيق حل المعادلات من الدرجة الثانية" FontSize="Large" TextColor="Accent" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="Center" /> </Frame.Content> </Frame> بالنسبة لعنصر الإطار Frame فقد ضبطنا الخاصيّة Padding له لإضافة حشوة صغيرة تحيط بمحتوياته. كما ضبطنا خصائص لون الحد الخارجي OutlineColor لتحمل اللون Accent وخاصيّة لون الخلفية BackgroundColor لتكون "#300000FF". القيمة السابقة هي قيمة ستة عشرية تتكوّن من أربعة مكوّنات. كل مكّون يحجز محرفين. هذه المكوّنات من اليسار إلى اليمين: قيمة الشفافيّة alpha وتتراوح بين 00 و FF (استخدمنا في هذا المثال القيمة 30)، ثم يأتي اللون الأحمر فالأخضر فالأزرق. فمن خلال القيمة "#300000FF" سيظهر معنا لون أزرق لكنّه شفّاف بعض الشيء. ضبطنا أيضًا خاصيّة التموضع الرأسي VerticalOptions لتكون StartAndExpand ليظهر الإطار في البداية (في الأعلى في هذا التطبيق). بعد ذلك تأتي الخاصيّة Frame.Content والتي يمكن إسناد عنصر مرئي واحد إليها. أسندنا لصيقة كما هو واضح في الرماز السابق، وضبطنا خصائصها ليكون حجم الخط كبيرًا ولونه Accent، كما جعلنا محاذاة النص ضمن اللصيقة في الوسط. تنحصر مهمّة عنصر الإطار في إكساب ناحية جمالية للصيقة التي يحتويها. لننتقل الآن إلى القسم الثاني الأوسط من واجهة التطبيق والذي يحتوي كما أشرنا على منطقة مدخلات المستخدم. سنضع هذا القسم بكامله ضمن مخطّط مكدّس. سيحتوي هذا المخطّط على ما يلي: 1- لصيقة ضمن إطار كما فعلنا تمامًا مع الرسالة الترحيبيّة السابقة في القسم العلوي. تحوي هذه اللصيقة نصًّا توضيحيًّا. لننظر إلى الرماز المسؤول عن إظهار اللصيقة التي تحتوي على النص التوضيحي: <StackLayout VerticalOptions="CenterAndExpand"> <StackLayout.Children> <Frame Padding="5" OutlineColor="Green" BackgroundColor="#3000FF00"> <Frame.Content> <Label Text="أدخل المعاملات التالية لإيجاد حل المعادلة " FontSize="Medium" TextColor="Lime" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="End" /> </Frame.Content> </Frame> ... </StackLayout.Children> </StackLayout> النقاط الثلاث الموجودة ضمن الرماز السابق هي مكان الرماز الذي سيُظهِر مربّعات النص المسؤولة عن استقبال الدخل من المستخدم، حيث تجنبّت وضعه صراحةً لكي نركّز الآن على الرماز الحالي. لاحظ عنصر الإطار Frame كيف يحتوي ضمن الخاصيّة Content له على اللصيقة التي تعرض العبارة "أدخل المعاملات التالية لإيجاد حل المعادلة". لقد ضبطت الخاصيّة HorizontalTextAlignment لها لتكون End أي ليظهر النص كما لو أنّه محاذًا نحو اليمين. 2- مخطّط مكدّس آخر لعرض مربّعات الإدخال Entry لاستقبال الدخل من المستخدم، وهو يقع أسفل الإطار الذي يحوي اللصيقة التي تعرض العبارة التوضيحيّة (انظر رقم 1): <StackLayout VerticalOptions="CenterAndExpand"> <StackLayout.Children> ... <StackLayout Orientation="Horizontal"> <StackLayout.Children> <Entry x:Name="txtA" HorizontalOptions="StartAndExpand" Placeholder="المعامل a" FontSize="Medium" Keyboard="Telephone" /> <Entry x:Name="txtB" HorizontalOptions="CenterAndExpand" Placeholder="المعامل b" FontSize="Medium" Keyboard="Telephone" /> <Entry x:Name="txtC" HorizontalOptions="EndAndExpand" Placeholder="المعامل c" FontSize="Medium" Keyboard="Telephone" /> </StackLayout.Children> </StackLayout> </StackLayout.Children> </StackLayout> الأمر الواضح هنا أنّني قد وضعت مربّعات النص Entry لاستقبال الدخل من المستخدم ضمن مخطّط مكدّس آخر، وهذا أمر طبيعي تمامًا في تصميم الواجهات. لقد جعلت خاصيّة الاتجاه Orientation لهذا المكدّس تحمل القيمة Horizontal أي أفقي. كما وضعت ضمن العنصر StackLayout.Children ثلاثة عناصر Entry لاستقبال المعاملات a وb وc على الترتيب. من الملاحظ أنّني استخدمت الخاصيّة x:Name لكلّ من هذه العناصر لكي نستطيع الوصول إلى محتوياتها ضمن ملف الشيفرة البرمجيّة المرافق لملف الرماز كما سنرى بعد قليل. كما استخدمت الخاصيّة Placeholder لكلّ منها لعرض نص توضيحي ضمن عنصر Entry يوضّح وظيفته. الأمر الأخير الملاحظ هنا هو استخدامي للخاصيّة Keyboard للعنصر Entry التي تسمح بتحديد لوحة المفاتيح التي ستظهر للمستخدم عندما يحاول الكتابة ضمن هذا العنصر. توجد عدّة لوحات مفاتيح تدعمها Xamarin.Froms. لقد استخدمت من أجل هذا المثال لوحة المفاتيح Telephone وهي لوحة مفاتيح مخصّصة لإدخال البيانات المتعلّقة بأرقام الهواتف. في الحقيقة توجد لوحة مفاتيح مخصّصة للأرقام اسمها Numeric ولكنّني آثرت لوحة مفاتيح Telephone عليها لأنّها تدعم إدخال إشارة السالب (-) وهذا ما لا توفّره لوحة المفاتيح الرقميّة القياسيّة Numeric. ننتقل الآن إلى القسم الأخير السفلي من الواجهة، وهو يحتوي على زر بسيط عندما ينقره المستخدم سيعمل البرنامج على حل المعادلة ويعرض النتيجة. انظر إلى الرماز الخاص به: <Button Text="حل المعادلة"` VerticalOptions="EndAndExpand" HorizontalOptions="FillAndExpand" HeightRequest="64" Clicked="btnSolve_Clicked"/> استخدمت هذه المرّة الخاصيّة HeightRequest التي يمكن من خلالها ضبط ارتفاع العنصر بشكل تقريبي. لقد جعلت ارتفاعه مساويًا لـ 1 سم تقريبًا. توجد خاصيّة أخرى مشابهة لها لضبط عرض أي عنصر بشكل تقريبي وهي WidthRequest. ضبطّت أيضًا معالج الحدث Clicked الذي سيتم تنفيذه عندما ينقر المستخدم على هذا الزر. اسم هذا المعالج btnSolve_Clicked وسيكون في الطبع ضمن ملف الشيفرة البرمجيّة. إليك الآن الرماز الكامل لهذا لواجهة هذا التطبيق مجمّعًا على الشكل التالي: <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SDESolverApp.SDESolverPage" Padding="5"> <StackLayout> <StackLayout.Children> <Frame Padding="5" OutlineColor="Accent" BackgroundColor="#300000FF" VerticalOptions="StartAndExpand"> <Frame.Content> <Label Text="تطبيق حل المعادلات من الدرجة الثانية" FontSize="Large" TextColor="Accent" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="Center" /> </Frame.Content> </Frame> <StackLayout VerticalOptions="CenterAndExpand"> <StackLayout.Children> <Frame Padding="5" OutlineColor="Green" BackgroundColor="#3000FF00"> <Frame.Content> <Label Text="أدخل المعاملات التالية لإيجاد حل المعادلة " FontSize="Medium" TextColor="Lime" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="End" /> </Frame.Content> </Frame> <StackLayout Orientation="Horizontal"> <StackLayout.Children> <Entry x:Name="txtA" HorizontalOptions="StartAndExpand" Placeholder="المعامل a" FontSize="Medium" Keyboard="Telephone" /> <Entry x:Name="txtB" HorizontalOptions="CenterAndExpand" Placeholder="المعامل b" FontSize="Medium" Keyboard="Telephone" /> <Entry x:Name="txtC" HorizontalOptions="EndAndExpand" Placeholder="المعامل c" FontSize="Medium" Keyboard="Telephone" /> </StackLayout.Children> </StackLayout> </StackLayout.Children> </StackLayout> <Button Text="حل المعادلة" VerticalOptions="EndAndExpand" HorizontalOptions="FillAndExpand" HeightRequest="64" Clicked="btnSolve_Clicked"/> </StackLayout.Children> </StackLayout> </ContentPage> لننتقل إلى ملف الشيفرة البرمجيّة المرافق لملف الرماز السابق. اسم هذا الملف بالطبع هو SDESolverPage.xaml.cs. احرص على أن تكون محتوياته على الشكل التالي: 1 using System; 2 using Xamarin.Forms; 3 4 namespace SDESolverApp 5 { 6 public partial class SDESolverPage : ContentPage 7 { 8 public SDESolverPage() 9 { 10 InitializeComponent(); 11 } 12 13 private void btnSolve_Clicked(object sender, EventArgs e) 14 { 15 double a, b, c; 16 17 string txt_a = txtA.Text; 18 string txt_b = txtB.Text; 19 string txt_c = txtC.Text; 20 21 if (double.TryParse(txt_a, out a) && 22 double.TryParse(txt_b, out b) && 23 double.TryParse(txt_c, out c)) 24 { 25 string result; 26 27 double delta = b * b - 4 * a * c; 28 29 if (delta > 0) 30 { 31 //there are two different solutions. 32 double x1 = (-b + Math.Sqrt(delta)) / (2 * a); 33 double x2 = (-b - Math.Sqrt(delta)) / (2 * a); 34 35 result = string.Format("يوجد حلين مختلفين في المجموعة R\nx1 = {0}\nx2 = {1}", 36 x1.ToString("#0.#"), 37 x2.ToString("#0.#")); 38 } 39 else if (delta == 0) 40 { 41 //there are two equal solutions. 42 double x = -b / (2 * a); 43 44 result = string.Format("يوجد حل مضاعف في المجموعة R\nx1 = x2 = {0}", 45 x.ToString("#0.#")); 46 } 47 else 48 { 49 //there is no solutions in R. 50 result = "المعادلة مستحيلة الحل في المجموعة R"; 51 } 52 53 DisplayAlert("الحل", result, "موافق"); 54 } 55 else 56 { 57 DisplayAlert("خطأ في المدخلات", "بعض المعاملات المدخلة غير صحيحة", "موافق"); 58 } 59 } 60 } 61 } يحتوي الصنف SDESolverPage بشكل أساسيّ على معالج الحدث btnSolve_Clicked الذي سيُستدعى عندما ينقر المستخدم زر حل المعادلة من الواجهة. يحتوي هذا المعالج على كامل منطق التطبيق. يحصل البرنامج على قيم المعاملات في الأسطر من 17 حتى 19 حيث تكون قيم نصيّة بالطبع، ثمّ يحوّل هذه القيم النصيّة إلى قيم من النوع double وذلك في الأسطر من 21 حتى 23 من خلال استخدام التابع الساكن TryParse من الصنف double. يحاول هذا التابع أن يحوّل القيمة النصيّة المُمرّرة إليه في الوسيط الأوّل، فإن نجح في ذلك فإنّه يُسند القيمة المُحوّلة إلى المتغيّر a الذي نمرّره كوسيط ثانٍ إلى هذا التابع ويُرجع التابع القيمة true. أمّا إذا فشلت عمليّة التحويل فإنّ التابع سيُرجع القيمة false فيختلّ شرط عبارة if، وبالتالي لن يُتابع البرنامج عمله في حل المعادلة ويعرض رسالة بهذا الخصوص إلى المستخدم بسبب عدم صلاحيّة أحد العوامل المُدخلة على الأقل. لاحظ أنّنا قد مرّرنا الوسيط الثاني الذي سيحمل نتيجة التحويل في حال نجاحه باستخدام الكلمة المحجوزة out. التي تسمح بتمرير عنوان المتغيّر إلى التابع وليس قيمته. يتابع البرنامج عمله في حال نجحت عمليّة تحويل المعاملات إلى double بحساب مميّز المعادلة ومقارنته بالحالات الثلاث المختلفة التي تحدثنا عنها مسبقًا. توجد ملاحظة أخيرة في أنّ التطبيق يعرض النتائج باستخدام صناديق رسائل قياسيّة في أندرويد، وذلك من خلال استخدام التابع DisplayAlert وهو من الصنف Page (السطران 53 و57) أيّ أنّه ينتمي إلى الصنف SDESolverPage من خلال الوراثة. يخضع التابع DisplayAlert لزيادة التحميل، وقد استخدمت الشكل الذي يتطلّب ثلاثة وسائط وهي بالترتيب عنوان الرسالة، والرسالة المراد عرضها، ثم النص المراد عرضه على الزر. يمكن بالطبع استخدام وسائل مختلفة لعرض النتائج للمستخدم، كعرضها ضمن صفحة منفصلة مثلًا، وقد يكون هذا الأسلوب أفضل. ولكن بالنسبة إلى هذه المرحلة فالحل المستخدم في هذا التطبيق يُعتبر جيّدًا. سنتعلّم مستقبلًا كيفيّة التعامل مع عرض المعلومات المختلفة عن طريق صفحات مستقلّة. الخلاصة بنينا في هذا الدرس تطبيقًا عمليًّا، يوضّح التعامل مع رماز XAML بشكل متقدّم أكثر. في الحقيقة ستحتاج إلى تطوير العديد من البرامج البسيطة كهذا البرنامج كي تتمكّن من تصميم الواجهات بشكل جيّد. سنتابع في الدروس القادمة العمل في تطوير تطبيقات عمليّة بسيطة ومفيدة، يمكن من خلالها تعلّم المزيد عن بناء الواجهات باستخدام XAML.
  2. إن بعض مواقع الإنترنت تُصمّم برسوميات بسيطة مسطّحة والبعض الآخر تكون مصمّمة برسوميات أنيقة عالية الدقة وغير مسطّحة، فأحيانًا تكون الواجهات بسيطة وتفي بالغرض وأحيانًا تكون ذات رسوميات عالية الجودة والأناقة وهو ما يجعل الموقع أجمل وأكثر متعة في التصفح والمتابعة، لذلك سنتعلّم في هذا الدرس كيفية تصميم بنرات لاختيار الخطط لأحد مواقع الاستضافة على سبيل المثال. سيتضمّن هذا الدرس شرحًا لمجموعة من الأدوات والمزايا المهمة والمميزة والتي ستصقل مهاراتكم كمصممين مبدعين. يمكنكم طبعًا تعديل النصوص بما يتناسب مع موقعكم أو مع حاجة العميل كما يمكنكم التعديل على الألوان والأحجام وعدد المقاطع وغيرها… وسنتعلّم كيفية إنشاء هذه الأشكال بدون اللجوء إلى أداة القلم لمن لم يتمكّن من هذه الأداة بعد، بحيث أننا لن نستخدم هذه الأداة في هذا الدرس، وسنقوم بإنشاء انعكاسات الإضاءة على حواف البنرات بشكل يدوي، وسنتعلّم كيفية إنشاء فرشاة جديدة واستخدامها وكذلك كيفية استخدام خصائص المزج والتلوين بالألوان والتدرجات اللونية وإنشاء نصوص ثلاثية الأبعاد والكثير من التقنيات في الرسم. افتح برنامج أدوبي إليستريتور ثم أنشئ مستندًا جديدًا بحجم 650×650 بكسل وبما أننا نصمم للويب فيجب أن يكون نظام الألوان هو RGB. سنقوم الآن بصنع الخلفية عبر إنشاء مربع بحجم المستند نفسه. اختر أداة المستطيلات Rectangle Tool ثم انقر نقرًا مزدوجًا على لوح الرسم لتفتح نافذة إنشاء المستطيلات، أدخل القيم 650×650 ثم ضع هذا المربع ليملأ لوح الرسم بالكامل. يمكنك الاستعانة بالأدلّة الذكية للقيام بوضع المربع في مكانه بسهولة، حيث ستساعدك على القيام بذلك وتعمل هذه الميزة من خلال الاختصار Ctrl+U. لوّن هذا المربع بتدرج لوني دائري من الأزرق (R:19 – G:94 – B:169) إلى الأزرق الفاتح (R:104 – G:201 – B:134) مع جعل موقع الفاصلة المتوسطة عند 37% تقريبًا لجهة الأزرق الفاتح. استخدم أداة التدرج اللوني Gradient Tool من خلال الاختصار M لرسم اتجاه وموقع مركز التدرج اللوني كما في الصورة التالية. افتح لوحة الطبقات من خلال الاختصار F7 ثم اقفل طبقة الخلفية حتى لا تتأثر بالأعمال التالية، وأنشئ طبقة جديدة لنقوم بالعمل عليها. ارسم مستطيلًا باستخدام أداة رسم المستطيلات بحجم 550×100 وضعه في وسط أعلى لوح الرسم. أزِل الحدود وأبقِ على اللون الأبيض للتعبئة مؤقّتًا. سنقوم بجعل الزاوية السفلى اليسرى من المستطيل منحنية بدون استخدام أداة القلم لرسم هذا الشكل، ولكن باستخدام أحد التأثيرات. لنتمكّن من ذلك سنقوم بقص المستطيل إلى نصفين، استخدم أداة المقص Scissors Tool لقص المستطيل من النقطة العليا إلى السفلى الموضحة في الصورة. والآن حدّد المسار النصفي الأيسر واذهب إلى القائمة Effect > Stylize > Round Corners ثم أدخل القيمة 60px واضغط OK. حدّد كلا الشكلين واذهب إلى القائمة Object > Expand Appearance حدّد كلا الشكلين مجدّدًا ثم اختر الخيار Unite من لوحة Pathfinder لتوحيد الشكلين في شكل واحد. لوّن الشكل الجديد بتدرّج لوني دائري من الأسود إلى الأبيض مع وضع اللون الأسود في الموقع 40% تقريبًا وذلك ليطغى اللون الأسود أكثر على التدرج. ثم ضع خيار Aspect Ratio على القيمة 30% ليتم ضغط التدرج شاقوليًّا واستخدم أداة التدرج اللوني لرسم اتجاه وحجم التدرج كما في الصور التالية. افتح لوحة الشفافية Transparency من خلال الاختصار Shift+Ctrl+F10 ثم اختر الخيار Color Dodge من خصائص المزج. سنقوم الآن برسم انعكاس زجاجي على كامل مساحة البنر. ارسم مستطيلًا بنفس حجم المستطيل الأساسي ثم ضعه فوق البنر تمامًا. ارسم شكلًا بيضويًا يغطّي جزءًا كبيرًا من المستطيل ثم دوّره بزاوية مائلة قليلًا كما في الصورة وضعه فوق النصف السفلي من المستطيل. حدّد كلا هذين الشكلين ثم اختر الخيار Minus Front من لوحة Pathfinder ليتم قص الشكل البيضوي من شكل المستطيل. استخدم أداة التدرج اللوني بنفس الطريقة كما في الصورة لجعل اللون الأسود في التدرج اللوني طاغيًا على الشكل. ثم اذهب مجدّدًا إلى لوحة الشفافية وطبّق خصائص المزج Color Dodge على الشكل الأخير. سنلاحظ بأنه هناك جزء صغير زائد عند الزاوية المنحنية في الجهة السفلية اليسرى من الشكل الأساسي لذلك سنقوم بقصّه من الشكل الجديد وذلك عبر مضاعفة الشكل الأساسي الموجود في الأسفل ثم نحدّد الشكل المضاعف مع الشكل الجديد ونختار الخيار Intersect من لوحة Pathfinder لنحصل على الشكل المطلوب. هذا هو الشكل الذي حصلنا عليه حتى هذه اللحظة، وهو ما يمثّل البنر الذي سنستخدمه لاحقًا، سنضيف عليه في الخطوات اللاحقة الإضاءات والانعكاسات التي ستضفي عليه المزيد من الحيوية والأناقة والشعور بشفافية المادة الزجاجية ولمعانها وألقها. ارسم دائرة صغيرة أسفل منتصف البنر باستخدام أداة رسم الأشكال البيضوية مع استعمال مفتاح Shift أثناء الرسم للمحافظة على تساوي الأبعاد والحصول على دائرة مثالية. لوّنها بتدرج لوني دائري من الأسود إلى الأبيض. غيّر خصائص المزج من لوحة الشفافية إلى Color Dodge. استخدم أداة التحديد Selection Tool لشد وسحب أطراف الدائرة وجعلها بعرض البنر تقريبًا وبارتفاع ضئيل للحصول على انعكاس إضاءة سفلي مع وضع هذا الانعكاس على حافة البنر السفلية. ضاعف هذا الشكل واسحبه إلى الحافة العلوية واجعل ارتفاعه أكبر بقليل لنحصل على الإيحاء بأن مصدر الإضاءة المسلطة على البنر الزجاجي من الأعلى. انسخ هذا الشكل وعدّل بزاويته وحجمه وضعه عند الحافة اليمنى من البنر واجعله أكثر رقة. سنقوم بتشكيل الانعكاس على الحافة المنحنية. وللقيام بذلك سنقوم بإنشاء فرشاة جديدة تمثّل الانعكاس. ارسم دائرة صغيرة جدًّا سوداء ومن ثم ارسم دائرة بحجم نقطة تقريبًا بيضاء في مركز الدائرة السوداء، حدّد الدائرتين معًا واذهب إلى القائمة Object > Bend > Make ثم اذهب إلى القائمة Object > Bend > Bend Options واختر الخيار Specified Steps وأدخل القيمة 50 ثم اضغط OK. لاحظ حجم الدائرة الجديدة بالنسبة لحجم البنر الكلي. مجدّدًا اجعل خصائص مزج هذه الدائرة Color Dodge. افتح لوحة الفراشي Brushes ثم اسحب شكل الدائرة إلى داخل قائمة الفراشي لتتم إضافتها إلى هذه القائمة. اختر Art Brush من القائمة. اترك الإعدادات كما هي واضغط OK. وهنا تظهر الفرشاة الجديدة ضمن لوحة الفراشي. والآن استخدم أداة رسم القوس Arc Tool وارسم قوسًا عند تلك الحافة المنحنية وعدّل بمقابض البيزير حتى يتوازى القوس مع الحافة. طبّق الفرشاة الجديدة على شكل القوس وخفّف حجم الحدود Stroke إلى 0.25pt. وبهذا يكون شكل البنر الزجاجي قد أصبح مكتملًا وجاهزًا للاستخدام. حدّد جميع الأشكال التي يتألف منها البنر ثم انقر بالزر الأيمن فوقها واجمعها في مجموعة واحدة عبر الخيار Group وذلك ليسهل علينا التعامل معها كشكل واحد أثناء نسخها وتحريكها فيما بعد. اسحب نسخة عن البنر نحو الأسفل بالاستعانة بالأدلة الذكية للمحافظة على ثبات المحور العمودي مع الضغط على مفتاح Alt أثناء السحب باستخدام أداة التحديد Selection Tool. اضغط على الاختصار Ctrl+D للحصول على نسختين إضافيتين بنفس المسافة بين البنرات ويصبح لدينا أربعة بنرات. حدّد جميع البنرات ثم اذهب إلى القائمة Object > Expand Appearance سنقوم الآن بكتابة المحتوى المطلوب بداخل البنرات، وبما أننا نتحدّث عن موقع للاستضافة فسيكون المحتوى عبارة عن خطط الاستضافة التي يوفرها الموقع لذلك سنضع أرقامًا لهذه الخطط وشرحًا بسيطًا عن الخدمات المُتضمنّة في كل خطة. استخدم أداة النص واكتب الأرقام من واحد إلى أربعة على يمين كل بنر وكبّر حجم الخط لنحو 107 واستخدم خطًّا عريضًا كخط Simplified Arabic. سنحوّل هذه الأرقام إلى أشكال ليسهل التعامل معها. حدّد الأرقام ثم اذهب إلى القائمة Type > Create Outlines أو اضغط على الاختصار Shift+Ctrl+O. انسخ Ctrl+C وألصق في المقدمة Ctrl+F هذه الأرقام وغيّر لونها مؤقتًا إلى الأصفر مثلًا لتمييزها. سنحوّل الأرقام الجديدة إلى مسارات مركّبة عبر تحديدها والذهاب إلى القائمة Object > Compound Path > Make أو عبر الاختصار Ctrl+8. تأكّد من تحديد المسارات المركبة ثم استخدم مفاتيح الأسهم لتحريكها نحو الأعلى واليمين قليلًا. حدّد المسارات المركبة مع شكل الأرقام الصفراء ثم اختر الخيار Minus Front من لوحة Pathfinder. لقد تمّ قص الأرقام الصفراء وبقي منها ما يشبه الحواف للأرقام الأصلية السوداء وهذا ما يمنحها الشعور بأنها ثلاثية الأبعاد. لوّن هذه الأرقام السوداء بلون رمادي متوسط ثم غيّر خصائص المزج إلى Multiply. حدّد أشكال الحواف الصفراء ولوّنها بتدرج لوني من الأبيض إلى الأسود مع جعل زاوية التدرج عند 135 درجة ضمن لوحة التدرجات اللونية. وبذلك نحصل على أرقام ثلاثية الأبعاد على يمين البنرات. قم بتغيير خصائص مزج شكل الحواف إلى Color Dodge لتتناسق الألوان مع بقية التصميم وتظهر الأرقام وكأنها زجاجية أيضًا. املأ البنرات بالمحتوى المناسب باستخدام أداة النص أو عبر برمجة الصفحة ذاتها، الخيار متروك لك لتقوم بالمناسب.
  3. في الدرس السابق قمنا باستخدام برنامج فوتوشوب لتصميم واجهة موقع لغابة افتراضية باسم "Pinewood Forest". أمّا في هذا الدرس فسوف نقوم بتكويد ذلك التصميم باستخدام لغتي HTML وCSS وتحويله إلى صفحة ويب كاملة. كما سنقوم أيضًا باستخراج الصور الموجودة في التصميم لاستعمالها في الموقع. في حال أنك لم تقرأ الدرس السابق، أنظر إلى الصورة في الأعلى لترى التصميم الذي سوف نقوم بتكويده. يحتوي الموقع على صورة خلفية كبيرة وثابتة لتسمح لمحتوى الموقع بالتمرير(scroll) فوقها، والمحتوى نفسه مجزأ إلى عدة أجزاء، وتم استخدام مجموعة من الصور لجذب انتباه الزائر. استخراج الصور الموجودة في التصميم ستكون الخطوة الأولى قبل البدء بتكويد التصميم هي استخراج الصور من التصميم. بعض أجزاء التصميم يمكن عملها باستخدام CSS فقط ولكن أجزاء أخرى من التصميم سنحتاج فيها إلى الصور. يحتوي الجزء الرئيسي للموقع على صورة خلفية كبيرة، وسوف نحتاج إلى ضغط هذه الصورة لتقليل حجمها الكبير وذلك عن طريق اللجوء إلى خيار Save for web. كما قلنا سابقًا، سيحتوي الموقع على خلفية ثابتة وسوف يظهر المحتوى فوق هذه الصورة، وبالتالي فإن العناصر مثل الشّعار سنحتاج إلى استخراجها بصيغة PNG-24 لأن هذه الصيغة تدعم الشفافية (transparency). ستكون خلفية المحتوى الرئيسي للموقع ذات طابع شفاف أيضًا وبالتالي سوف نحتاج إلى استخراجها بصيغة PNG، وهذه الخلفية سيتم تقسمها إلى ثلاثة أقسام؛ قسم علوي وقسم سفلي وقسم مكرر في المنتصف. المجموعة النهائية للصور سوف تحتوي على صور بصيغة PNG وأخرى بصيغة JPEG. بعض الصور ستكون بحجم صغير، وهذه الصور سيتم تكريرها (باستخدام CSS) لإنشاء خلفيات مزخرفة، أمّا الصور الأخرى فسوف تكون صورًا بديلة عن النصوص لاستخدامها كعناوين. بنية ملف HTML <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Visit Pinewood Forest</title> <link href="styles.css" rel="stylesheet" /> </head> <body> <div id="container"> </div> </body> </html> سيحتوي الملف الرئيسي (index file) على أكواد HTML. يُستخدم <doctype html!> لتعريف المتصفح بإصدار HTML المُستخدم ويعتبر أيضًا من الممارسات الجيدة في عالم تصميم الويب، لذلك احرص على أن يكون موجودًا في كل موقع تقوم بتصميمه. يتبع ذلك وسم <head> ويحتوي هذا الوسم على عنوان الصفحة وعلى رابط لملف CSS. وأخيرًا يوجد وسم <div> وسيحتوي هذا الوسم على بقية عناصر/وسوم الصفحة. <body> <div id="container"> <div id="header"> <p id="logo"> <a href="#" title="Return to the homepage"> <img src="images/pinewood-forest-logo.png" alt="Pinewood Forest logo" /> </a> </p> <ul> <li><a href="#">Visit</a></li> <li><a href="#">Discover</a></li> <li><a href="#">Trails</a></li> <li><a href="#">Maps</a></li> </ul> </div> </div> </body> </html> يبدأ التصميم بوسم div مع إعطائه id بقيمة "header" وسيحتوي هذا الوسم على الشّعار وعلى عناصر القائمة الرئيسية (navigation items)، وسيكون الشعار عبارة عن صورة داخل وسم <img> موضوعة في وسم <a>. تُستخدم title الموجودة في وسم <a> لتعريف المستخدم بالوجهة التي سيصل إليها حال نقره على الرابط، أمّا alt في وسم <img> فإنها تُستخدم لإعطاء المستخدم وصفًا عن الصورة في حالة عدم ظهور الصورة. يُعتبر وسم <ul> هو الوسم الشائع عند عمل القوائم الرئيسية لأنّه يُصوّر لنا وبدقة تلك القائمة على هيئة HTML حتى لو لم يكن هناك تنسيقات CSS. وبالرجوع إلى التصميم يمكنك ملاحظة أن الشعار موجود في الوسط بين قوائم العناصر الرئيسية، ولكننا سنبقي كلا العنصرين (الشعار والقائمة الرئيسية) مفصولين عن بعضهما حتى نحصل على هئية وملف HTML نظيف ومُرتّب، وسنلجأ لاحقًا إلى استخدام CSS لتحريك تلك العناصر حتى نحصل على نتيجة مرضية ومطابقة للتصميم. <div id="content"> <div id="feature"> <div id="feature-content"> <h1>Explore the forest</h1> <p>Find everything you need to explore and discover the mysteries of the forest, from maps and trail guides to must see attractions</p> <p class="btn"><a href="#">Begin your journey</a></p> </div> </div> </div> بعد الترويسة (header) تأتي منطقة المحتوى الرئيسي (main content)، ولجعل هيكل ملف HTML نظيفًا فسوف يتم وضع جميع العناصر في وسم <div> واحد، كما وستظهر منطقة الـfeature في بداية الصفحة وداخل وسم <div> ليتم تموضعها بشكل دقيق ومناسب. أمّا بالنسبة للعنوان الرئيسي في الصفحة (الذي يحتوي على النص "Explore the forest") فسوف يتم وضعه داخل وسم <h1>. لاحظ أيضًا أنه تم إضافة "class="btn إلى العنصر <p> ليمكننا تحويل هذا العنصر إلى زر باستخدام CSS. المستوى الثاني من العناوين سيكون موجودًا داخل وسم <h2>، وسيكون المحتوى الرئيسي منقسمًا إلى عمودين، بحيث يكون العمود الأكبر عبارة عن div مع id بقيمة "main" وبداخل هذا العمود توجد النصوص (عناصر <p>). لا تنسى تحويل الروابط إلى عناصر <a> وأي رموز خاصة (characters) إلى ما يقابلها من HTML entities (مثل رمز "&" يتم تحويله إلى "&"). وفي الأسفل من نفس العمود يوجد قسم "upcoming events"، ويمكننا استخدام عناصر <dl> ،<dt> و<dd> (اختصار للكلمات "Definition List"، "Definition Term" و"Definition Description" على التوالي) بحيث تحتوي عناصر dt على تاريخ الحدث وعناصر <dd> على وصف بسيط للحدث. لاحظ أننا استعملنا وسوم <span> داخل عناصر <dt> وذلك لإعطائها تنسيقات مميزة باستخدام CSS. <div id="side"> <div class="aside"> <a href="#"><img src="images/tracks-and-trails.jpg" alt="Tracks and Trails" /></a> <p>Pinewood Forest has a vast selection of walking and hiking trails to suit every visitor<a href="#">Find out more</a></p> </div> <div class="aside"> <a href="#"><img src="images/mountain-biking.jpg" alt="Mountain Biking" /></a> <p>Pinewood Forest is home to some of the most demanding XC and Freeride Mountain Biking routes<a href="#">Find out more</a></p> </div> <div class="aside"> <a href="#"><img src="images/christmas-events.jpg" alt="Christmas Events" /></a> <p>Pinewood Forest has a vast selection of walking and hiking trails to suit every visitor<a href="#">Find out more</a></p> </div> </div> </div> <div id="footer"> <p id="back-to-top"><a href="#">Back to top</a></p> </div> </div> بالنسبة للعمود الأصغر فسوف يكون موجودًا داخل عنصر div آخر مع id بقيمة "side". تتكون القائمة الجانبية (sidebar) من ثلاثة أقسام رئيسية وكل قسم يحتوي عنوان على شكل صورة وعلى وصف بسيط لكل قسم، ولأن كل صورة تحتوي على نص بداخلها فقد قمنا باستخدام alt لكل صورة حتى نحافظ على ما يسمى بالـaccessibility. وفي نهائية الصفحة قمنا بإغلاق وسم <div> الخاص بالمحتوى وتحتها يوجد div خاص بالـfooter وبادخله نص "Back to top" ليأخذنا إلى أعلى الصفحة عند الضغط عليه. انتهينا إلى الآن من هيكلة ملف HTML ويمكنك إلقاء نظرة إلى الصورة في الأعلى لترى كيف يجب أن يظهر بدون CSS. لاحظ أنه يمكن قراءة الملف حتى بدون تنسيق الملف باستخدام CSS. تنسيق الصفحة باستخدام CSS body, div, h1, h2, h3, h4, h5, h6, p, ul, ol, li, dl, dt, dd, img, form, fieldset, input, textarea, blockquote { margin: 0; padding: 0; border: 0; } body { font: 14px/26px Georgia, Serif; color: #444a54; background: #2d3237 url(images/bg-photo.jpg) center top no-repeat fixed; } #container { width: 960px; margin: 50px auto; } لنبدأ الآن بتنسيق الموقع باستخدام CSS. يُستخدم السطر الأول من أجل إزالة أي تنسيقات افتراضية للمتصفحات (يسمى هذا "CSS reset")، وبعد ذلك يوجد داخل المحدد body الخصائص العامة للخطوط في الموقع وصورة خلفية، ولأننا نريد هذه الصورة أن تكون ثابتة لا تتحرك مع باقي الصفحة عند التمرير(scrolling) فقد قمنا بإعطائها القيم "fixed" ،"top" و"center". وقد قمنا بإضافة لون أزرق (2d3237) حتى تظهر الخلفية بشكل أفضل لمن لا يمكنه رؤية الصورة لسبب أو لآخر وكذلك لمن يمتلك شاشات بدقة وأبعاد ضخمة. أمّا بالنسبة للحاوي الرئيسي (main container) فقد تم إعطاؤه عرض ثابت بقيمة 960px وتم توسيطه باستخدام الطريقة الشائعة margin: 0 auto. header { background: url(images/content-top.jpg) center bottom no-repeat; overflow: hidden; } header p#logo { position: relative; width: 295px; margin: 0 auto -74px auto; } header ul { width: 916px; margin: 0 auto 110px auto; overflow: hidden; list-style: none; } header li { float: left; } header li:nth-child(1) { margin: 0 70px 0 0; } header li:nth-child(2) { margin: 0 325px 0 0; } header li:nth-child(3), header li:nth-child(4) { margin: 0 0 0 70px; } header li a { font-size: 16px; letter-spacing: 9px; color: #4e5761; text-decoration: none; } header li a:hover { color: #7c8896; } يمكنك ملاحظة أنه تم إضافة صورة كخلفية للقسم العلوي من جزء المحتوى إلى الأسفل من الترويسة. ولموضعة الشعار وعناصر القائمة الرئيسية كما هو موجود في التصميم، فقد استخدمنا الخاصية margin بقيم سالبة. ولأن عناصر القائمة موجودة في كلا الجانبين من الشعار فقد تم استخدام nth-child لتحديد كل عنصر من العناصر الأربعة وإعطائه قيمة margin مناسبة، وعن طريق استخدام letter-spacing استطعنا تنفيذ التباعد بين الحروف(tracking) الموجود في التصميم. content { padding: 0 52px; overflow: hidden; background: url(images/content-repeat.png) center top repeat-y; } content #feature { width: 916px; height: 420px; position: relative; margin: 0 0 30px -30px; background: url(images/feature-bg.jpg); } content #feature #feature-content { position: relative; width: 384px; top: 92px; left: 460px; } content #feature #feature-content h1 { widht: 384px; height: 91px; margin: 0 0 5px 0; background: url(images/explore-the-forest.png); text-indent: -9999px; } content #feature #feature-content p { color: #fff; margin: 0 0 15px 8px; } content #feature #feature-content p.btn a { display: block; widows: 163px; height: 39px; background: url(images/begin-your-journey.png); text-indent: -9999px; } content #feature #feature-content p.btn a:hover { margin: -1px 0 0 0; } بما أنّ ارتفاع div الخاص بالمحتوى سيختلف من صفحة لأخرى، فقد قمنا باستخدام صورة ليتم تكريرها حتى نسمح لجزء المحتوى أن يتمدد بدون قيود، واستخدمنا padding على اليمين واليسار حتى نُبعد محتوى الصفحة عن الحواف. ولأنّ منطقة المحتوى ستحتوي على عمودين وكل منهما يحتوي على الخاصية float، فسوف نحتاج إلى استخدام overflow: hidden حتى يظهر كل شيء بشكل جيد. إعطاء قسم الـfeature الخاصية position: relative سيسمح للمحتوى بالتحرك في مكانه، كما أنّ القيمة السالبة للخاصية margin ستعوّض عن قيمة padding التي تم إعطاؤها لـdiv المحتوى وذلك لنسمح لذلك القسم بالتمدد إلى أقصى أطراف الصفحة. كما أنه تمّ استخدام صورة في وسم h1، ولكن تم تنسيق الفقرة باستخدام خصائص font في CSS. وبالنسبة للزر، فقد تم استخدام صورة وإعطائه بعض التنسيقات حتى يظهر بشكل جيد. content #main { width: 536px; float: left; margin: 0 20px 0 0; } content h2 { font-size: 20px; font-weight: normal; margin: 0 0 20px 0; } content p { margin: 0 0 20px 0; } content a { color: #3f6489; } content a:hover { color: #0d3965; } content dl { } content dt { float: left; width: 40px; height: 50px; margin: 0 15px 0 0; background: #a1a3a5 url(images/date-bg.png); font-size: 30px; color: #fff; text-align: center; } content dt span { display: block; font-size: 12px; font-weight: bold; text-transform: uppercase; } content dd { float: left; width: 480px; } content dd h3 { float: left; font-size: 20px; font-weight: normal; } content dd span { float: left; margin: 4px 0 0 10px; visibility: hidden; } content dd p { clear: left; } content dd:hover span { visibility: visible; } سيكون الـdiv الرئيسي هو الأعرض بين العمودين؛ بعرض 536px. وسيكون العرض لكل من main وside بالإضافة إلى الـmargin بينهما هو العرض الخاص بـdiv الأب منقوصًا منه قيمة padding اليسار واليمين. تم تحويل عناصر dt إلى أيقونة التاريخ عن طريق إعطائها عرض وطول ولون خلفية رمادي. وباستخدام تنسيقات font مناسبة أمكننا جعل نص التاريخ كبيرًا وبلون أبيض، كما أنّه تم جعل الخط الخاص بالعنصر span أصغر بقليل حتى يظهر الشهر أسفل رقم اليوم بشكل جميل. وحتى تظهر عناصر dt وdd بجانب بعضها فقد تم إعطاؤها الخاصية float: left. لاحظ أننا استخدمنا visibility: hidden على العنصر span وذلك حتى نخفيه عن أنظار الزائر إلى أن يضع مؤشر الفأرة فوق عنصر dd لنقوم عندها بإظهار رابط "View more info". content #side { width: 300px; float: left; } content .aside { padding: 17px 0 0 17px; margin: 0 0 30px 0; background: url(images/aside-bg.png) center top no-repeat; } content .aside img { margin: 0 0 15px 0; } footer { padding: 70px 22px; background: url(images/content-bottom.png) center top no-repeat; } footer p#back-to-top { float: right; font-size: 11px; } footer p#back-to-top a { color: #fff; text-decoration: none; } footer p#back-to-top a:hover { color: #d7d9d8; } كل عنصر aside. تم إعطاؤه خلفية مزخرفة، وبالنسبة للخطوط فإنها ستأخد التنسيقات الخاصة بـ div المحتوى بسبب ما يسمى بالتوريث (inheritance). أمّا بالنسبة لرابط "back to top" فسوف نضطر إلى إعطائه تنسيقات جديدة لأنه موجود خارج div المحتوى، ولأنّ هذا الرابط موجود ضمن خلفية داكنة وخارج المحتوى الرئيسي فإننا سنحتاج لتعديل الألوان وجعلها مختلفة عن البقية الموجودة في باقي الصفحة. بقي شيء واحد قبل أن ننتهي من هذا الدرس وهو أنّه يجب عليك أن تعرف أن خاصية nth-child غير مدعومة في بعض إصدارات متصفح Internet Explorer، لذلك إذا أردت أن تدعم تلك المتصفحات فيجب عليك استخدام jQuery: $(document).ready(fucntion() { $("#header ul li:nth-child(1)").css("margin-right", "70px"); $("#header ul li:nth-child(2)").css("margin-right", "325px"); $("#header ul li:nth-child(3)").css("margin-left", "70px"); $("#header ul li:nth-child(4)").css("margin-left", "70px"); }); إلى هنا نكون قد أنهينا درسنا وحصلنا على صفحة كاملة وجاهزة. يمكنك أيضًا تصفح الموقع بشكله النهائي إذا أحببت ذلك. أو تصفح الملفات المصدرية. ترجمة -وبتصرف- للمقال: Design a Textured Outdoors Website in Photoshop لصاحبه: Iggy.
  4. في عالم اليوم، لم يعد بالإمكان قصر اهتمامنا على الهواتف المحمولة والحواسيب، فلدينا أجهزة لوحية وأخرى "تُرتدى" كالسّاعات والنّظارات الذكيّة. سيكون موضوعنا اليوم عن التصميم لمختلف أنواع الأجهزة. فهرس سلسلة مدخل إلى تجربة المستخدم: مدخل إلى تجربة المستخدم User Experience فهم ودراسة المستخدمين في مجال تجربة المستخدم دراسة الشريحة المستهدفة في مجال تجربة المستخدم كيفية التصميم للأجهزة المختلفة (هذا الدرس) هندسة المعلومات في تجربة المستخدم تعرف على أنماط التصميم في مجال تجربة المستخدم أشياء لا يمكن اعتبارها رسوما تخطيطية (Wireframes) في مجال تجربة المستخدم تعرف على الرسوم التخطيطية (Wireframes) في مجال تجربة المستخدم مفهوم الثقل المرئي (Visual Weight) والألوان في مجال تجربة المستخدم التكرار ومخالفة الأنماط في مجال تجربة المستخدم المحاذاة والقرب في مجال تجربة المستخدم تعرف على أساليب مسح الواجهة والتراتب المرئي في مجال تجربة المستخدم أساليب الإطلاع في مجال تجربة المستخدم: التصفح، البحث والاكتشاف تصميم هيكل صفحة الويب والعناصر الأساسية في مجال تجربة المستخدم الأزرار، النماذج والدعوات إلى الإجراء في مجال تجربة المستخدم استخدام علم النفس في مجال تجربة المستخدم لتكييف المستخدم وإقناعه كيف تغير الخبرة من تجربة المستخدم؟ تصميم تجربة المستخدم من خلال بيانات وإحصائيات المستخدمين تعرف على أنواع المخططات الإحصائية في مجال تجربة المستخدم اختبارات أ/ب (A/B Test) في مجال تجربة المستخدم الخطوة الأولى: كيف سيكون التعامل مع الواجهة؟ باللمس بالإصبع أم بمؤشّر الفأرة؟ الخطوة الثانية: ابدأ بالأجهزة الصغيرة يعتقد البعض أن عبارة "mobile first" الشّائعة تأتي من صعود شعبيّة الهواتف الذّكية، وهذا جزء من الحقيقة، أمّا الجزء الآخر فهو قائم على أن التّصميم للأجهزة الصّغيرة محدودة القدرات يُجبر المصمّم على التّركيز على المحتوى والوظيفة الأساسيّة للمشروع، مؤدّيًا بدوره إلى تطبيقات بسيطة وجميلة؛ أمّا العكس (أي البدء بالأجهزة القويّة) فهو أشبه بإقحام قطّ في قفص عصفور، أمر ليس بسيطًا ولا جميلًا! الخطوة الثالثة: ما الإمكانيات المميزة لهذا الجهاز؟ تتنقّل الهواتف الذّكية معنا طيلة اليوم، وهذا يعني أنّنا نقضي وقتًا طويلًا في استخدامها، وأن باستطاعتنا استخدام الموقع في تطبيقاتنا، كما أنّها أجهزة صغيرة الحجم ويسهل نقلها، أمّا الحواسيب المحمولة فهي أقل سهولةً في النّقل ولكنّها أكثر قدرةً، وشاشاتها أكبر حجمًا، وفيها لوحة مفاتيح مُريحة، ومؤشّر يسمح بتحديد أكثر دقّة ووظائف أكثر. لا تُصرَّ كثيرًا على فكرة "وحدة الواجهة" بين الأجهزة المختلفة، بل فكّر بأسلوب مختلف لكلّ جهاز. الخطوة الرابعة: لا تنس البيئة التي يعمل فيها التطبيق هناك اختلاف في الخطوط العامّة لتجربة المستخدم بين Mac OS X وWindows، وكذلك يختلف Windows Vista عن Windows 8، وiOS 7 عن iOS 6، وقد تُضطّر لاختيار إصدارات محدودة لاستهدافها، وأخرى تتجاهلها، ففي كلّ مرّة توفّر تطبيقك لإصدار جديد، يتضاعف جهد التصّميم والتّطوير والصّيانة في المستقبل. كن بعيد النّظر! الخطوة الخامسة: كن مستجيبا هل ستوفّر تطبيقك على الويب؟ هل يدعم بضعة أنواع من الهواتف فقط؟ كيف سيعمل على الأجهزة القادمة؟ كل الأجهزة تستطيع التّواصل مع الإنترنت اليوم، لذا احرص على أن باستطاعة تطبيقك التلاؤم مع مختلف الأجهزة التي قد يرغب مُستخدمو تطبيقك باستعمالها. الخطوة السادسة: فكر بأكثر من شاشة واحدة في الوقت نفسه قد يكون هذا الموضوع متقدّمًا، ولكنّ بإمكانك بشيء من الجهد تحقيقه. هل يمكن استخدام هاتفك وحاسوبك سويّة كما يمكن التّحكم بالتّلفاز عن بُعد؟ هل يمكن لمجموعة من الهواتف أن تتحكّم بلعبة على حاسوب لوحيّ في غرفة واحدة؟ وإذا كنت تستخدم جهازين في وقت واحد، فهل يمكن نقل البيانات بينهما؟ ماذا عن مزامنة البيانات؟ هل ستؤدّي إلى مشاكل في الاستعمال؟ فكّر في الأمر! سنتعرّف في الدّرس القادم على أنماط التّصميم، وهي مجموعة من الأساليب الشّائعة لحلّ المشكلات المُتكّررة في تصميم تجربة المُستخدم. ترجمة بتصرّف للدرس Designing For Devices من سلسلة Daily UX Crash Course لصاحبها Joel Marsh.
  5. ووردبريس هو منصة رائعة لإدارة المحتوى. إذا كنت تملك أيّ محتوى يأتي في شكل وحدات شبيهة بالمقالات (أو ما شابهها مثل منتجات) فلا أجد سببا يدفعك لعدم استخدام ووردبريس. قد يكون التعاون باستخدام سكربت ميديا ويكي سهل أيضا، واستخدام دروبال مع أنظمة الشركات يعد أمرا سهلا وشائعا، لكن ووردبريس له مكانته أيضا في هذا المجال، وهو في رأيي، يوفر تجربة تحرير أفضل. أحد الطرق لجعل المحتوى في ووردبريس يعمل بشكل أفضل هو إضافة معلومات إضافية له (metadata). قد يكون الأمر على شكل تصنيفات خاصة (taxonomies) أو على شكل بيانات تستخدم لهدف واحد (custom fields). ماهو الحقل المخصص في ووردبريس؟إذا أردت أن تستخدم معلومات محددة متغيرة لكل مقال ما (أو شيء شبيه بمقال كمنتج)، هنا تستطيع استخدام الحقول المخصصة في ووردبريس. "الحقول المخصصة" لها تسميتان مختلفتان في ووردبريس، غالبا ما يطلق عليها خصائص المنشور أو المعلومات الجانبية (post metadata) أو post_meta وعادة ما يطلق عليها باسم الحقول المخصصة، وهذه الترجمة الرسمية التي يستخدمها فريق ترجمة ووردبريس العربي. نحن نضيف الحقول المخصصة عندما نريد أن نخزن خصائص إضافية لمنشور ما. منشورات ووردبريس تأتي بالعديد من الخصائص الإضافية بشكل مسبق: تاريخ النشر، كاتب الموضوع، آخر وقت تّم التعديل عليهم. لكنك قد تريد المزيد، مثلا تريد أن تضيف عنوانا ثانويا للمنشور، أو تريد أن تضيف ملخص المنشور تصميم منفرد. ووردبريس يقوم بتخزين هذه المعلومات في قاعدة البيانات، وباستخدام دوال معينة نقوم بتحديدها وتخزينها واسترجاعها. الحقول المخصصة تنفرد عن خيارات الموقع site_settings حيث أنّ لهم علاقة بالمنشور وليس بالموقع ولكن كلاهما يعملان بنظام عنوان وقيمة key/value pair يتم استخارجهم من قاعدة البيانات عبر دوال محددة، لذا إن كانت لك تجربة بنظام خيارات الموقع Settings API فلن تواجه مشكلة في فهم الحقول المخصصة. كيف أضيف الحقول المخصصة لمنشور؟هناك العديد من الطرق التي تستطيع استخدامها لإضافة الحقول المخصصة، الواجهة الافتراضية للتعامل مع الحقول الخاصة في ووردبريس قديمة ولم يتم تحديثها منذ مدة، ورغم أنها تخدم الهدف إلا أنها بعيدة عن المثالية. الجزء المضاف في الأسفل "ما بعد الأساسيات" سيدخل في التفاصيل حول خيارات أخرى تستطيع اللجوء لها من أجل التحكم في الحقول الخاصة، لكن سنقوم الآن بفهم الواجهة الأصلية فحسب، لأنها ستكون موجودة دوما في كل المواقع. في شاشة التعديل على منشور ستجد صندوق "خصائص إضافية"، وستقوم أنت بتعديل الحقول المخصصة فيه. لا داعي لنمر على كامل معلومات تكوين الصندوق، ستقوم ببساطة باختيار الاسم (أو تضيف واحدا جديدا في حال لم تقم بالأمر من قبل). من ثم تقوم بإضافة القيمة، إضغط على الزر ولقد قمت بإضافة الحقل إلى منشورك، محفوظا مع بقية عناصرك. إظهار الحقول المخصصة في منشوراتكلتستخدم الحقول الخاصة في منشوراتك أمامك عدة دوال، وتسمياتهم تختلف حسب طريقة تكلم الناس عنهم، الدوال الأساسية هي كالتالي: ()the_meta: مثل كل دوال ووردبريس التي تبدأ بـ _the فدالة ()the_meta الهدف منها طبع المعلومات (echo) حتى لا تقوم بالأمر يدويا. تستطيع استخدامها عندما لا تريد أن تغير أيّ شيء بالمعلومات التي تريد طباعتها. لكنها تبدو لي غبر مفيدة لأنها لا تتيح لك أيّ تحكم بهيكلة المعلومات التي تحصل عليها، كما أنها تقوم بطبع كل المعلومات للصفحة.()get_post_meta: هي الدالة التي أستخدمها أنا طوال الوقت، المتغير الأول (parameter) الذي تحتاجه هو معرف (ID) المنشور، المتغير الثاني هو اسم الحقل الذي تريد جلبه، والثالث هو Boolean في حال كنت تريد القيمة على شكل string أو array مصفوفة (true من أجل string وfalse ل array).()get_post_custom: عمل بشكل شبيه جدا لـ ()get_post_meta لكنها تختلف في التسمية، الفرق أنك تقوم بتمرير ID المنشور له فحسب (بشكل اختياري أيضا) وسيقوم بإرجال كل القيم المخصصة للمنشور على شكل array.ما بعد الأساسيات: كيفية تحسين واجهة الحقول المخصصةأحد نقاط ضعف ووردبريس من ناحية الحقول المخصصة هو الصندوق الذي تستخدمه للتعديل عليها، فكما أسلفنا الذكر، الصندوق ليس مفيدا لتلك الدرجة، لذا أنت تملك الفرصة لتحسين التجربة لمستخدميك وزبائنك. الدوال التي تحتاجها للتعامل مع الحقول الخاصةحتى الآن، فقد تعلمنا كيف نسترجع الحقول الخاصة فحسب، مهمة أخرى ستقوم بها عند التطوير هي تعديل أو حذف المعلومات. من أجل هذه المهمة يقدم ووردبريس 3 دوال بسيطة للقيام بالأمر وهي: ()add_post_meta : هي الطريقة التي تستخدمها لإنشاء الحقل لأول مرة، تقوم بتمرير ID المنشور لها واسم الحقل المخصص (meta_key) والقيمة التي تريدها، وبشكل اختياري تستطيع تحديد أن يجعل ووردبريس تلك القيمة فريدة من نوعها. addpostmeta($postid, $metakey, $meta_value, $unique = false) ()update_post_meta : يمكن أيضا استخدام هذه الدالة لإنشاء حقل مخصص جديد، لذا هي تملك القدرة لتحل مكان ()add_post_meta في حال لم تكن واثقا أن الحقل جديد أو لا فتستطيع استعمالها، أول ثلاث خيارات هم نفس خيارات ()add_post_meta والخيار الأخير هو القيمة السابقة، وهو أمر لم استخدمه من قبل حقا ولكن قد يكون مفيدا في حال كنت تملك الكثير من القيم لاسم واحد (key). updatepostmeta($postid, $metakey, $metavalue, $prevvalue='') ()delete_post_meta : هي كما تتوقع تماما، وخياراتها مثل البقية تماما، عدى أن الخيار الأخير (قيمة الحقل) هي قيمة اختيارية تستطيع أن لا تحددها. deletepostmeta( $postid, $metakey, $meta_value = '' ) شرح كيفية استخدام هذه الدوال داخل لوحة التحكم هو خارج نطاق المقال، لكنك تستطيع استعمالها عبر إنشاء صندوق جديد، واستخدام الدوال اللازمة وحفظ المعلومات أثناء حفظ المنشور. استخدام إضافات مصممة لتحسين تجربة الحقول الخاصةهناك العديد من الإضافات الرائعة التي تقوم بتحسين واجهة الحقول الخاصة، أشهرها في نظري هي Pods و Advanced Custom Fields. تقوم هذه الإضافات باستخدام custom post type لإنشاء حقول جديد تعمل بمثابة حقل مخصص. أداة أبسط وأقوىالطريقة التي استخدمها عادة والتي تختلف عن البقية هي إضافة CMB2 فهي تتيح لك تحكم عبر الشفرة البرمجية (عكس الإضافات الأخرى التي تتطلب منك إنشاء الحقول عبر واجهة). استخدام هذه الطريقة للبناء بدل الطريقة التقليدية الذي يوفرها ووردبريس هو أمر مختلف تماما وتجربة رائعة. لن تحتاج لكتابة دوال كبيرة لبناء صناديق لحقول مخصصة ثم محاولة حفظها فهي تقوم بكل شيء بشكل أوتوماتيكي. كل ما عليك القيام به هو وضع الملفات في قالبك أو إضافتك أو تنصيب الإضافة والعمل مع دوالها من قالبك، لشرح أكبر لها اقرأ التوثيق المرفق لها. يجدر الذكر أنّ الإضافة مترجمة للعربية بنسبة 93% (بتاريخ هذا اليوم) ويعتبر هذا دعما ممتازا للعربية لذا الشكر لكل من ساهم في ترجمتها (تستطيع الانضمام لهم عبر موقع Transifex). قوة الحقول المخصصة في ووردبريسكما أسلفنا الذكر، الحقول المخصصة تعتبر جزءا مهما في تطوير استخدامك لووردبريس. استخدام الأمور المبنية في ووردبريس لنشر المحتوى أمر جيد، ولكن الحقول المخصصة هي ما تسمح لإضافات مثل WooCommerce و Easy Digital Downloads بإضافات مميزات قوية لووردبريس. ترجمة -وبتصرف- للمقال: Everything You Should Know about WordPress Custom Fields لصاحبه: DAVID HAYES.
  6. يهدف هذا الدرس إلى بناء تطبيق CRUD (إدراج بيانات في قاعدة بيانات، القراءة منها، تحديثها وحذفها؛ اختصار لـUpdate، Read، Create وDelete). التطبيق عبارة عن واجهة لإدارة لائحة من الموظفين: إضافة موظّف، تحرير بياناته أو حذفها. سنستخدم Laravel 5 للنهاية الخلفية Backend و AngularJS للنهاية الأمامية Frontend. سنستخدم أيضا Bootstrap لإضافة لمسة جمالية إلى التطبيق. هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي: مدخل إلى Laravel 5.تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب.تهجير قواعد البيانات في Laravel.استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها.إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel. (هذا الدرس)الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار. AngularJS هو إطار عمل جافاسكريبت قويّ وفعّال، يتبنى مبدأ النموذج-العرض-المتحكم MVC ويعمل لدى العميل (المتصفّح). للاطلاع على المزيد عن AngularJS تابع سلسلة دروس مدخل إلى تعلم AngularJS . يفترض هذا الدرس معرفة أساسيات Laravel 5، تثبيت كلّ من PHP، MySQL، ِApache وComposer. يغطي الدرس المواضيع التالية: إنشاء نهاية خلفية في Laravel 5، ستكون عبارة عن واجهة برمجية API.بنية تطبيق AngularJS.واجهة برمجية باستخدام Laravel 5ننشئ في هذه الفقرة النهاية الخلفية للتطبيق الذي نعمل عليه. سيتولى Laravel هذه المهمة. نبدأ بإنشاء تطبيق Laravel ثم نعدّه لتوفير الواجهة البرمجية. الخطوة الأولى: إنشاء تطبيق Laravelننفذ الأمر التالي في أصل المستند Document root لإنشاء مشروع Laravel باسم angulara: composer create-project laravel/laravel angularaراجع درس تثبيت Laravel 5 وإعداده على Windows وUbuntu للمزيد حول تثبيت Laravel وإعداده. سنفترض في بقية هذا الدرس تثبيت Laravel على المنصة المفضلة لديك وإنشاء مضيف افتراضي باسم angulara.dev. الخطوة التالية هي إعداد تهجير قاعدة البيانات. الخطوة الثانية: إعداد قاعدة البياناتستحتاج لقاعدة بيانات للعمل مع التطبيق. استخدم برنامج إدارة قاعدة البيانات المفضل لديك أو نفذ الأمر التالي في سطر أوامر MySQL لإنشاء قاعدة بيانات للمشروع: CREATE DATABASE `angulara`;ننتقل الآن لإعداد Laravel لكي يعمل مع قاعدة البيانات. افتح ملف env. في مجلد تطبيق Laravel وعدل القيم التالية بما يناسب: DB_HOST=localhost // اسم قاعدة البيانات DB_DATABASE=angulara // اسم مستخدم في MySQL لديه صلاحيات الكتابة والقراءة في القاعدة أعلاه DB_USERNAME=root // كلمة سر المستخدم DB_PASSWORD=melodyاحفظ التعديلات. نستغل أداة Artisan لإنشاء ملف تهجير خاص بجدول يحوي بيانات الموظفين employees. نفذ الأمر التالي لإنشاء ملف التهجير: php artisan make:migration create_employees_tableستحصُل على الرسالة التالية التي تعرض اسم الملف المنشأ: Created Migration: 2016_01_05_203637_create_employees_tableينشئ الأمر ملفا في المجلد database/migrations، نفتحه للتعديل عليه. عدّل المحتوى كالتالي: <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateEmployeesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employees', function (Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); $table->string('email')->unique(); $table->string('contact_number'); $table->string('position'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('employees'); } }احفظ التعديلات ثم نفذ أمر ِArtisan التالي: php artisan migrateينفذ الأمر التهجيرات وينشئ جدول بيانات الموظفين. تظهر الرسائل التالية بعد تنفيذ الأمر: Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2016_01_05_203637_create_employees_tableتحقق من قاعدة بيانات MySQL، ستجد أن جدولا جديدا أُدرِج في القاعدة. الخطوة الثالثة: إنشاء واجهة برمجيةننشئ متحكما Controller للتطبيق، سنسميه Employees: php artisan make:controller Employeesثم يأتي دور النموذج Model: php artisan make:model Employeeسنضيف مصفوفة في النموذج لتفعيل الإسناد الشامل؛ افتح ملف النموذج وعدّله على النحو التالي: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { protected $fillable = array('id', 'name', 'email','contact_number','position'); }احفظ التعديلات. ننتقل للتعديل على المتحكم. افتح ملف المتحكم Employees وعدله ليصبح كالتالي <?php namespace App\Http\Controllers; use App\Employee; use Illuminate\Http\Request; use App\Http\Requests; use App\Http\Controllers\Controller; class Employees extends Controller { /** * Display a listing of the resource. * * @return Response */ public function index($id = null) { if ($id == null) { return Employee::orderBy('id', 'asc')->get(); } else { return $this->show($id); } } /** * Store a newly created resource in storage. * * @param Request $request * @return Response */ public function store(Request $request) { $employee = new Employee; $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return 'Employee record successfully created with id ' . $employee->id; } /** * Display the specified resource. * * @param int $id * @return Response */ public function show($id) { return Employee::find($id); } /** * Update the specified resource in storage. * * @param Request $request * @param int $id * @return Response */ public function update(Request $request, $id) { $employee = Employee::find($id); $employee->name = $request->input('name'); $employee->email = $request->input('email'); $employee->contact_number = $request->input('contact_number'); $employee->position = $request->input('position'); $employee->save(); return "Sucess updating user #" . $employee->id; } /** * Remove the specified resource from storage. * * @param int $id * @return Response */ public function destroy($id = null) { if ($id == null) { } else { $employee = Employee::find($id); $employee->delete(); return "Employee record successfully deleted #" . $id; } } }يعرِّف المتحكم الدوالّ index لسرد قائمة بالموظفين، store لإضافة موظف جديد، show لعرض موظف بناء على معرّفه، update لتحديث بيانات موظّف وdestroy لحذف موظّف. تبقى لنا إعداد المسارات Routes في Laravel. افتح ملف المسارات routes.php وعدله كالتالي: <?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the controller to call when that URI is requested. | */ Route::get('/', function () { return view('index'); }); Route::get('/api/v1/employees/{id?}', 'Employees@index'); Route::post('/api/v1/employees', 'Employees@store'); Route::post('/api/v1/employees/{id}', 'Employees@update'); Route::delete('/api/v1/employees/{id}', 'Employees@destroy');لاحظ استخدام إجراءات HTTP وفقا للمبدأ المشروح في درس إنشاء واجهة برمجية API في Laravel 5. يختلف التعامل مع المسار api/v1/employees حسب إجراء HTTP المستخدم: get يُستخدم للحصول على معلومات موظف أو قائمة بالموظفين، post لإضافة موظف جديد، put لتحديث بيانات موظّف وdelete لحذف موظّف. أكملنا الآن جانب النهاية الخلفية بإنشاء واجهة برمجية. ننتقل للواجهة الأمامية التي ستستخدم الواجهة البرمجية للحصول على بيانات الموظفين وتنسيقها قبل عرضها في المتصفح. بنية تطبيق AngularJSسيأخذ مجلد public (الواجهة الأمامية لتطبيق Laravel) الشكل التالي: يحوي المجلّد الفرعي app ملفات جافاسكريبت التابعة لـAngularJS.توجد متحكمات AngularJS في المجلّد app/controllers.توجد ملفات نواة AngularJS في المجلّد app/lib. توجد أيضا إمكانية استخدام شبكة توصيل محتوى Content delivery network, CDN.توجد ملفات CSS في المجلد css.ملفات جافاسكريبت غير التابعة لـAngularJS توجد في المجلد js.توجد ملفات الواجهة الأمامية في الملف المرفق، سنشرح ما يحتاج لشرح منها. الملف app.jsسنستخدم الملف public/app/app.js لتعريف التطبيق الخاص بنا: var app = angular.module('employeeRecords', []) .constant('API_URL', 'http://angulara.dev/api/v1/');ننشئ وحدة Module في AngularJS ونسند الكائن إلى المتغير app. سيُستخدم هذا المتغير في جميع ملفات AngularJS؛ ثم نعرّف ثابتا Constant لرابط الواجهة البرمجية API_URL. ملحوظة: إن كنت اخترت اسما مختلفا للمضيف فضعه مكان angulara.dev. المتحكم Employees.jsسيكون هذا الملف مسؤولا عن التفاعل مع عروض تطبيق AngularJS: app.controller('employeesController', function($scope, $http, API_URL) { // الحصول على لائحة الموظفين $http.get(API_URL + "employees") .success(function(response) { $scope.employees = response; }); // عرض نافذة منبثقة $scope.toggle = function(modalstate, id) { $scope.modalstate = modalstate; switch (modalstate) { case 'add': $scope.form_title = "Add New Employee"; break; case 'edit': $scope.form_title = "Employee Detail"; $scope.id = id; $http.get(API_URL + 'employees/' + id) .success(function(response) { console.log(response); $scope.employee = response; }); break; default: break; } console.log(id); $('#myModal').modal('show'); } //save new record / update existing record $scope.save = function(modalstate, id) { var url = API_URL + "employees"; var request_method = 'POST'; //append employee id to the URL if the form is in edit mode if (modalstate === 'edit'){ url += "/" + id; request_method = 'PUT'; } $http({ method: request_method, url: url, data: $.param($scope.employee), headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).success(function(response) { console.log(response); location.reload(); }).error(function(response) { console.log(response); alert('This is embarassing. An error has occured. Please check the log for details'); }); } //delete record $scope.confirmDelete = function(id) { var isConfirmDelete = confirm('Are you sure you want this record?'); if (isConfirmDelete) { $http({ method: 'DELETE', url: API_URL + 'employees/' + id }). success(function(data) { console.log(data); location.reload(); }). error(function(data) { console.log(data); alert('Unable to delete'); }); } else { return false; } } });نعرِّف متحكما باسم employeesController في المتغيّر app الذي أنشأناه في الملف app.js. حدّدنا الاعتماديات بـ $http، scope$ وAPI_URL. نستدعي خدمة http$ في AngularJS لإرسال طلب إلى الواجهة البرمجية، مع تمرير المعطى API_URL + "employees": $http.get(API_URL + "employees").success(function(response) {$scope.employees = response;});عند نجاح الطلب نُسنِد الإجابة إلى المتغير scope.employees$ الذي سيصبح متاحا في العرض View لإظهار محتواه. تعرض الدالة: $scope.toggle = function(modalstate, id) {…}نافذة منبثقة تحوي استمارة لإضافة موظّف جديد أو تعديل بيانات موظّف موجود حسب الحالة. نستخدم الدالة: $scope.save = function(modalstate, id){…}في حالتيْ الإضافة والتعديل. بالنسبة لإضافة موظّف نستخدم إجراء POST؛ وفي حالة التعديل نستخدم الإجراء PUT. تحذف الدالة: $scope.confirmDelete = function(id){…}بيانات موظّف من جدول الموظفين. عرض البيانات المتحصل عليها من الواجهة البرمجية بـAngularJSسننشئ عرضا لإظهار البيانات التي نتحصل عليها من الواجهة البرمجية؛ يستخدم كل من angularJS وBlade الحاضنات المزدوجة {{}} لعرض البيانات، لذا لن نحفظ عرض AngularJS بلاحقة blade.php حتى لا يعدّ نظام Blade العرض موجها له. محتوى العرض هو التالي، نحفظ الملف index.php في ملف العروض resources/views حتى يُحمّل عند طلبه من المسار / (الصفحة الرئيسية للموقع): <!DOCTYPE html> <html lang="en-US" ng-app="employeeRecords"> <head> <title>Laravel 5 AngularJS CRUD Example</title> <!-- Load Bootstrap CSS --> <link href="<?= asset('css/bootstrap.min.css') ?>" rel="stylesheet"> </head> <body> <h2>Employees Database</h2> <div ng-controller="employeesController"> <!-- Table-to-load-the-data Part --> <table class="table"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>Contact No</th> <th>Position</th> <th><button id="btn-add" class="btn btn-primary btn-xs" ng-click="toggle('add', 0)">Add New Employee</button></th> </tr> </thead> <tbody> <tr ng-repeat="employee in employees"> <td>{{ employee.id }}</td> <td>{{ employee.name }}</td> <td>{{ employee.email }}</td> <td>{{ employee.contact_number }}</td> <td>{{ employee.position }}</td> <td> <button class="btn btn-default btn-xs btn-detail" ng-click="toggle('edit', employee.id)">Edit</button> <button class="btn btn-danger btn-xs btn-delete" ng-click="confirmDelete(employee.id)">Delete</button> </td> </tr> </tbody> </table> <!-- End of Table-to-load-the-data Part --> <!-- Modal (Pop up when detail button clicked) --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">{{form_title}}</h4> </div> <div class="modal-body"> <form name="frmEmployees" class="form-horizontal" novalidate=""> <div class="form-group error"> <label for="inputEmail3" class="col-sm-3 control-label">Name</label> <div class="col-sm-9"> <input type="text" class="form-control has-error" id="name" name="name" placeholder="Fullname" value="{{name}}" ng-model="employee.name" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">Name field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Email</label> <div class="col-sm-9"> <input type="email" class="form-control" id="email" name="email" placeholder="Email Address" value="{{email}}" ng-model="employee.email" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.email.$invalid && frmEmployees.email.$touched">Valid Email field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Contact Number</label> <div class="col-sm-9"> <input type="text" class="form-control" id="contact_number" name="contact_number" placeholder="Contact Number" value="{{contact_number}}" ng-model="employee.contact_number" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.contact_number.$invalid && frmEmployees.contact_number.$touched">Contact number field is required</span> </div> </div> <div class="form-group"> <label for="inputEmail3" class="col-sm-3 control-label">Position</label> <div class="col-sm-9"> <input type="text" class="form-control" id="position" name="position" placeholder="Position" value="{{position}}" ng-model="employee.position" ng-required="true"> <span class="help-inline" ng-show="frmEmployees.position.$invalid && frmEmployees.position.$touched">Position field is required</span> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id="btn-save" ng-click="save(modalstate, id)" ng-disabled="frmEmployees.$invalid">Save changes</button> </div> </div> </div> </div> </div> <!-- Load Javascript Libraries (AngularJS, JQuery, Bootstrap) --> <script src="<?= asset('app/lib/angular/angular.min.js') ?>"></script> <script src="<?= asset('js/jquery.min.js') ?>"></script> <script src="<?= asset('js/bootstrap.min.js') ?>"></script> <!-- AngularJS Application Scripts --> <script src="<?= asset('app/app.js') ?>"></script> <script src="<?= asset('app/controllers/employees.js') ?>"></script> </body> </html>نربط تطبيق AngularJS بوسم html حتى يكون له كامل التحكّم في العناصر الموجودة في الصفحة: <html lang="en-US" ng-app="employeeRecords"> نفس الشيء بالنسبة للمتحكم employeesController الذي نربطه بعنصر div حتى نجعل جميع دوال المتحكم متاحة في هذا العنصر: <div ng-controller="employeesController">نستخدم تعليمة ng-repeat للمرو على جميع عناصر المجموعة employees: <tr ng-repeat="employee in employees">تعمل ng-repeat بطريقة مشابهة لعمل الحلقة التكرارية foreach. التحقق من بيانات استمارات AngularJSاستخدمنا في استمارات الموظفين طرقا للتحقق من المُدخلات. اعثر على الشفرات التالية في ملف العرض index.php ولاحظ استخدامها: <form name="frmEmployees" class="form-horizontal" novalidate="">تعرّف هذه الشفرة استمارة باسم frmEmployees وتضيف إليها خاصيّة novalidate للطلب من HTML 5 الامتناع عن تدقيق الاستمارة، سنتولى الأمر. <input type… ng-model="employee.name" ng-required="true">تستخدم تعليمة ng-model لربط حقول الاستمارة ببيانات النموذج Employee. ربطنا الحقل أعلاه بخاصية name في النموذج. بهذه الطريقة يكون محتوى الحقل متاحا للنموذج، والعكس أيضا. تدل التعليمة ng-required أن الحقل مطلوب. إن لم تذكر قيمة لهذا الحقل فلن يمكن إرسال الاستمارة. <span class="help-inline" ng-show="frmEmployees.name.$invalid && frmEmployees.name.$touched">لا يظهر هذا العنصُر إلا إذا أخفق التحقق من حقل name قبله. تظهر رسالة تفيد أن قيمة الحقل مطلوبة. ng-disabled="frmEmployees.$invalid" تعطّل هذه التعليمة إمكانية إرسال الاستمارة عند إخفاق التحقق من أحد الحقول المطلوبة. حان الآن وقت تجربة ما عملناه في الخطوات السابقة، افتح الموقع (بالنسبة لي اخترتُ إنشاء مضيف افتراضي angulara.dev): http://angulara.dev/ستحصُل، إن اتبعت الخطوات السابقة، على الواجهة التالية: اضغط على زر Add New Employee لإضافة موظّف. ستظهر نافذة منبثقة لإضافة بيانات الموظّف. تصبح الواجهة بعد إضافة موظفين على النحو التالي: تمكّن الأزرار edit و delete الموجودة في كل سطر تحديثَ أو حذف بيانات موظّف. الملف المرفق: مجلد public. ترجمة -وبتصرّف- لمقال Laravel 5 AngularJS Tutorial لصاحبه Rodrick Kazembe.
  7. تعرّفنا في الجزء السّابق على Asana والخصائص التي توفرها لإدارة عمل فرق العمل عن بعد، التواصل فيما بينهم، وتسهيل رؤية نتائج العمل. كما تعرّفنا على كيفية إنشاء حساب Asana وبعض الأمور التي تتعلّق بالحساب. في هذا الجزء سنتعرّف على واجهة Asana بجميع أقسامها، كما سنأتي إلى شرح اختصارات لوحة المفاتيح التي ستوفّر عليك الوقت الكثير وتساعدك في تسريع تدفّق العمل. الواجهة تُقسم واجهة Asana إلى خمسة أقسام: الشريط الجانبي Sidebar.الشريط العلوي Top Bar.الترويسة Header.اللوحة الرئيسيّة Main Pane.اللوحة اليمنى. Right Pane.وكما موضّحة في الصورة أعلاه. أولا: الشريط الجانبي تستطيع من خلال الشريط الجانبي: الوصول لوحة التحكم My Dashboard.الوصول إلى مفضلتك Favorites، من المشاريع، الأشخاص (قوائم مهامهم)، الوسوم، وغيرها، والتي تتمثّل بأيقونة النجمة.الوصول إلى الأنشطة المشاريع، الأشخاص، الوسوم التي قمت باستعراضها مؤخرًا، Recents، والتي تتمثّل بأيقونة الساعة.الوصول إلى محادثات الفريق Team Conversations.الوصول إلى تقويم الفريق Team Calendar.الوصول إلى فريقك (وهذا في حالة "المؤسسات Organizations" فقط)، أو مشاريع "مساحة العمل Workspace" الخاصّة بك.استعراض الفرق التي تنتمي إليها والانضمام إلى فرق أخرى في "مؤسستك".لوحة التحكم Dashboardتوفّر لوحة التحكم نظرة أوسع وأشمل حول حالات المشاريع التي تعمل عليها وتعرض الرسوم البيانية التي توضّح تقدم تلك المشاريع. وبذلك تستطيع إدارة العمل دون أن تضطر إلى مغادرة الصفحة. انقر على My Dashboard وسيتم إظهارها في اللوحة الرئيسيّة. المشاريع Projectsالمشروع هو عبارة عن مجموعة من المهام. يستخدم المشروع لتحقيق الهدف النهائي بتقسيمه إلى عدة مهام يتم توكيلها إلى أفراد الفريق لتحقيق ذلك الهدف. يعرض الشريط الجانبي مشاريعك في فريقك أو في "مساحة العمل" الخاصّة بك. انقر على اسم المشروع وسيتم إظهاره في اللوحة الرئيسيّة. ملاحظة: تشير أيقونة القفل في الصورة أعلاه إلى أنّ المشروع خاص Private Project، وهذا أحد خيارات خصوصية المشاريع التي هي: Private you: خاص بك؛ أي لا أحد غيرك يمكنه مشاهدة المشروع.Private to Members: خاص بأعضاء المشروع فقط.Public: عام، ويستطيع كل شخص في الفريق أو "مساحة العمل" الوصول إليه ورؤيته.خيارات المشروعمرر الفأرة فوق اسم المشروع وانقر على أيقونة الثلاث نقاط لاستعراض بعض خيارات المشروع. انقر على السهم للوصول إلى الخيارات التالية: Highlight Color: لتغيير لون المشروع.الإضافة إلى/ الحذف من المفضلة.(Use as a Template (Copy Project: لنسخ المشروع.Archive: لأرشفة المشروع.Delete: لحذف المشروع.كما تستطيع الوصول إلى المزيد من الخيارات عند فتح المشروع. سحب المشروع وإسقاطه Drag & Drop وتستخدم هذه الخاصية لغرض ترتيب المشاريع في الشريط الجانبي. المفضلات Favoritesتستطيع تأشير المشاريع، الأشخاص (قوائهم مهامهم)، الوسوم، أو البحث المخصّص Search Views كمفضلة لحفظها في الشريط الجانبي وتسهيل الوصول إليها. وسيظهر ما قمت بتفضيله لك فقط، حيث أنّ كل شخص لديه قائمة من المفضلات الخاصّة به. ستظهر المفضلات في موضع ثابت في الجزء العلوي من الشريط الجانبي وعلى جانبها أيقونة النجمة. ويمكنك إعادة ترتيب المفضلات عن طريق السحب والإسقاط. الإضافة إلى/الحذف من المفضلةانقر على أيقونة النجمة في الترويسة لإضافة مشروع ما إلى المفضلة، وستلاحظ تغير لون النجمة إلى الأصفر وظهور المشروع في الجزء العلوي من الشريط الجانبي. وإذا قمت بالنقر على أيقونة النجمة من جديد سيتم إزالة المشروع من المفضلة بتغيّر لون النجمة إلى الأبيض واختفاء المشروع من الشريط الجانبي. الأنشطة الحديثة Recentsيتيح لك هذا الخيار الانتقال السريع إلى المشاريع، الأشخاص، أو الوسوم التي قمت باستعراضها مؤخرًا. وستظهر الأنشطة الحديثة تلقائيًا أسفل المفضلات مباشرةً، وبجانبها أيقونة الساعة. إخفاء وإظهار الشريط الجانبيبإمكانك إخفاء الشريط الجانبي عن طريق النقر على علامة X في الجزء العلوي منه إذا كنت تريد توسيع مساحة المركز واللوحة اليمنى. ولإظهاره من جديد، انقر على زر الخطوط الثلاثة. ثانيا: الشريط العلوي تستطيع من خلال الشريط العلوي: الوصول إلى قائمة مهامك My Tasks.الوصول إلى صندوق الوارد My Inbox.استخدام زر الإضافة السريعة Quick Add المتمثل بأيقونة + لإنشاء مهمّة، مشروع، محادثة، أو دعوة المزيد من الأشخاص.إجراء بحث عن المهام، المشاريع، المحادثات، الوسوم، أو الأشخاص.الوصول إلى المساعدة Help.الوصول إلى إعدادات الملف الشخصي، إعدادات "مساحات العمل" أو "المؤسسات"، أو التبديل بين "مساحات العمل" أو "المؤسسات" الخاصّة بك.مهامي My Tasksستظهر المهام التي أوكلت إليك في كل "مؤسسة" أو "مساحة عمل" في قائمة My Tasks، وعادةً ما تكون قائمة مهامك هي محطتك الأولى في Asana يوميًا. وستظهر هذه القائمة في اللوحة الرئيسيّة عند النقر على My Tasks. صندوق الوارد My Inboxيمكن اعتبار صندوق الوارد بمثابة مركز التنبيهات/الإشعارات في Asana، حيث يُستخدم للاطلاع على آخر التحديثات من قبل زملائك في الفريق. التحديثات التي تصلك إلى صندوق الوارد هي: المهام التي أوكلت إليك.المهام التي تقوم بمتابعتها.المشاريع التي تشارك فيها.المحادثات التي تم إشراكك بها. زر الإضافة السريعة Quick Add يتيح لك زر الإضافة السريعة (+) سهولة: إنشاء مهمّة.إنشاء مشروع.بدء محادثة.دعوة عضو جديد إلى "مساحة العمل" أو "المؤسسة" الحالية الخاصّة بك.البحث Searchاستخدم البحث للعثور على المهام، المشاريع، المحادثات، الوسوم، أو الأشخاص. قم بالنقر داخل حقل البحث واكتب النص الذي تريد البحث عنه ثم اضغط Enter. أو اختر "البحث المتقدّم" Advanced Search لإنشاء بحث مخصّص Search View. البحث المخصّص Search Viewالبحث المخصّص هو عبارة عن قائمة من المهام التي تطابق المعايير التي تحددها عند البحث. استخدم البحث المخصص للعثور على أي مجموعة محددة من المهام. بإمكانك إنشاء بحث يتضمن أي مجموعة كانت من الأشخاص الذين أوكلت إليهم المهام assignees، المشاريع، الوسوم، تواريخ انتهاء المشاريع due dates، وغيرها الكثير. ستشاهد في نافذة البحث المتقدم العديد من المتغيّرات التي يمكنك استخدامهم لتخصيص البحث عن المهام أو المحادثات. كما يمكنك استخدام متغيرات أخرى عن طريق الخيار Search by Another Field في أسفل نافذة البحث المتقدم. المساعدة Help تستطيع الوصول إلى نافذة المساعدة والحصول على الكثير من الموارد المفيدة عن طريق النقر على زر علامة الاستفهام في الشريط العلوي. القائمة المنسدلة للشريط العلوي انقر على صورة الملف الشخصي في الشريط العلوي لإظهار القائمة المنسدلة التي تستطيع من خلالها: التبديل بين "مساحات العمل" و"المؤسسات" الخاصّة بك.ترقية "مساحة العمل" أو "المؤسسة" الحاليّة إلى الخدمة المدفوعة Premium.الوصول إلى إعداد "مساحة العمل" أو "المؤسسة" الحالية.إنشاء "مساحة عمل" جديدة.مغادرة "مساحة العمل" أو "المؤسسة" الحالية.الوصول إلى إعدادات الملف الشخصي.تسجيل الخروج.لاحظ أنّ علامة الصح في الصورة أعلاه تشير إلى "مساحة العمل" أو "المؤسسة" التي تشاهدها حاليًا. ثالثا: الترويسة تستطيع من خلال الترويسة: تأشير المشروع، المهمّة، أو البحث المخصص الذي تستعرضه حاليًا كمفضّل عن طريق أيقونة النجمة.الوصول إلى خيارات المشروع، المهام، أو البحث المخصّص الذي تستعرضه حاليًا عن طريق أيقونة السهم المتجه إلى الأسفل.تغيير طريقة عرض المشروع، المهام، أو البحث المخصص الذي تستعرضه حاليًا.عرض قائمة أعضاء المشروع.خيارات القائمة المنسدلة في الترويسة تتيح لك القائمة المنسدلة عن النقر على السهم الوصول إلى الخيارات التالية: Edit Name & Description: لتعديل اسم ووصف مشروعك.Sync to Calendar: لمزامنة مهامك وتواريخ انتائها إلى تقويم خارجي، كتقويم جوجل، Outlook، iCal أو أي تقويم آخر يتيح لك الاشتراك بواسطة العناوين URL.Add Tasks by Email: يوفر هذا الخيار عنوان بريد إلكتروني يمكن استخدامه لإنشاء مهام عن طريق إرسال بريد إلكتروني داخل Asana.Print: لطباعة المشروع.(Use as Template (Copy Project: لنسخ المشروع (تكريره).Move to Another Team: لنقل المشروع إلى فريق آخر في مؤسستك، علمًا أنّ هذا الخيار مُتاح في "المؤسسات" فقط.Highlight Color: لتغيير لون المشروع.Export: لتصدير المشروع أو "مهامي My Tasks" كملف CSV أوJSON.Archive: لأرشفة المشروع.Delete: لحذف المشروع.طرق عرض المشروع Views بإمكانك التبديل بين خمس طرق عرض مختلفة للمشروع عن طريق الترويسة: List: وهذا هو الخيار الافتراضي لعرض المشروع الذي يعرض قائمة من المهام.Conversations: تتيح لك طريقة العرض هذه بدء المحادثات مع زملائك في المشروع نفسه، وهذا الخيار مُتاح في المشاريع فقط.Calendar: في طريقة العرض هذه تتم تصفية المهام فقط مع تواريخ انتهائها وعرضها على شكل تقويم.Progress: لعرض المعلومات حول المشروع وتقدّمه، بما في ذلك تحديثات الحالة ومخطط التقدّم، وهذا الخيار أيضًا مُتاح في المشاريع فقط.Files: لتصفية المهام مع المرفقات attachments، وهذا الخيار مُتاح في المشاريع و"مهامي My Tasks".إخفاء وإظهار الترويسةتستطيع إخفاء الترويسة لتوسيع مساحة المركز واللوحة اليمنى عن طريق أيقونة السهم المزدوج في اليسار. ولعرضها مجددًا، قم بالنقر على أيقونة السهم المزدوج نفسها. رابعا: اللوحة الرئيسيةعندما تقوم بتحديد مشروع، وسم، أو شخص ما من الشريط الجانبي، ستظهر قائمة المهام ذات الصلة بما قمت بتحديده في اللوحة الرئيسيّة. كما أنّها المكان الذي ستشاهد فيه نتائج بحثك، التنبيهات الواردة، بطاقات لوحة تحكّم المشروع، ومشاركات المحادثة. من خلال اللوحة الرئيسيّة تستطيع: إضافة مهمّة جديدة.فرز وتصفية قائمة المهام.تأشير المهمّة كمنتهية أو غير منتهية.عرض وتعديل اسم المهمّة.تحديد المشاريع أو الوسوم الأخرى التي ترتبط بها المهمّة.مشاهدة عدد "القلوب"* التي حصلت عليها المهمّة.تحديد تاريخ انتهاء المهمّة due date.تحديد الشخص المسؤول عن إنجاز المهمّة assignee.يستخدم زر "القلب" للتعبير عن اهتمامك بالمهمّة أو تحمّسك لها، إبداء الموافقة على تعليق أحدهم، أو التعبير الامتنان لإنجاز مهمّة ما. خامسا: اللوحة اليمنىاللوحة في الجانب الأيمن من المتصفح هي المكان التي تظهر فيه تفاصيل المهمّة التي يتم تحديدها في اللوحة الرئيسيّة. من خلال اللوحة اليمنى تستطيع: توكيل المهمّة إلى شخص في الفريق.تعيين تاريخ ووقت انتهاء المهمّة.التعبير عن الاهتمام بالمهمّة عن طريق زر "القلب".تحديد المشروع الذي تنتمي إليه المهمّة.تأشير المهمّة كمنتهية أو غير منتهية.إضافة وصف للمهمّة لتوضيح المزيد من التفاصيل.بناء قائمة من المهام الفرعية.إرفاق الملفات.إضافة تعليق على المهمّة.متابعة، أو إلغاء متابعة المهمّة.إخفاء وإظهار اللوحة اليمنىتستطيع إخفاء اللوحة اليمنى لتوسيع مساحة المركز عن طريق النقر على أيقونة X. ولإعادة اظهارها مجددًا، انقر على زر السهم الأيمن. وضع ملء الشاشة بإمكانك استخدام وضع ملء الشاشة إذا رغبت في التركيز على مهمّة محددة وذلك عن طريق: النقر على أيقونة الثلاث نقاط في أعلى اللوحة اليمنى.اختيار Full Screen. اختصارات لوحة المفاتيحتفيد اختصارات لوحة المفاتيح في تسريع تدفق العمل وتسهيل تنفيذ بعض الأوامر دون الحاجة إلى استخدام الفأرة. الاختصارات الأساسية موضحة أدناه لنظام Windows. أما بالنسبة لنظام Mac فهي نفسها، قم فقط استبدال مفتاح Ctrl بمفتاح Cmd. ويرجى ملاحظة أنّ بعض الاختصارات قد لا تعمل على لوحات المفاتيح الدولية. الاختصارات الخاصة بالمهامEnter: إنشاء مهمّة جديدة.Tab+ BKSP: مسح المهمّة/ المهام المحددة (أو BKSP عندما يكون اسم المهمّة فارغًا).Ctrl+ Enter: تأشير المهمّة/المهام المحددة كمنتهية.Ctrl+ السهم الأعلى/ Ctrl+السهم الأسفل: التحرّك إلى الأعلى/إلى الأسفل.Ctrl+ Shift+ السهم الأعلى/ Ctrl+ Shift+ السهم الأسفل: للانتقال إلى القسم section التالي الأعلى/الأسفل.Ctrl+ C: نسخ المهام المحددة.Ctrl+ V: لصق المهام المحددة (واحدة لكل سطر).Tab+ M: تعيين نفسك كمسؤول عن إنجاز المهمّة المحددة.Tab+ H: إعطاء "قلب" للمهمّة المحددة.Tab+ Y: تأشير المهمّة لإنجازها اليوم Today.Tab+ U: تأشير المهمّة كالمهمّة القادمة Upcoming.Tab+ L: تأشير المهمّة لإنجازها لاحقًا Later.: اكتب النقطتين في نهاية اسم المهمّة لإنشاء قسم جديد.Tab+ Z: أرشفة المهام المكتملة.Tab+ C: التعليق على المهمّة المحددة.Tab+ A: توكيل المهمّة المحددة إلى أحد أعضاء المشروع.Tab+ D: تعيين تاريخ انتهاء المهمّة Due Date.Tab+ F: إضافة مُتابع للمهمّة.Tab+ S: إنشاء مهمّة فرعية Subtask.Tab+ /: البحث عن مشروع، وسم، شخص، أو مهمّة.Tab+ Enter: الانتقال إلى قائمة المهام.الاختصارات الخاصة بالتحديدالسهم الأعلى/السهم الأسفل: تغيير التحديد.Shift+ زر الفأرة الأيسر: تحديد مجموعة من المهام المتجاورة.Shift+ السهم الأعلى/السهم الأسفل: تحديد مجموعة من المهام المتجاورة للأعلى/للأسفل.Ctrl+ زر الفأرة الأيسر: لتحديد عدد من المهام المتفرقة غير المتجاورة.الاختصارات الخاصة بصندوق الواردJ/K: التحرّك إلى الأعلى/ الأسفل.H: إخفاء أرشيف التنبيهات (الانتقال إلى تبويب صندوق الوارد).S: إظهار أرشيف التنبيهات (الانتقال إلى تبويب الأرشيف).F: متابعة أو إلغاء متابعة.I: أرشفة التنبيه المحدد.U: لإرسال الأرشيف المحدد إلى صندوق الوارد.Ctrl+ /: عرض اختصارات لوحة المفاتيح.Tab: فتح التفاصيل.ESC: غلق التفاصيل.Tab+ X: وضع التركيز.Tab+ Q: الإضافة السريعة.Tab+ Enter: نشر تعليق (من حقل التعليقات).Tab+ B: What it sounds like.بعد أن تعرّفت على Asana، واجهتها، وكيفية إنشاء الحساب، حان الوقت لتتعرف على كيفية استخدامها ودعوة فريقك، وهذا ما سنستعرضه في الجزء الثالث من هذه السلسة. ترجمة وبتصرف لأدلة المساعدة لخدمة asana.
  8. قمنا في الدرس الأول من هذه السلسلة بإنهاء تصميم واجهة مدونة بناءً على مبادئ الخطوط والطباعة (typography) باستخدام برنامج فوتوشوب، وكنا قد استعملنا نظام شبكي (grid) صارم لتخطيط الصفحة. وفي هذا الدرس سنقوم بتحويل ذلك التصميم إلى نموذج HTML5. وفي الدرس التالي والأخير من هذه السلسلة سنقوم بتحويل هذا النموذج إلى قالب ووردبريس كامل. يمكنك الاطلاع على الدرس السابق الذي قمنا فيه بتصميم واجهة المدونة باستخدام الفوتوشوب. وقد قلنا بأن اسم القالب سيكون "Typo" وبأنه سيعتمد بشكل كلي على الـtypography من دون استعمال أي صور حتى يكون التركيز بالكامل على المحتوى. التحضير لبدء التكويدبما أنّ هذا التصميم بسيط ويرتكز بشكل كبير على مبادئ الـtypography فلن يكون هناك الكثير من الصور التي سنحتاج إلى استخراجها من الفوتوشوب، فالملفات الوحيدة التي سنحتاج إلى استخراجها هي الخلفية المزخرفة (background texture) وبعض الأيقونات. مع ذلك وحتى نجعل عملية التكويد سهلة فسوف نقوم باستخراج نُسخ من الأعمدة (columns) والخطوط الشبكية (grid lines) مما يسهل عملية موضعة ومحاذاة العناصر أثناء عملية التكويد. سنقوم بتحويل هذا التصميم باستخدام عناصر HTML5 (مثل <header> ،<nav> ،<section>)، وبذلك فإنّه من الضروري أن تعرف هذه العناصر وفيما إذا كانت مناسبة لهذا التصميم. بنية ملف HTML5<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Typo</title> <link href="style.css" rel="stylesheet" /> <link href='http://fonts.googleapis.com/css?family=Droid+Serif:400,400italic' rel='stylesheet' type='text/css'> <script src="js/scripts.js"></script> </head> <body> <div id="container">يبدأ الملف عادة بـDoctype لتعريف المتصفح بأننا نستخدم HTML5، وهناك أيضًا وسم <head> وبداخله وسم <title> يحتوي على عنوان المدونة ووسم <link> لربط ملف CSS الذي نريد استخدامه. لاحظ أيضًا أننا استعملنا خدمة Google We Fonts للحصول على الخط Droid Serif. من الضروري أن تنتبه أيضًا لأمر ما وهو أنه عندما تريد أن تقوم بتكويد أي صفحة باستخدام وسوم HTML5 فإنه لا يجب عليك دائمًا استخدام وسوم <section> بدلًا من <div>، ففي بعض الأحيان تكون وسوم <div> مناسبة أكثر (كأن تستخدمه كحاوي لباقي العناصر). <header> <h1><a href="#" title="Return to the homepage">Typo</a></h1> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Archives</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header>أحد الوسوم الجديدة في لغة HTML5 هو <header> ويعد استخدام هذا الوسم من أجل بناء وتكويد ترويسة الموقع أفضل من استخدام وسم <div> وإعطائه id بقيمة "header" كما يفعل الكثير من المطورين. ويمكنك بعد ذلك أن تضع وسم <nav> داخله ليحتوي على القائمة الرئيسية للموقع (main navigation menu). استخدمنا أيضًا وسم <h1> وبداخله وسم <a> ليحتوي على عنوان المدونة (ليعمل وكأنه شعار الموقع). إذا كنت تتذكر عندما صممنا الموقع في فوتوشوب فقد قمنا بوضع رقم بجانب كل عنصر من عناصر القائمة الرئيسية، لذلك قد تعتقد أنه من المناسب استعمال <ol> ولكن من وجهة نظر دلالية (semantically) فهذا غير صحيح لأنه لا يوجد علاقة ترابطية/تتابعية بين تلك العناصر فهي وضعت فقط من أجل تجميل تلك العناصر، وبالتالي سوف نقوم بإضافة هذه الأرقام لاحقًا باستخدام CSS. <div id="content" role="main"> <article> <h2><a href="#">Getting your stock photos seen</a></h2> <p>Lorem ipsum dolor sit amet[...]leo placerat.</p> <ul class="postinfo"> <li>17th October 2011</li> <li>Posted in <a href="#">Articles</a></li> <li><a href="#">Continue Reading &raquo;</a></li> </ul> </article>قد تعتقد أيضًا أن استعمال <section> بدلًا من <div> هو الأنسب، ولكن هذا غير صحيح من ناحية دلالية (semantic). فالطريقة المفضلة هي استخدام <div> مع إضافة ARIA role بالقيمة "main" حتى نعطي للوسم معنى أفضل. وبالنسبة لمحتوى المدونة (المقالات) يمكنك استخدام <article> لاحتوائها. <nav id="pagination"> <ul> <li class="older"><a href="#">&laquo; Older posts</a></li> <li class="newer"><a href="#">Newer posts &raquo;</a></li> </ul> </nav> </div>أسفل المقالات يوجد روابط ترقيم الصفحات (pagination)، وفي العادة فإنّ هذه الروابط ليست بتلك الأهمية التي تجعلنا نضعها داخل وسم <nav> (استخدام <nav> ليس محصورًا فقط على القائمة الرئيسية للمدونة، بل يمكن استخدامه في عدة أماكن) إلّا أنني أرى أنّ روابط ترقيم الصفحات مهمة في أي مدونة للوصول إلى محتوى إضافي. <aside id="sidebar"> <section id="about"> <h3>About me</h3> <p>Typo is a WordPress theme based entirely on a balanced typographic design. A strict grid layout keeps everything tidy, allowing the content to shine. <a href="#" class="more">Find out more &raquo;</a></p> </section> <section id="categories"> <h3>Categories</h3> <ul> <li><a href="#">Articles</a></li> <li><a href="#">Design</a></li> <li><a href="#">Graphics</a></li> <li><a href="#">Inspiration</a></li> <li><a href="#">Retro</a></li> </ul> </section>لاحظ أننا استخدمنا الوسم <aside> لاحتواء محتوى القائمة الجانبية (sidebar). لاحظ أنّ القائمة الجانبية تحتوي على عدة أقسام وبالتالي سيكون استخدام <section> لكل قسم في هذه الحالة مناسبًا أكثر من <div>. <section id="search"> <h3>Search</h3> <form method="get" action="#"> <fieldset> <input type="text" id="searchbar" placeholder="I'm looking for&hellip;" /> <input type="submit" id="searchsubmit" value="Search" /> </fieldset> </form> </section> </aside> وفي أسفل القائمة الجانبية يوجد مربع البحث، وسوف نستخدم بعض من الخصائص الجديدة في لغة HTML5. وأحد هذه الخصائص هو placeholder بحيث تمكننا هذه الخاصية من وضع نص داخل حقل الإدخال لإخبار المستخدم بما يجب عليه إدخاله في ذلك الحقل. </div> <div id="footer-container"> <footer> <ul id="credits"> <li class="wordpress"><a href="http://wordpress.org">Powered by WordPress</a></li> <li class="spoongraphics"><a href="http://www.blog.spoongraphics.co.uk">Theme by SpoonGraphics</a> </li> </ul> <p id="back-top"><a href="#">Back to top</a></p> </footer> </div>بقي علينا الآن إضافة الـfooter، ففي هذه الحالة سنحتاج إلى وضعه خارج منطقة المحتوى الرئيسي لنسمح له بالتمدد على كامل الصفحة. يمكننا استخدام الوسم <footer> لاحتواء عناصر ومحتويات تلك المنطقة. ملف الـHTML كاملا<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Typo</title> <link href="style.css" rel="stylesheet" /> <link href='http://fonts.googleapis.com/css?family=Droid+Serif:400,400italic' rel='stylesheet' type='text/css'> <script src="js/scripts.js"></script> </head> <body> <div id="container"> <header> <h1><a href="#" title="Return to the homepage">Typo</a></h1> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Archives</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header> <div id="content" role="main"> <article> <h2><a href="#">Getting your stock photos seen</a></h2> <p>Lorem ipsum dolor sit amet[...]leo placerat.</p> <ul class="postinfo"> <li>17th October 2011</li> <li>Posted in <a href="#">Articles</a></li> <li><a href="#">Continue Reading &raquo;</a></li> </ul> </article> <article> <h2><a href="#">Top 10 tips for new bloggers</a></h2> <p>Lorem ipsum dolor sit amet[...]leo placerat.</p> <ul class="postinfo"> <li>17th October 2011</li> <li>Posted in <a href="#">Articles</a></li> <li><a href="#">Continue Reading &raquo;</a></li> </ul> </article> <article> <h2><a href="#">10 fantastic photography tips</a></h2> <p>Lorem ipsum dolor sit amet[...]leo placerat.</p> <ul class="postinfo"> <li>17th October 2011</li> <li>Posted in <a href="#">Articles</a></li> <li><a href="#">Continue Reading &raquo;</a></li> </ul> </article> <nav id="pagination"> <ul> <li class="older"><a href="#">&laquo; Older posts</a></li> <li class="newer"><a href="#">Newer posts &raquo;</a></li> </ul> </nav> </div> <aside id="sidebar"> <section id="about"> <h3>About me</h3> <p>Typo is a WordPress theme based entirely on a balanced typographic design. A strict grid layout keeps everything tidy, allowing the content to shine. <a href="#" class="more">Find out more &raquo;</a></p> </section> <section id="categories"> <h3>Categories</h3> <ul> <li><a href="#">Articles</a></li> <li><a href="#">Design</a></li> <li><a href="#">Graphics</a></li> <li><a href="#">Inspiration</a></li> <li><a href="#">Retro</a></li> </ul> </section> <section id="social"> <h3>social</h3> <ul> <li><a href="#">Twitter</a></li> <li><a href="#">Facebook</a></li> <li><a href="#">Flickr</a></li> <li><a href="#">Behance</a></li> <li><a href="#">Last.FM</a></li> <li><a href="#">Youtube</a></li> </ul> </section> <section id="latest"> <h3>Latest posts</h3> <ul> <li><a href="#">Getting your stock photos seen</a></li> <li><a href="#">Top 10 tips for new bloggers</a></li> <li><a href="#">10 fantastic photography tips</a></li> </ul> </section> <section id="search"> <h3>Search</h3> <form method="get" action="#"> <fieldset> <input type="text" id="searchbar" placeholder="I'm looking for&hellip;" /> <input type="submit" id="searchsubmit" value="Search" /> </fieldset> </form> </section> </aside> </div> <div id="footer-container"> <footer> <ul id="credits"> <li class="wordpress"><a href="http://wordpress.org">Powered by WordPress</a></li> <li class="spoongraphics"><a href="http://www.blog.spoongraphics.co.uk">Theme by SpoonGraphics</a></li> </ul> <p id="back-top"><a href="#">Back to top</a></p> </footer> </div> </body> </html>إضافة تنسيقات CSSبما أننا نملك الآن مستند HTML جاهز فيمكننا إضافة تنسيقات CSS للخروج بصفحة تشبه التي قمنا بتصميمها باستخدام الفوتوشوب. body, div, h1, h2, h3, h4, h5, h6, p, ul, ol, li, dl, dt, dd, img, form, fieldset, input, textarea, blockquote { margin: 0; padding: 0; border: 0; } body { background: #dedede url(images/bg.jpg); font-family: 'Droid Serif', serif; font-size: 14px; line-height: 24px; color: #666; } a { color: #4b7ea9; font-style: italic; } a:hover { color: #105896; } header a, h2 a { color: #666; font-style: normal; text-decoration: none; } #container { width: 916px; margin: 0 auto; padding: 48px 22px 0 22px; background: url(images/grid.jpg); overflow: hidden; }يُستخدم السطر الأول من أجل إزالة أي تنسيقات افتراضية للمتصفحات (يسمى هذا "CSS reset")، وبعد ذلك يوجد داخل المحدد body الخصائص العامة للخطوط (ما يهمنا هنا هو الخاصية line-height، فقد أعطيناها القيمة 24px حتى تتوافق مع شبكة الخطوط القاعدية (baseline grid) التي استخدمناها في تصميم الواجهة في برنامج الفوتوشوب (وصورة خلفية. وبما أننا أضفنا الكود الخاص بخدمة Google Web Fonts في ملف الـHTML فيمكننا استخدام الخط Droid Serif في تنسيقات CSS كما يحلو لنا. أضفنا أيضًا التنسيقات الخاصة بالروابط ولكن استثنينا الروابط الموجودة في الترويسة (header) وعناوين التدوينات (الموجودة داخل وسم <h2>) حتى يتوافق كل شيء مع التصميم. قمنا أيضًا بتوسيط الحاوي الرئيسي باستخدام margin: 0 auto ووضعنا لهذا الحاوي صورة الشبكة (grid) على شكل خلفية حتى نستطيع موضعة عناصر الصفحة بكل سهولة بناءً على التصميم الموجود لدينا. header { margin: 0 0 98px 0; } header h1 { float: left; font-size: 36px; font-weight: normal; } header nav { float: right; text-align: right; padding: 6px 0 0 0; } header nav ul { list-style: none; } header nav li { float: left; font-size: 18px; width: 136px; margin: 0 0 0 20px; } header nav li:nth-child(1):before { content: "1. "; color: #a2a2a2; } header nav li:nth-child(2):before { content: "2. "; color: #a2a2a2; } header nav li:nth-child(3):before { content: "3. "; color: #a2a2a2; } header nav li:nth-child(4):before { content: "4. "; color: #a2a2a2; } header nav li:nth-child(5):before { content: "5. "; color: #a2a2a2; }استعملنا margins وpaddings بقيم مناسبة لوضع العناصر استنادًا على خطوط الشبكة مع استخدام بعض القيم العشوائية مثل 98px حتى نضمن أن كل شيء موضوع في مكانه الصحيح. يمكنك استخدام Developer tools أو Firebug لمساعدتك في عمل التعديلات من دون أن يصيبك صداع في رأسك بسبب وجود بعض الحسابات المعقدة قليلًا. هل تذكر عندما تكلمنا عن تلك الأرقام الموجودة بجانب عناصر القائمة الرئيسية؟ فقد قلنا بأننا سوف نستخدم CSS لإضافتها لأنها ليست مهمة كثيرًا ولأننا لا نريدها أن تظهر في ملف HTML، وللقيام بذلك سوف نستخدم المحددين :nth-child و :before مع الخاصية content التي سنضع الأرقام بداخلها. #content { float: left; width: 526px; margin: 0 98px 0 0; } #content article { margin: 0 0 67px 0; } #content article h2 { font-size: 30px; margin: 0 0 29px 0; font-weight: normal; } #content p { margin: 0 0 24px 0; } #content .postinfo { list-style: none; overflow: hidden; } #content .postinfo li { float: left; width: 136px; margin: 0 20px 0 0; font-style: italic; color: #a2a2a2; } #pagination { overflow: hidden; margin: 0 0 120px 0; } #pagination ul { list-style: none; } #pagination li { font-size: 18px; } #pagination li.older { float: left; } #pagination li.newer { float: right; }قمنا أيضًا بإضافة تنسيقات CSS الخاصة بالتدوينات ابتداءً بـdiv المحتوى. بالنسبة لعرض هذا الـdiv فقد قمنا بحسابه اعتمادً على عرض الأعمدة والمسافة بينها (columns and gutters) التي عندما نقوم بجمعها مع العرض الخاص بالقائمة الجانبية وأي margins فإنها تعطينا العرض الخاص بالـdiv الحاوي (container div). قمنا أيضًا بإضافة تنسيقات الخطوط الخاصة بعناصر h2 وmargin بقيمة مناسبة حتى يبقى كل شيء متوافقًا مع شبكة الخطوط القاعدية، واستعملنا الخاصية ()background: url لوضع صورة شعار ووردبريس في أسفل يسار الصفحة ولم ننسَ أيضًا العنصر back-top# إلى يسار الصفحة بحيث يأخذنا إلى أعلى الصفحة عند الضغط عليه. #sidebar { width: 292px; float: left; padding: 4px 0 0 0; } #sidebar h3 { font-size: 18px; font-weight: normal; margin: 0 0 25px 0; } #sidebar ul { list-style: none; } #sidebar section { margin: 0 0 47px 0; } #sidebar #about a.more { display: block; text-align: right; } #sidebar #categories { width: 136px; float: left; margin: 0 20px 0 0; } #sidebar #social { width: 136px; float: left; }قمنا بإزاحة القائمة الجانبية إلى جانب المحتوى الرئيسي (عن طريق الخاصية float:left) وأضفنا التنسيقات الخاصة بالعناصر الموجودة داخلها ليصبح كل شيء كما هو موجود في تصميم الفوتوشوب. بعض عناصر القائمة الجانبية يمكن وضعها بجانب بعضها، لذلك قمنا بإضافة العرض المناسب لهذه العناصر حتى تتوافق مع التصميم. #sidebar #search #searchbar { width: 230px; height: 36px; float: left; border: 1px solid #c7c7c7; padding: 0 45px 0 15px; margin: -8px 0 0 0; background: #e2e2e2; /* Old browsers */ background: -moz-linear-gradient(top, #e2e2e2 0%, #ffffff 16%); /* FF3.6+ */ background: -webkit-linear-gradient(top, #e2e2e2 0%,#ffffff 16%); /* Chrome10+,Safari5.1+ */ font-size: 14px; font-style: italic; color: #a2a2a2; } #sidebar #search #searchsubmit { width: 17px; height: 17px; float: right; margin: -27px 15px 0 0; background: url(images/search-icon.png); text-indent: -9999px; }مربع البحث هو العنصر الوحيد في الموقع الذي يحتوي على تأثيرات بصرية، فيمكننا إضافة تأثيرات التدرج باستخدام خاصية gradient الموجودة في لغة CSS، وبالنبسة للأيقونة فيمكننا إضافتها باستخدام الخاصية ()background: url. #footer-container { background: rgba(0,0,0,0.2); overflow: hidden; } footer { width: 916px; margin: 0 auto; padding: 10px 22px 50px 22px; } footer #credits { list-style: none; float: left; } footer #credits li { float: left; margin: 0 6px 0 0; } footer #credits li.wordpress a { display: block; width: 20px; height: 20px; background: url(images/credits.png) no-repeat 0 0; text-indent: -9999px; } footer #credits li.spoongraphics a { display: block; width: 25px; height: 20px; background: url(images/credits.png) no-repeat -30px 0; text-indent: -9999px; } footer #back-top { float: right; font-size: 12px; }كا ما تبقى علينا الآن هو إضافة التنسيقات الخاصة بالـfooter. يمكننا محاكاة خلفية الـfooter عن طريق استخدام الخاصية background وإعطاؤها لونًا أسودًا بشفافية 20% (background: rgba(0,0,0,0.2. وبما أنَ الحاوي الخاص بالـfooter سيتمدد على كامل الصفحة فإننا سنضطر إلى إعطاء الـfooter قيم width وmargin مختلفة. تنسيقات CSS كاملةbody, div, h1, h2, h3, h4, h5, h6, p, ul, ol, li, dl, dt, dd, img, form, fieldset, input, textarea, blockquote { margin: 0; padding: 0; border: 0; } body { background: #dedede url(images/bg.jpg); font-family: 'Droid Serif', serif; font-size: 14px; line-height: 24px; color: #666; } a { color: #4b7ea9; font-style: italic; } a:hover { color: #105896; } header a, h2 a { color: #666; font-style: normal; text-decoration: none; } #container { width: 916px; margin: 0 auto; padding: 48px 22px 0 22px; background: url(images/grid.jpg); overflow: hidden; } header { margin: 0 0 98px 0; } header h1 { float: left; font-size: 36px; font-weight: normal; } header nav { float: right; text-align: right; padding: 6px 0 0 0; } header nav ul { list-style: none; } header nav li { float: left; font-size: 18px; width: 136px; margin: 0 0 0 20px; } header nav li:nth-child(1):before { content: "1. "; color: #a2a2a2; } header nav li:nth-child(2):before { content: "2. "; color: #a2a2a2; } header nav li:nth-child(3):before { content: "3. "; color: #a2a2a2; } header nav li:nth-child(4):before { content: "4. "; color: #a2a2a2; } header nav li:nth-child(5):before { content: "5. "; color: #a2a2a2; } #content { float: left; width: 526px; margin: 0 98px 0 0; } #content article { margin: 0 0 67px 0; } #content article h2 { font-size: 30px; margin: 0 0 29px 0; font-weight: normal; } #content p { margin: 0 0 24px 0; } #content .postinfo { list-style: none; overflow: hidden; } #content .postinfo li { float: left; width: 136px; margin: 0 20px 0 0; font-style: italic; color: #a2a2a2; } #pagination { overflow: hidden; margin: 0 0 120px 0; } #pagination ul { list-style: none; } #pagination li { font-size: 18px; } #pagination li.older { float: left; } #pagination li.newer { float: right; } #sidebar { width: 292px; float: left; padding: 4px 0 0 0; } #sidebar h3 { font-size: 18px; font-weight: normal; margin: 0 0 25px 0; } #sidebar ul { list-style: none; } #sidebar section { margin: 0 0 47px 0; } #sidebar #about a.more { display: block; text-align: right; } #sidebar #categories { width: 136px; float: left; margin: 0 20px 0 0; } #sidebar #social { width: 136px; float: left; } #sidebar #search #searchbar { width: 230px; height: 36px; float: left; border: 1px solid #c7c7c7; padding: 0 45px 0 15px; margin: -8px 0 0 0; background: #e2e2e2; /* Old browsers */ background: -moz-linear-gradient(top, #e2e2e2 0%, #ffffff 16%); /* FF3.6+ */ background: -webkit-linear-gradient(top, #e2e2e2 0%,#ffffff 16%); /* Chrome10+,Safari5.1+ */ font-size: 14px; font-style: italic; color: #a2a2a2; } #sidebar #search #searchsubmit { width: 17px; height: 17px; float: right; margin: -27px 15px 0 0; background: url(images/search-icon.png); text-indent: -9999px; } #footer-container { background: rgba(0,0,0,0.2); overflow: hidden; } footer { width: 916px; margin: 0 auto; padding: 10px 22px 50px 22px; } footer #credits { list-style: none; float: left; } footer #credits li { float: left; margin: 0 6px 0 0; } footer #credits li.wordpress a { display: block; width: 20px; height: 20px; background: url(images/credits.png) no-repeat 0 0; text-indent: -9999px; } footer #credits li.spoongraphics a { display: block; width: 25px; height: 20px; background: url(images/credits.png) no-repeat -30px 0; text-indent: -9999px; } footer #back-top { float: right; font-size: 12px;}نموذج HTML5 النهائيأصبح نموذجنا جاهزًا الآن للاختبار قبل أن نقوم بتحويله إلى قالب ووردبريس. كل شيء يبدو جيدًا في المتصفحات الحديثة (إضافة إلى متصفح IE9). إذا أردت أن تدعم الإصدارات الأقدم من متصفح Internet Explorer فسوف تحتاج إلى المزيد من المجهود. تصفح النتيجة النهائية من هنا. ترجمة -وبتصرّف- للمقال Create a Typography Based Blog Layout in HTML5 لصاحبه Iggy.
  9. سيكون هذا هو الدرس الأول من أصل درسين سنقوم من خلالهما بتصميم وتكويد واجهة موقع لغابة افتراضية اسمها "Pinewood Forest". سنستخدم في تصميم هذه الواجهة العديد من textures وخليط من اللونين الأزرق والرمادي. ستكون النتيجة النهائية كما في الصورة التالية: سيكون الهدف من هذا الموقع هو تعريف الزوار بهذه الغابة وما تقدمه وإعلامهم بالأحداث القادمة، وستحتوي خلفية الموقع على صورة كبيرة ثابتة لتسمح بتمرير (scroll) محتوى الموقع فوقها، كما سيتم تقسيم محتوى الموقع إلى عدة أجزاء رئيسية مع استخدام بعض الصور الفوتوغرافية لجذب انتباه الزائر. سنقوم في هذا الدرس بتصميم الواجهة الرئيسية للموقع باستخدام برنامج الفوتوشوب، أمّا في الدرس الثاني فسنقوم بتكويد التصميم باستخدام لغتي HTML وCSS. سنبدأ أولًا بإنشاء مستند جديد، وبما أنّ التصميم سيحتوي على صورة خلفية كبيرة فإننا سنحتاج إلى إنشاء مستند يستطيع استيعاب الشاشات ذات الدّقة والأبعاد الكبيرة (24 أو 27 انش). باستخدام أداة marquee قم برسم منطقة في منتصف الصفحة بعرض 960px وقم بوضع guides على طرفي ما قمت برسمه. ستكون هذه المنطقة هي المنطقة التي سوف تحتوي على المحتوى الرئيسي للموقع. قم بتحميل صورة ذات أبعاد كبيرة يمكنها تغطية معظم الصفحة (يمكنك تحميل الصورة التي استعملتها في هذا الدرس من هنا). قم الآن بإدراج هذه الصورة في المستند وقم بتعديل أبعادها لتتناسب مع الشاشات الكبيرة (لنقل 1920px) واجعل هناك هامش بسيط على كلا الجانبين، ثم ضع guide أسفل الصورة ليصبح كل شيء كما في الصورة التالية: قم الآن بإضافة Layer Mask للصورة واستعمل بعضًا من الفرش المائية (Watercolor brushes) لإبهات الأطراف. قم بتخفيف شفافية (opacity) الفُرش لإنشاء مظهر أجمل لتصبح الصورة وكأنها متداخلة مع الخلفية: قم باستعمال خطّي League Gothic وClarendon لإنشاء الشّعار الخاص بالموقع وقم بوضعه في منتصف الصفحة. قم بتعديل حجم الخطوط حتى يكون التركيز أكبر على كلمة "Pinewood" وقم بمحاذاة الكلمتين عن طريق زيادة المسافة بين الحروف (the tracking) في كلمة "forest". سيكون الشعار مشابهًا للصورة: قم بإضافة تأثيري Drop Shadow وGradient Overlay لكلمة "Pinewood". سوف يضفي كلا التأثيرين نوعًا من العمق على الشعار وسيجعلانه بارزًا أكثر في الصفحة. حاول أن تجعل التباين (contrast) قليل بين تأثير الـgradient وشفافية الظل (shadow) حتى يظهر بشكل أفضل: قم بإضافة/كتابة عناصر القائمة الرئيسية وقم بتوزيعاها على التساوي على كلا جانبي الشّعار. يمكنك استعمال خط Georgia كخط بديل عن Clarendon الذي استعملناه في الشّعار. يمكن تنفيذ التباعد بين حروف الكلمات (tracking) باستعمال الخاصية letter-spacing الموجودة في لغة CSS وهو ما سنفعله لاحقًا في الدرس القادم. قم برسم مستطيل كبير بين الـguides ذات العرض 960px التي وضعناها في خطوة سابقة وقم بملء هذا المستطيل بلون رمادي فاتح كاللون المستعمل في تأثير gradient الخاص بالشّعار: قم بإضافة Noise خفيف عن طريق الذهاب إلى: Filter > Noise > Add Noise ولتكن القيمة 2.5% لإعطاء نوع من الجمال الحسي على منطقة المحتوى في الموقع. اضغط على زر ctrl في لوحة المفاتيح وأبق يدك على هذا الزر وبعدها اضغط بزر الفأرة الأيسر على الصورة المصغرة (thumbnail) للطّبقة (layer) التي أنشأناها في الخطوة السابقة. ستلاحظ أنه تم اختيار المنطقة الخاصة بتلك الطبقة. قم الآن بالضغط بزر الفأرة الأيمن على ما تمّ اختياره واختر Transform Selection ثم قم بتقليص الطول والعرض بنسبة 40px واملأ تلك المنطقة باللون الأبيض، بعدها قم بإضافة تأثير Drop Shadow على تلك الطبقة: قم بتحميل فرش paint roller واستعملها في جعل الحواف الرمادية خشنة نوعًا ما وذلك عن طريق الرسم على قناع الطبقة (layer mask). فعّل التحديد (selection) الخاص بالمنطقة البيضاء واملأها باللون الأسود فوق قناع الطبقة (layer mask) لجعلها شفافة ثم بعد ذلك قم بإنقاص شفافية الحواف الرمادية إلى 60% حتى تظهر الخلفية التي وراءها: قم بتحميل صورة ما لوضعها كخلفية للمنطقة البارزة (main feature area) في الصفحة، ثم باستخدام أداة marquee selection قم برسم مستطيل كما ها موضح في الصورة أعلاه، بعد ذلك اضغط بزر الفأرة الأيمن على تلك المنطقة واختر Select Inverse ثم اضغط على زر delete من لوحة المفاتيح: يمكنك ملاحظة أن ألوان الصورة لا تتناسب كثيرًا مع الموقع، لذلك سنقوم ببعض التعديلات باستخدام أداة Curves. قم بتعديل قنوات اللونين الأخضر والأحمر على شكل يشبه حرف S واللون الأزرق على شكل حرف S ولكن معكوس كما هو موضح في الصورة: قم بتقليل تشبّع (saturation) الصورة لتخفيف حدّة الألوان. ستظهر ألوان هذه الصورة بعد التعديلات بشكل يتلائم مع ألوان التصميم: استعمل واحدة من فرش paint roller التي قمت بتحميلها سابقًا واستعملها لرسم خلفية لوضع بعض النصوص فوقها كما تظهر الصورة: قم بتعديل حجم وتباعد الحروف الخاصة بنص العنوان لإضفاء بعض الجمال، بعد ذلك اجعل حجم الخط للفقرة 14px: عليك الآن باستعمال نفس التأثيرات المستعملة في الشّعار (Gradient Overlay و Drop Shadow) وتطبيقها على النص الذي كتبته للتو: سنحتاج الآن إلى إضافة زر call to action لإخبار الزّوار إلى أين يمكنهم ان يتوجهوا بعد تصفحهم للصفحة الرئيسية. لفعل ذلك قم برسم مستطيل بحجم مناسب واملأه بلون أزرق متوافق مع اللون العام للموقع، ثم قم بإضافة فلتر noise خفيف لتخشين الزر قليلًا. بعد ذلك استعمل أداة المسح (Eraser tool) واختر pencil بعرض 1px وقم بمسح جزء من كل طرف من الأطراف الأربعة للزر. أنظر الصورة التالية: قم بإضافة تأثير Inner Glow للزر واستعمل لون أزرق أدكن بقليل من لون الزر نفسه. لتكن الإعدادات عبارة عن Normal blending mode وشفافية (opacity) بنسبة 100% وقم بتعديل الأحجام حتى تصبح ملائمة. قم أيضًا بإعطاء الزر إطار(stroke) بحجم 1px باستعمال لون أرزق أفتح بقليل من لون الزر: ويتبقى في الآخر إعطاء نص مُعبّر لوضعه على الزر، وتأكّد أيضًا أن جميع عناصر المنطقة البارزة (feature area) مرتّبة بشكل مناسب وأنيق: قم الآن بتعبئة منطقة المحتوى بالنصوص التي تريدها، واجعل حجم خط العنوان أكبر بقليل واجعله يتمدد على عرض الصفحة بالكامل. افصل النص المتبقي إلى عمودين؛ واحد عريض للمحتوى الرئيسي والآخر بعرض أصغر للمحتوى الجانبي (sidebar). يجب علينا أيضًا أن نميّز الروابط بلون مختلف عن باقي النص، لذلك قم بتلوين بعض الكلمات بلون أزرق واجلعها تحتوي على خط أسفلها (underline). في جزء المحتوى الجانبي (sidebar) سيكون هناك ثلاث مناطق تؤدي إلى مناطق أخرى في الموقع، بحيث تحتوي كل واحدة من هناك المناطق على صورة، عنوان وفقرة قصيرة. قم بإضافة خلفية مزخرفة وذلك باستعمال paint roller brushes وقم بعد ذلك بقص صورة خارطة ووضعها داخلها: استعمل paint roller brushes لإنشاء خلفية أخرى بلون أزرق أدكن بقليل من اللون الذي استعملته في الخطوة السابقة وستكون هذه الخلفية هي المكان الذي سيحتوي على العنوان الخاص بكل منطقة. لا تنسى قص الأجزاء المتداخلة لتتوافق مع طرف الصورة. قم بإضافة عنوان قصير فوق الخلفية التي أنشأناها في الخطوة السابقة وقم بإعطاءه نفس التأثيرات المستعملة في النص الموجود في الـfeature section: قم بوضع كل العناصر التي أنشأناها إلى الآن في مجلد واحد وبعد ذلك قم بنسخ ذلك المجلد مرتين وقم بالتعديل على عناصر كل مجلد بالشكل المناسب. أنظر الصورة: سوف نضيف الآن قسم "Upcoming events" أسفل النص الموجود في العمود الرئيسي. قم باستعمال نفس تنسيقات الخطوط الموجودة في الترويسة وباقي المحتوى الرئيسي، وبعدها قم بإنشاء جزء خاص بالتاريخ واستعمل لون رمادي مشابه للإطار(border): كل حدث سيحتوي على التاريخ، عنوان، بعض المعلومات ووصف بسيط: يمكننا الآن التخطيط لكيفية تحويل هذا التصميم إلى ملف HTML وهذا ما سنفعله في الدرس القادم بإذن الله. وبهذا نكون قد وصلنا إلى نهاية المقال، وأصبح لدينا تصميم جاهز يمكننا تحويله إلى صفحة ثابتة باستعمال لغتي HTML وCSS. ترجمة -وبتصرّف- للمقال Design a Textured Outdoors Website in Photoshop لصاحبه Iggy.
  10. هناك الكثير من الأشخاص ممن يحبون سلسة الدروس التي تبدأ بتصميم مدونة باستخدام برنامج فوتوشوب وتنتهي بتحويل ذلك التصميم إلى قالب ووردبريس كامل، وهذا ما سنقوم به في هذه السلسلة المكونة من ثلاثة دروس، بحيث سنقوم أولًا بتصميم فكرة القالب باستخدام الفوتوشوب، بعدها سنقوم بـتحويل ذلك التصميم إلى نموذج HTML5 وأخيرًا إلى قالب ووردبريس كامل. سنقوم بتسمية القالب الذي سنقوم بإنشائه بالاسم "Typo"، بحيث سيعتمد القالب بشكل كامل على مبادئ الخطوط والطباعة (typography) حتى يكون التركيز بشكل كامل على المحتوى. وبما أننا نريد للتصميم أن لا يحتوي على أي عناصر رسومية (صور مثلًا) فإننا سوف نستخدم نظام شبكي (grid) صارم لتحقيق التوازن في التصميم وربط جميع عناصره معًا. سوف نحتاج في البداية إلى نظام شبكي لوضعه في مستند الفوتوشوب الذي سنقوم بإنشائه، ولقد قمت بالفعل بإنشاء واحد مكون من 12 عمودًا (column) باستخدام موقع grid.mindplay.dk، كما أنني أنشأت نمط (pattern) على شكل خطوط لتعمل كشبكة خطوط قاعدية (baseline grid) بحجم 24px. قم بملء طبقة الخلفية (background layer) بلون رمادي فاتح وبعدها قم بإضافة Noise بقيمة أقل من 3% وذلك عن طريق الذهاب إلى: Filter > Noise > Add Noise قم بضبط الإعدادات إلى Gaussian وMonochromatic. قم بتحميل واحدة من الـtextures الموجودة هنا وضعها داخل مستند الفوتوشوب الذي نعمل عليه وقم بتحريكها إلى أعلى يسار الملف. قم بإلغاء تشبع الـtexture وتغيير نمط المزج (blending mode) إلى Darken. سوف تحتاج أيضًا إلى تعديل مستويات (levels) الصورة لتصبح ساطعة أكثر لتتناسب مع الخلفية الرمادية الفاتحة. قلنا سابقًا بأنّ هذا التصميم سوف يعتمد بشكل كلي على الـtypography بما في ذلك الشّعار. سوف نستخدم خط Droid Serif في التصميم وسنقوم لاحقًا في الدروس التالية من هذه السلسلة باستخدام خدمة Google Web Fonts. قم الآن بإضافة عناصر القائمة الرئيسية (navigation) بناءً على أعمدة النظام الشبكي والخط القاعدي (baseline)، وضع بجانب كل عنصر رقمًا (كما هو مبين في الصورة بالأسفل) وقم بتغيير لون هذه الأرقام حتى تكون أقل بروزًا من النص (أعطها لونًا أفتح/أبهت من لون عناصر القائمة نفسها). اجعل هناك مسافة قليلة بين الترويسة (header) وبين المحتوى الرئيسي للمدونة. وبما أنّ عنوان التدوينة يعدّ من أهم العناصر في أي مدونة فسوف نختار حجم خط كبير. قم باختيار أداة الكتابة وأنشئ مربع نصّي وضع بداخله نصًا عشوائيًا، واجعل حجم الخط 14pt وهو خط مناسب للمحتوى واجعل التباعد بين السطور (leading) بقيمة 24pt. يجب علينا تمييز الروابط داخل محتوى المدونة بتنسيقات مختلفة. لذلك سوف نجعلها ذات لون أزرق، مائلة (italic) وتحتها خط (underline). قم الآن بجمع العناصر التي تمثل التدوينة الأولى داخل مجلد واحد (اختر العناصر واضغط على ctrl + G من لوحة المفاتيح). قم بتكرير هذا المجلد ليصبح لدينا تدوينتين وقم بمحاذاة التدوينة الثانية أسفل الأولى واجعل بينهما مسافة مناسبة. قم بإضافة رابطين أسفل التدوينات؛ الأول "الصفحة التالية (next page)" والآخر "الصفحة السابقة (previous page)"، وقم بإعطاء هذين الرابطين نفس تنسيقات الروابط (أزرق ،مائل وتحته خط) وقم بزيادة الحجم حتى يكونا بارزين بشكل أفضل. ابدأ الآن بإضافة محتوى القائمة الجانبية (sidebar) واجعلها على نفس مستوى المحتوى الرئيسي اعتمادًا على خطوط الخط القاعدي الخاص بالنظام الشبكي، وبما أنّ ترويسات/عناوين (headers) هذه القائمة ليست مهمة كثيرًا فسوف نجعل حجم الخط الخاص بها صغيرًا. بعض الروابط في المدونة يمكن أن توضع بجانب بعضها (تكون كلمة واحدة على الأغلب)، والبعض الآخر سيكون فوق بعضه البعض (تكون جمل كاملة كعنوان لمقال على سبيل المثال، لذلك لن يكون هناك مجال لوضعها بجانب بعضها). لنقم الآن ببناء مربع البحث. قم برسم مستطيل واملأه بلون مناسب (#f7f7f7 مثلًا)، وبما أنّ مربع البحث يعد من أهم العناصر في أي موقع فسوف نقوم بإعطائه بعض التأثيرات لتمييزه عن باقي عناصر الموقع. أنقر مرتين على طبقة مربع البحث لإضافة بعض التأثيرات. قم بإضافة تأثير Inner Shadow خفيف وتأثير Color Overlay بلون رمادي فاتح وStroke بحجم 1px بلون رمادي مناسب. قم بمحاذاة النص الموجود داخل مربع البحث بالنسبة للخط القاعدي. سيؤدي هذا إلى أن يصبح الهامش أعلى وأسفل النص الموجود داخل مربع البحث غير متساوي، وبالتالي سوف نحتاج إلى قص جزء من مربع البحث حتى نصلح الأمر. بقي علينا إضافة أيقونة بحث إلى يمين مربع البحث. يمكنك رسمها يدويًا أو استخدام أيقونة جاهزة لتسهيل المهمة عليك. عندما تنظر إلى مربع البحث من دون وجود النظام الشبكي فإنّه يبدو متناسقًا ومتوازنًا. فالعناصر من مثل الأزرار أو مربعات البحث تحتاج غالبًا إلى تحجيمها من دون استعمال نظام شبكي وذلك حتى تسمح للنص الموجود بداخلها بأن يبقى على خطوط النظام الشبكي ليبدو كل شيء متوازنًا. تبقى علينا الآن أن نقوم بإضافة الـfooter، لذلك قم برسم مستطيل بسيط في نهاية الصفحة واجعل هذا المستطيل يأخذ ارتفاع سطرين من أسطر النظام الشبكي وقم بإعطائه لونًا اسودًا وقم أيضًا بتغيير نمط المزج (blending mode) إلى Overlay. أخيرًا وليس آخرًا، قم بإضافة بعض العناصر إلى الـfooter. لاحظ أنّه مع أننا لم نستخدم في هذا التصميم أي صور أو عناصر بصرية، إلّا أنّ الصفحة بقيت جميلة ومؤثرة وذلك لاستخدامنا لشبكة خطوط قاعدية (baseline grid) مناسبة مما جعل كل شيء متناسقًا. يمكنك في الصورة رؤية النتيجة النهائية بدون وجود الخطوط الشبكية وكيف أنّ كُلّ شيء في الصفحة يبدو متوازنًا ومتناسقًا مع بعضه. ترجمة -وبتصرّف- للمقال Create a Typography Based Blog Design in Photoshop لصاحبه Iggy.
  11. عمل أطر مفرغة -أو تصاميم مبدئيّة- أثناء التصميم لا يكلف شيئًا تقريبًا، ولكن يمكنه أن يحقق عائدًا ممتازًا. ورغم أن العديد من المصممين يبدؤون برسم "سكِتش" في ذهنهم، ومن ثمّ يضعونه في برنامج فوتوشوب أو حتى يبدؤون بكتابة الأكواد مباشرة، بينما يبدأ آخرون على الورق. نعم، هو الورق العادي الذي تعرفه، والذي تكتب عليه بالقلم. يبدو هذا كتقنية عمرها عشر سنوات، ولكن حتى الآن ما زال أفضل المصممين في هذا العالم يستخدمونه لصالحهم. سيوفر عليك عمل تصميم مبدئيّ الكثيرَ من الإحباط في المراحل اللاحقة من تطوير المشروع، حيث يؤكّد بأنه ليس هناك أشياء عليك التراجع عنها أو إعادة تصميمها. إذا قمت بعمل تصميم أوليّ بطريقة سليمة، فبإمكانك أن تبيت مرتاح البال بأنك لن تضطر مستقبلًا لإعادة التصميم من البداية. إن ما تعنيه الأطر المفرغة هو وضع أفكار التصميم على الورق لكلّ من صفحات الموقع. في الغالب ستتشارك كل الصفحات ببعض العناصر، ولهذا فستكون الصفحة الأولى أكثر صعوبة في التصميم، بينما ستكون بقيتها أقل صعوبة، حيث تكون قد حصلت على فكرة مبدئيّة عن النمط العام للتصميم. أبق في بالك أن هذه العناصر مهمّة لأيّ تصميم. عندما تقلّب بين الصفحات، سيكون على المستخدم أن يقدر على التعرف على الصفحة وأن يعلم أنه لم يغادر الموقع ويذهب إلى موقع آخَر. أبق دائمًا على التنقلات والأقسام المهمة (المحتوى، الشريط الجانبي، ذيل الصفحة) في نفس المكان، ولكن هذا صار شائعًا كما لو أنه دليل للمبتدئين في التصميم، لذا لننتقل إلى أمور متقدمة أكثر. الأطر المفرغة – نظرة عامةلكي تكون قادرًا على استخدام إطار مفرغ، فأنت بحاجة إلى معرفة كيف يعمل. ما يفعله الإطار المفرغ بسيط، فهو يُظهِر الشكل العام للوقع والمكونات الرئيسيّة على الورق. يمكنك أن تستخدم أشكال مختلفة كصناديق وحاويات لرسم المحتوى فيها، وتنقلات، وعناصر وظيفيّة أخرى. قد تسأل نفسك، لم نستخدم الأشكال؟ الإجابة بسيطة: لأنها تسمح لنا بأن نركّز على التصميم أكثر وان ننسى الأكواد والتوافقية بين المتصفحات والصور وما إلى ذلك. إنه تصميم بسيط ونقيّ. الصورة من Zach Hoeken. الأطر المفرغة أم تصاميم فوتوشوب؟وكبديل عن التصاميم الأوليّة للمواقع على الورق، يمكن إنشاء التصميم المرئيّ على برنامج فوتوشوب أولًا. ورغم أن لها مزايا إلى حدّ ما، فإن إنشاء الشكل العام في فوتوشوب غير عمليّ، وذلك لأنه لا يسمح لك بالتركيز على العناصر الأساسيّة للتصميم. ولهذا، إذا أردت البدء بالتصميم في فوتوشوب، فقد تبدأ أيضًا بالتفكير في الألوان والصور والخطوط. لا حاجة لهذا الأمر إذا بدأت العمل على الورق. والعمل على الورق أسرع بكثير أيضًا، ولذا لِمَ لا تقوم بها بهذه الطريقة؟ ولهذا، يمكنك أن تبدأ التصميم في فوتوشوب في مرحلة لاحقة، ولكن لا أنصح بعمل ذلك قبل أن تكون لديك فكرة واضحة عن ما ترغب بالحصول عليه من المشروع. الطريقة الوحيدة لتحقيق ذلك هي البدء على الورق. يمكنك أن تدعو الإطار المُفرَغ بأنه "سكِتش" إذا أردت ذلك. وفي الحقيقة أن الأطر المفرغة هي سكتش بسيط للموقع. توصل الأطر المفرغة بعض الأفكار للزبون، حيث يمكنه أن يقبلها أو يرفضها. إذا رفضها، فسيكون من السهل بالنسبة لك أن تأخذ ورقة أخرى وترسم عليها أفكار أخرى من البداية. الهدف الأساسيّ من الأطر المفرغة هو أن تسمح لك بالتركيز على الأشياء المهمة في الموقع، وهي: كيف تبدو كل صفحة، وأين تقع أهم العناصر فيها، وكيف تحقق التوازن الإيجابيّ الذي تريده بشكل عام. وبعد أن تكون قد حصلت على فكرة عن ما يريده الزبون، ويقبل هو التقسيم الأساسي للموقع، يمكنك حينها أن تطوّر السكتش البسيط إلى شيء أكثر تفصيلاً. قد يكون الآن الوقت المناسب لبدء التفكير في الخطوط والألوان والصور. الصورة من Denkbeelhouwer. مرحلة عمل التصاميم الأوليةمن الضروريّ بالنسبة للمصممين والزبائن أن يعملوا معًا أثناء هذه المرحلة من المشروع. وحيث أنّه ليس لدى الزبون الكثير ليقوله أثناء مرحلة كتابة الأكواد، فهذه هي المرحلة التي يمكنه فيها تقديم الكثير من المدخلات التي عليك أن تأخذها بعين الاعتبار. تذكر أنه بمجرد موافقته على التصميم، فسيعطيك وهو راض حرية أكثر في الأفكار الأخرى؛ في هذه المرحلة يثق فيك وفي خبراتك. سيكون هذا مشروعًا طويلًا وصعبًا إذا لم تحصل منه على الموافقة على الإطار المفرغ الأساسيّ. إذا كنت زبونًا فتذكر أن لا تركز كثيرًا على عدم وجود ألوان وصور وخطوط وأمور أخرى تتعلق بالنمط. إن وظيفة المصمم في هذه المرحلة هي أن يعطيك فكرة بسيطة عن ما يراه بأنه جيد لك. إذا طلبت منه أطر مفرغة مفصلة أكثر ورفضتها ثلاثة أو أربعة مرات، فسيكلفك ذلك الكثير من المال. ومن ناحية أخرى، إذا طلبت أطر مفرغة بسيطة ورفضتها، فلن تكلفك بذلك القدر، وذلك لأن رسمها والتفكير فيها أسهل. أدوات لعمل تصاميم أولية للمواقعفيما يلي قائمة بالأدوات التي اختبرتها حديثًا لأرى إلى أيّ حد يمكن للمصممين الاعتماد عليها لبناء أطر مفرغة. إذا لم يكن الورق مناسبًا لك، فهناك خيارات أخرى ممكنة (دون ترتيب معين): 1. iPlotzتسمح ك هذه الأداة بأن تصنع أطر مفرغة يمكنك أن تنقر عليها وتتنقل خلالها. يسمح لك هذا بإنشاء تجربة مشابهة للموقع الحقيقيّ. ورغم أن بإمكانك الحصول على حساب مجانيّ، إلا أنني أنصحك بالحصول على واحد من حسابات Premium إذا كنت جادًّا في أن تبدأ بعمل التصاميم الأولية للمواقع واتخاذها كمهنة من الآن. 2. Balsamiqإذا كنت تحب الرسم، فستعطيك هذه الأداة شعورًا مشابهًا لذلك، إلا أنه رقميّ هذه المرة. يمكن تضبيط وإعادة ترتيب هذه الأدوات بسهولة، والتحكم بها سهل أيضًا. النتائج نظيفة، ومن المزايا الأخرى لها هو أنّ كل شيء يمكن تكرارها في الوقت الحقيقيّ. 3. Pencil Projectيمكن استخدام هذه الأداة لعمل مخططات انسيابية وتصاميم أوليّة للواجهات بسهولة. 4. templatrرغم أنه لن يسمح لك برسم أيّ شيء، إلى أن هذه الأداة تمكنك من إنشاء تصاميم لموقعك أثناء العمل. لست بحاجة لمعرفة HTML ويمكنك تنزيل القالب في النهاية بنقرة زر واحدة. 5. Flair Builderيمكن لهذه الأداة التفاعل مع الأطر المفرغة بسرعة عالية جدًّا. هذه الأداة سهلة الاستخدام وتأتي مع لوحة من العناصر الفعالة التي ستسهل مهمة إنشاء تصاميم أوليّة. هذه الأداة تفاعليّة، وستحسن تجربتك كثيرًا. صورة من Michael Lancaster. خلاصة القولالأطر المفرغة، أو التصاميم الأوليّة للمواقع، هي عملية يعرفها الكثير من المصممين، رغم أن القليل منهم فقط من يستخدمونها. ورغم أنها تبدو بأنها تأخذ الكثير من الوقت، إلا أنها -على المدى البعيد- ستساعدك كثيرًا. إذا كنت تعرف كيف تتواصل بطريقة سليمة وأن تعمل عن قرب مع الزبون، أثناء مرحلة عمل التصاميم الأولية، فستتم بقية العمل بسلاسة أكبر مما تتوقع. أنصحك كثيرًا أن تقوم بعمل تصميم أوليّ لعملك قبل البدء في كتابة الأكواد، أو أن تُنشئ التصميم الأولي بأكمله في فوتوشوب. هذا سيجعل المهمة كلها أسهل لك، وسيوفر عليك الكثير من الإحباط طوال مدة العمل. وإلى المرة القادمة، تواصل معنا في الردود، وأخبرنا برأيك. هل تقوم بعمل تصاميم أوليّة للتصاميم التي تعمل عليها؟ وما مدى جدوى ذلك بالنسبة لك؟ وإذا لم تكن تفعل ذلك، فلماذا؟ ترجمة -وبتصرف- للمقال: Beginner's Guide to Wireframes and Tools to Create Them.
  12. سنتعلم طريقة تصميم مشغل صوتيات Audio Player باستخدام برنامج أدوبي اليستريتور، حيث سنعتمد في درسنا هذا على تقنية التصميم المسطّح (flat design). بداية سنحتاج إلى تحميل هذه الملفات: خط Latoحزمة الأيقوناتمع قليل من الصّبر والوقت (أقل من 30 دقيقة).إعدادات مساحة العمل1. نقوم بفتح ملف جديد خاص بالدّرس، نختار اسمًا للملف قد يكون Audio Player أو أي اسم آخر ثم نحدد قياسه 1280px*1280px ونتأكّد أننا اخترناه مخصص للويب ( profile: web). (عادة نختار المقاسات الكبيرة للتصميم حتى لا يتأثر عند تصغيره) 2. باستخدام أداة Rounded Rectangle Tool نرسم شكلا ونختار له المقاسات التّالية: 598px*244px*8px، ثم نحدد له اللون EFEFEF#: 3. باستخدام أداة المستطيل (M) نرسم مستطيلا نقوم بوضعه فوق الشّكل الأوّل كما في الصورة ونحدد اللون D35353 #: 4. نقوم بتحديد الشّكلين بالضّغط على CTRL+A، أوعن طريق الضّغط على الشّكلين وفي نفس الوقت نضغط CTRL+Shift: 5. بعد تحديد الشّكلين نختار الأداة (Shape Builder tool (Shift+M لجعلهما متناسقين: 6. نستطيع فعل ذلك بطريقة أخرى بالضّغط على الجزء الذي نريد حذفه، نلاحظ أنّ ذلك الجزء قد أصبح مستقلا عن الشّكل، فنقوم مباشرة بحذفه. 7. نُعيد تطبيق الخطوتين 4 و6 لتصميم مؤشّر المسار الخاص بمشغل الموسيقى فنتحصل على الشكل التالي: 8. نقوم بإضافة بعض اللّمسات على التّصميم، كإضافة عنوان الملف الموسيقي، مدّته الزمنيّة، والملف التّالي. نختار نوع الخط: Lato Regular، مقاسه: font، ولونه: 7C7C7C#: 9. نقوم بتحريك مؤشّر الحجم (للتوضيح بأن الملف الموسيقي قيد التّشغيل)، وذلك باستخدام أداة rounded rectangle ورسم مستطيل فوق الشكل السَابق، نختار له المقاس: 422px*14px*15px radius واللون: CCCCCC#. 10. الآن نضيف مستطيل آخر على المستطيل السّابق نختار له اللّون d84848 #، ثمّ نحدد مسار كلاً من المستطيل الأوّل والثاني. باستخدام أداة Shape Builder tool نقوم بحذف الجزء الزّائد من المستطيل الذي في الأعلى فنحصل على هذا الشكل التالي: 11. باستخدام أداة (Ellipse tool (L نرسم دائرة ونختار لها اللون d74948 #، ثم نقوم بإضافة أيقونة الصّوت الموجودة في ملف الأيقونات كما يظهر في الصّورة: تصميم أزرار التحكم الخاصة بالتشغيل12. نرسم مستطيلا نضعه على الخلفية الرّئيسية للمشغّل ونختار له اللّون d85656 #: 13. نحاول أن نجعل المستطيل على شكل دائري وذلك باستخدام أداة the Shape builder tool وحذف الأجزاء الزّائدة: 14. الآن، نضيف العناصر الموجودة في ملف الأيقونات: تصميم قائمة التشغيل15. نقوم بنسخ كل ما سبق لنا تصميمه: 16. نقوم بتكبير الخلفيّة الرّئيسية بمقدار 460px، أو أي قيمة تريدها: 17. نقوم بتمديد خلفيّة العناصر بحيث تصبح أكبر من الخلفيّة الأساسية، ثم نحذف الأجزاء الزّائدة باستخدام أداة the Shape Builder. الهدف من ذلك هو جعل الجزء الذي يحتوي على أزرار التحكّم لا يظهر بشكل دائري في الأطراف. 18. نضع للقائمة عُنواناً: 19. باستخدام أداة the rectangular grid tool، نرسم شبكة تحتوي علي 6 تقسيمات أفقية فقط (نضع 0 أمام التقسيمات العموديّة): 20. نقوم بتوسيع الشّبكة لتتناسب مع خلفيّة مشغل الصوتيات، ونغير قيمة opacity إلى حوالي 20%، وباستخدام أداة the scissors tool نحذف الخط الأفقي: 21. لاستخدام أداة (scissors tool (C، يكفي أن نحدّد جزء من المسارالذي نريد حذفه ونضغط مرتين، ثم نستخدم زر الحذف delete من لوحة المفاتيح أو زر backspace: 22. الآن الشبكة جاهزة، نقوم بوضع الأدوات الموجودة في ملف الأيقونات والذي سبق وقمنا بتحميله ثم نضع عنوانا للقائمة: 23. لتصميم شريط التّمرير، نقوم برسم مستطيل باستخدام الأداة rounded rectangle tool، نحدّد له اللون cccccc# أما لمؤشّر التوقف فنختاراللّون 262626# مع استخدام أداة the Shape Builder tool: 24. أنهينا تصميم واجهة Audio Player، بإمكانك أن تحفظ العمل على شكل: AI, PSD, JPG, PDF أو SVG. ترجمة -وبتصرّف- للدرس How to Create a Music Player UI Using Adobe Illustrator لصاحبه James Richman.
  13. رؤوس الجداول الثابتة ليست بالأمر الجديد في مواقع الويب. على عكس الورق، حيث يستطيع القارئ نقل نظره بسرعة إلى أعلى الشاشة ليعرف في أي عمود هو، لكن أبعاد الشاشة تجعل من قراءة الجداول الطويلة أمر صعبا. رؤوس الجداول الثابتة، كما يشير اسمها، تبقى ثابتة في أعلى الجدول حتى وإن نزلنا أكثر في الجدول. يساعد الأمر في إبقاء أسماء الأعمدة دوما في متناول اليد، حتى لا يجبر المستخدم على الرجوع إلى أعلى الجدول كل مرة من أجل النظرة ثم الرجوع مجددا. يوجد العديد من سكربتات وإضافات jQuery التي تعمل بطريقة فعالة وخالية من الأخطاء، فهم ليسوا الحل المثالي لجميع المشاكل الممكنة، ففي بعض الحالات، على الجداول أن تتبع قواعد هيكلة لم تحسب لها الإضافات حساب، كالجداول التي تسمح بإظهار مؤشر التحرك (scroll bar) عندما لا تكفي المساحة لإظاهر الجدول. هذا المقال لن يكون الحل المثالي لجميع المواقف، ولكنه سيكون حلا لأغلب المشاكل الشائعة. حل باستخدام CSS فحسب عبر position: sticky؟تملك CSS حلا مناسبا لهذه المشكلة وهو عبر استخدام postion: sticky. لكن للأسف، الحل غير مدعوم في chrome رغم أنه كان مدعوما سابقا، إلا أنّ فريق التطوير قام بإلغاء الخاصية تماما منه إلى أجل غير معلوم. ولأننا لا نستطيع التضحية بكل مستخدمي متصفح chrome فعلينا إيجاد حل بديل للمشكلة. حل عبر استخدام jQueryحل jQuery هو بسيط جدا، لكن قبل أن نبدأ باستخدام، علينا أن نلقي نظرة على كيف يكون جدول ما صحيحا من حيث الهيكلة: <table> <thead> <tr> <th></th> <!-- more columns are possible --> </tr> </thead> <tbody> <tr> <td></td> <!-- more columns are possible --> </tr> <!-- more rows are possible --> </tbody> <tfoot><!-- هذا الجزء اختياري --> <tr> <td></td> </tr> </tfoot> </table>ما الذي نحاول تحقيقه؟سنحاول جعل السكربت يدعم أغلب المشاكل الشائعة والتي هي: الاستخدام الأساسي: رأس الجدول يكون ثابتا.رؤوس الجداول الأفقية والعمودية.الجداول العريضة:العمود الأفقي: إذا كان هنالك العديد من الأعمدة التي لا يمكن إظهارها في عرض الصفحة، فسنستخدم عمودا جانبيا ثابتا.الصف العمودي: وهو الاستخدام الأساسي، أن يكون الرأس العلوي ثابتا عند النزول بالجدول.كلا العمودين: حيث نثبت كل من العمود والصف.CSS من أجل البدءرغم أننا سنستخدم حلاّ عبر جافاسكربت، فإن CSS ضرورية من أجل تنفيذ الأمر: .sticky-wrap { overflow-x: auto; position: relative; margin-bottom: 1.5em; width: 100%; } .sticky-wrap .sticky-thead, .sticky-wrap .sticky-col, .sticky-wrap .sticky-intersect { opacity: 0; position: absolute; top: 0; left: 0; transition: all .125s ease-in-out; z-index: 50; width: auto; /* Prevent table from stretching to full size */ } .sticky-wrap .sticky-thead { box-shadow: 0 0.25em 0.1em -0.1em rgba(0,0,0,.125); z-index: 100; width: 100%; /* Force stretch */ } .sticky-wrap .sticky-intersect { opacity: 1; z-index: 150; } .sticky-wrap .sticky-intersect th { background-color: #666; color: #eee; } .sticky-wrap td, .sticky-wrap th { box-sizing: border-box; }ملاحظة: من المهم جدا نقل كل CSS الخاصة بوسم <table> إلى sticky-wrap. هذا حتى يتاح لنا التحكم بها مباشرة عبر jQuery. لنقل أنك تملك CSS التالي: table { margin: 0 auto 1.5em; width: 75%; }كل ما عليك فعله ببساطة هو نقلها إلى sticky-wrap. : .sticky-wrap { overflow-x: auto; /* Allows wide tables to overflow its containing parent */ position: relative; margin: 0 auto 1.5em; width: 75%; }استخدام جافاسكربتسوف نقوم بتنفيذ دالتنا على كل جدول موجود في الصفحة، الأهم من هذا سنتفقد إن كان الجدول يملك <thead> وإن كان هذا الأخير يحتوي على الأقل على <th> واحد. إن لم تتحق الشروط، فستتجاهل دالتنا هذا الجدول. $(function () { // هنا نقوم باختيار جميع الجداول في الصفحة // لكنك حر بتحديد الجداول التي تريدها $('table').each(function () { if($(this).find('thead').length > 0 && $(this).find('th').length > 0) { // بقية السكربت تكون هنا } }); });الخطوة 1: نسخ عنصر <thead>// تحديد المتغيرات وبعض الاختصارات var $t = $(this), $w = $(window), $thead = $(this).find('thead').clone(), $col = $(this).find('thead, tbody').clone();الخطوة 2: تغليف الجدول ونسخهمن أجل دعم الحالات التي يكون فيها الجدول أعرض من ماهو مسموح (أي عندما يكون عندما عدد كبير من الأعمدة، أو أعمدة طويلة، فنحوي الجدول في <div> حتى نسمح لك بأن يكون scrollable على المحور الأفقي: // احتواء الجدول $t .addClass('sticky-enabled') .css({ margin: 0, width: '100%'; }) .wrap('<div class="sticky-wrap" />'); // تفقد إن كنا قد حددنا بأن يكون الجدول قابلا للتمرير (scroll) على المحور الأفقي if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y'); // صنع رأس جدول جديد بصنف .stiky-head $t.after('<table class="sticky-head" />') // إذا كان <tbody> يحتوي على <th> فنقوم بصنع عمود جديدة ليكون الخانة أعلى الجدول if($t.find('tbody th').length > 0) { $t.after('<table class="sticky-col" /><table class="sticky-intersect" />'); } // اختصارات var $stickyHead = $(this).siblings('.sticky-thead'), $stickyCol = $(this).siblings('.sticky-col'), $stickyInsct = $(this).siblings('.sticky-intersect'), $stickyWrap = $(this).parent('.sticky-wrap');الخطوة 3: وضع محتوى الجداول المنسوخةما سنقوم به الآن هو أخذ المحتوى المنسوخ من الجدول الأصلي ووضعه في الجداول الجديدة التي ستكون ملتصقة: رأس الجدول الجديد سيستلم كامل المحتوى من عنصر <thead> المنسوخ.الأعمدة الملتصقة ستستلم المحتوى من أول عنصر <th> من <thead> وكل عناصر <th> المتبقية من <tbody>.اندماج العمود مع الصف (أيّ الخانة المشتركة بين العمود والصف) ستأخذ محتوى من خلال أعلى خانة على يمين الجدول (بافتراض أننا نتعامل مع الصفحة على أساس RTL).// StickyHead يحصل على المحتوى من <thead> $stickyHead.append($thead); $stickyCol .append($col) .find('thead th:gt(0)').remove() .end() .find('tbody td').remove(); // StickyIntersect يحصل على المحتوى من <th> في <thead> $stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');الخطوة 4: الدوالهنا يأتي أهم جزء من السكربت الخاص بنا، سنحدد أيّ دوال يجب أن تنفذ من أجل أن يعمل السكربت بشكل صحيح: دالة من أجل تحديد عرض عناصر <th> في رأس الجدول المنسوخ، بما أننا نسخنا عنصر <thead> فحسب، فعرض رأس الصفحة المنسوخ الكلي لن يكون عرض رأس الصفحة الفعلي، لأن عرض <tbody> لم يتم إضافته حيث لا نعلم هل سيؤثر على رأس الصفحة أو لا.دالة من أجل تحديد مكان رأس الصفحة الثابت حتى نقوم بتحديث بُعد رأس الصفحة المنسوخ الأفقي، الذي قمنا بتحديد position: absolute عندما نبدأ بتمرير شريط التقدم داخل الجدول.دالة من أجل تحديد مكان العمود الجانبي الثابت ولها نفس حالة تثبيت رأس الصفحة.دالة من أجل حساب المساحة المتبقية وسنقوم بشرح هذه الدالة لاحقا بشكل أعمق. // Function 1: setWidths() // Purpose: To set width of individually cloned element var setWidths = function () { $t .find('thead th').each(function (i) { $stickyHead.find('th').eq(i).width($(this).width()); }) .end() .find('tr').each(function (i) { $stickyCol.find('tr').eq(i).height($(this).height()); }); // Set width of sticky table head $stickyHead.width($t.width()); // Set width of sticky table col $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width()) }, // Function 2: repositionStickyHead() // Purpose: To position the cloned sticky header (always present) appropriately repositionStickyHead = function () { // Return value of calculated allowance var allowance = calcAllowance(); // Check if wrapper parent is overflowing along the y-axis if($t.height() > $stickyWrap.height()) { // If it is overflowing // Position sticky header based on wrapper's scrollTop() if($stickyWrap.scrollTop() > 0) { // When top of wrapping parent is out of view $stickyHead.add($stickyInsct).css({ opacity: 1, top: $stickyWrap.scrollTop() }); } else { // When top of wrapping parent is in view $stickyHead.add($stickyInsct).css({ opacity: 0, top: 0 }); } } else { // If it is not overflowing (basic layout) // Position sticky header based on viewport scrollTop() if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) { // When top of viewport is within the table, and we set an allowance later // Action: Show sticky header and intersect, and set top to the right value $stickyHead.add($sticktInsct).css({ opacity: 1, top: $w.scrollTop() - $t.offset().top }); } else { // When top of viewport is above or below table // Action: Hide sticky header and intersect $sticky.add($stickInsct).css({ opacity: 0, top: 0 }); } } }, // Function 3: repositionStickyCol() // Purpose: To position the cloned sticky column (if present) appropriately repositionStickyCol = function () { if($stickyWrap.scrollLeft() > 0) { // When left of wrapping parent is out of view // Show sticky column and intersect $stickyCol.add($stickyInsct).css({ opacity: 1, left: $stickyWrap.scrollLeft() }); } else { // When left of wrapping parent is in view // Hide sticky column but not the intersect // Reset left position $stickyCol .css({ opacity: 0 }) .add($stickyInsct).css({ left: 0 }); } }, // Function 4: calcAllowance() // Purpose: Return value of calculated allowance calcAllowance = function () { var a = 0; // Get sum of height of last three rows $t.find('tbody tr:lt(3)').each(function () { a += $(this).height(); }); // Set fail safe limit (last three row might be too tall) // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value if(a > $w.height()*0.25) { a = $w.height()*0.25; } // Add height of sticky header itself a += $sticky.height(); return a; }; }والآن سنقوم بشرح ما قمنا به في الدالة الرابعة، نحن لا نريد من رأس الجدول أن يلحقنا إلى أسفل الجدول، فالأمر غير ضروري وقد يغطي لنا آخر سطر من الجدول، لذا من الضروري إبقاء مساحة فارغة في الأسفل. حسب ما جربت، فقد اكتشفت أننا لا نحتاج لرأس الجدول عندما نصل لأخر 3 سطور من الجدول لأن تركيزنا انتقل على المحتوى الآن. $t.find('tbody tr:lt(4)').each(function () { allowance += $(this).height(); });الخطوة 5: ربط كل شيءوالآن قد انتهينا من تعريف كل الدوال اللازمة، كل ما تبقى هو ربط المتفقدات أو (Event handlers) مع عنصر(window)$. عندما يجهز الـDOM نقوم بالحسابات الأولية للعرض.عندما تحمل كامل المعلومات نقوم بحساب الأبعاد مرة أخرى، هذه الخطوة مهمة لأن جدولك قد يحتوي على أشياء تحمل بعد الـ DOM مثل الصور وخطوط الويب.عندما يتم التمرير في الحاوي الرئيسي ولكن هذا سيحدث في حالة كان المحتوى أكبر من عرض الحاوي، حينها نريد إعادة تغيير مكان العمود الرئيسي.عندما يتم تصغير نافذة المتصفح نريد إعادة حساب العرض.عندم يتم النزول في المتصفح نريد أن نغير مكان رأس الجدول.يمكن تلخيص ما قلناه للتو في الكود التالي. يجدر الذكر أن أحداث التصغير والتمرير يتم التحكم بهما باستخدام إضافة throttle+debounce. // #1: DOMعندما يجهز الـ setWidths(); // #2: نراقب الحاوي في حال حدوث تمرير فيه $t.parent('.sticky-wrap').scroll($.throttle(250, function() { repositionStickyHead(); repositionStickyCol(); })); // الآن نربط ما قمنا بعنصر $(window) $w // #3: عندما يتم تحميل كامل المحتويات .load(setWidths) // #4: عندما يتم تصغير النافذة // قمنا باستخدام throttle هنا حتى لا يتم إطلاق الحدث أكثر من مرة (في الوضع الافتراضي يتم إطلاق الحدث من أجل كل جزء يتم تصغيره، هنا ننتظر حتى ينتهي التصغير كاملا ثم نطلق) .resize($.throttle(250, function () { setWidths(); repositionStickyHead(); repositionStickyCol(); }) // #5: عندما يتم النزول في النافذة // استخدمنا throttle حتى لا يتم إطلاق الدالة كثيرا .scroll($.throttle(250, repositionStickyHead);وانتيهنا، كان هذا كل شيء! النقاشنحن نعرف أن لاشيء كامل، لذا سنناقش الطرق الأخرى التي تملك محاسن على هذه الطريقة ومساوئها ولم استخدمنا هذه الطريقة. استخدام position: fixedاستخدام هذه الطريقة قد يبدو مغريا لسبيين: لا يوجد حاجة لحسابات من أجل رأس الجدول، لأن العنصر المثبت (fixed) يقع خارج الصفحة الفعلية وسيبقى ثابتا في مكانه.نتجنب البطء في الحسابات هذا لأن العناصر الثابتة تلاحق الجدول ولا تثبت معه، لأننا نقوم بالحساب في فترات ثابتة (عبر throttle) وبالتالي سيظهر أن العنصر الثابت غير متجاوب وبالتالي غير طبيعي.لكن المشكلة في هذه الطريقة هي أننا نزيل العنصر من رونق الصفحة، ففي حالة تجاوز عرض الجدول العرض المسموح وأصبح من الضروري إضافة scroll فإن رأس لن يلحق المحتوى على المحور الأفقي لأنه ثابت في الصفحة. وهذا سبب كبير لا يسمح لنا باستخدام أغلب إضافات jQuery التي تقدم هذه الخواص. وكتبت هذه الدورة من أجل إصلاح هذا الأمر بالتحديد. استخدام position: stickyالخاصية الجديدة مناسبة للأمر، في الواقع لقد بنيت من أجل هذا الأمر في الحسبان، المشكلة فيها أنها غير مدعومة من متصفح chrome (سبق وكانت مدعومة ولكن أزيل الدعم كليا) وبذلك تفقد كل الزوار من هذا المتصفح. مثال حي:See the Pen avovoo by Hsoub Academy (@HsoubAcademy) on CodePen. ترجمة -وبتصرف- للمقال: Sticky Table Headers & Columns لصاحبه Terry Mun.