اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'svg'.

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

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

نوع المحتوى


التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

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

التصنيفات

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

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

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

  1. يمكن أن تقوم SVG بأكثر بكثير من مجرد عرض الصور الثابتة، إذ تعد إمكانياتها الحركيّة واحدة من أكثر مميزاتها قوةً، مما يعطيها مزايا فريدة عن صيغ الصور الأخرى، وهي أحد الأسباب العديدة التي تجعل SVG أفضل من الصور النقطية، بما فيها GIF. ولكن هذا، بالطبع، ينطبق فقط على الصور التي تعد مرشحةً جيدةً لتكون SVG، مثل: table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } الشعارات، الصور غير المعقدة، المعتمدة على الأشعة، أدوات التحكم بواجهة المستخدم، الرسوم البيانية، والأيقونات. بالطبع، إذا كان لديك صورة أكثر ملاءمةً للصيغة النقطية – مثل الصور الفوتوغرافية أو الرسومات المعقدة جدًا المعتمدة على الأشعة (والتي من الطبيعي أن تكون كبيرة الحجم جدًا مثل صور SVG)، فعليك استخدام صيغة الصور النقطية بدلاً منها. لا يجب أن تكون الصورة مرشّحاً جيداً لـ SVG فقط، ولكن يجب أن يكون SVG مرشّحاً جيداً للصورة. فمثلًا، إذا كان حجم الصورة صغير جداً كصور PNG، يجب استخدام PNG، وتقديم إصدارات/معاملات دقة مختلفة للصورة باستخدام srcset أو <picture>، بالاعتماد على ما تعمل عليه وتحاول تحقيقه. عمومًا، الصور المذكورة أعلاه هي عادةً مرشّحات مثالية لـ SVG. وإذا كنت ستحرّك أيًا منها، فإنّ الطريقة المعقولة للقيام بذلك هي إنشاء صورك المتحركة عن طريق تحريك شيفرة SVG. ومع ذلك، في الأسبوع الماضي، ظهر رابطًا منبثقًا في يوميات حسابي على التويتر يشير إلى مجموعة من الأيقونات المتحركة كـ GIF. إنّ أول ما مرّ في ذهني عندما رأيتهم بأنّهم كانوا مرشحين مثاليين لـ SVG ويجب أن يتم إنشاؤهم كصور SVG، وليس صور GIF. في العديد من الحالات يمكنك استبدال صور GIF بصور SVG بالفعل، تمامًا كما يمكن أن تستبدلها بتنسيقات الصور النقطية الأخرى لمرشّحين مثل تلك المذكورة أعلاه. إنّ القدرة على تحريك صور SVG هي ما يمنحها هذه الميزة والقدرة. وهذا ينطبق على عناصر أكثر من الأيقونات المتحركة. لذا، لهذا السبب أعتقد أنّه يجب عليك استخدام SVG بدلًا من صور GIF كلما استطعت. جودة الصورة الميزة الأولى لاستخدام SVG بدلًا من GIF - أو أية صيغة صورة لهذه المسألة - هي - كما هو متوقع - ميزة SVG الأولى: استقلالية الدقة. ستبدو صورة SVG فائقة الوضوح عند أي دقة للشاشة، بغض النظر عن حجمها. في حين أن صور GIF - صيغة الصورة النقطية - لا تظهر كذلك. حاول تكبير الصفحة التي تحتوي على صورة GIF وشاهد كيف ستبدو صورة الـ GIF منقطة ومحتوياتها غير واضحة. مثلّا، يبدو تسجيل GIF التالي لحركة صورة SVG جيدًا بهذا الحجم الصغير: يؤدي تكبير الصفحة عدّة مرات إلى جعل الصورة غيرَ واضحةٍ وتصبح حواف ومنحنيات العناصر الداخلية مسننةً، كما تشاهد في الصورة أدناه: بينما إذا قمت بالتحقق من عرض SVG التجريبي وتكبير الصفحة، فإن محتوى SVG سيبقى واضحًا وصافيًا بغض النظر عن مقدار التكبير. لتوفر صورًا واضحةً للشاشات عالية الدقة عند استخدام صيغة صورة نقطية مثل GIF، تحتاج إلى استخدام <picture> أو srcset وتشغيل الصور بسياقات مختلفة. بالطبع، كلما زادت دقة الصورة، زاد حجم الملف. مع صور GIF، سيصل حجم الملف لحجمٍ كبير بشكلٍ هائل. لكننا سنصل إلى ذلك في غضون دقيقة، كذلك، فإنّ استخدام صور GIF عالي الدقة وعرضها بحجمٍ أصغر للهواتف المحمولة يعد أمرًا سيئًا بالنسبة للأداء، لذا لا تفعل ذلك. عندما تنشئ أيقونات أو صور GIF متحركة، أبعادها ثابتةٌ. غيّر الأبعاد أو كبّر وصغّر الصفحة، وستحصل على صورة غير واضحة. أمّا مع SVG، ستتخلص من مشكلة الحجم، وستحصل على وضوحٍ دائم. يمكنك إنشاء صور SVG صغيرة وتغيير أبعادها وفق احتياجاتك دون التضحية بوضوح الصورة. نتيجة صورة GIF صورة SVG متحركة GIF مثل تنسيقات الصور الأخرى تمامًا، غير مستقلة الدقة، ولذا ستبدو غير واضحة عند تغيير حجمها أو عرضها بدقة أعلى صورة SVG قابلة لتغيير الحجم ومستقلة الدقة، وستبدو واضحةً بأي دقة شاشة الألوان والشفافية ربما يكون السبب الأول لتبتعد عن التعامل مع صور GIF هو الطريقة التي يتعامل بها مع الشفافية، خاصةً عندما يتم عرض الصورة على خلفية غير الخلفية البيضاء. هذه مشكلة تظهر غالبًا عند استخدام أيقونات GIF (سواءً كانت متحركة أم لا)، عندما يتم إنشاء الأيقونات عادةً بخلفيات شفافة. مثلًا، فكر مليّا بالدائرة التالية المحاطة بحدّ، أُنشئت كصورة SVG (يسار) وGIF بخلفية شفافة (يمين). المشكلة واضحة بمجرد النظر إلى الصورتين: تحتوي دائرة GIF على حواف رمادية حول حدّها. إذا كنت لا تعاينها في المتصفح، فقد لا يكون التأثير مرئيًا لك لأنّه من الممكن ألا يتم تطبيق أنماط الشكل. فيما يلي لقطة توضح المشكلة (على اليمين): يحدث هذا لأن الشفافية في صور GIF ثنائية. هذا يعني أن كل بكسل إما يعمل أو لا يعمل؛ البكسل سيظهر إما شفافًا أو ممتلئًا بشكلٍ كامل. وهذا بدوره يعني أنّ الانتقال بين اللون الأمامي ولون الخلفية ليس سلسًا، والتشوهات الناتجة تظهر بسبب تردد العينات غير المناسب، والمعروفة باسم التعرج. عندما لا يكون الخط مستقيمًا تمامًا، فإنّه يتسبب بأن تكون بعض البكسلات (حول الحواف) شفافة جزئيًا وممتلئة جزئيًا ، لذلك يحتاج البرنامج إلى معرفة اللون الذي يجب استخدامه لهذه البكسلات. تأثير الهالة "ناتج عن كل البكسلات التي كانت ممتلئة أكثر من 50٪ امتلاءً كاملاً وتحمل لون الخلفية بدلاً من اللون الذي تم تنقيطه" كريس ليلي. لذلك يكون هذا التأثير عادةً ناتجًا عن تلوث البكسل من لون الخلفية التي تتكون الصورة على أساسه مقارنةً بما هي عليه عند إنشائها/حفظها في محرر الرسومات. عادةً ما يحاط التعرج بمكافح تعرج، ولكن هذا ليس بالأمر البسيط عندما تكون الشفافية ثنائية: حلّ هذه المشكلة هو الشفافية المتغيرة، والمعروفة باسم قناة ألفا، والتي تسمح بدرجات متفاوتة من الشفافية وبالتالي انتقالًا أكثرَ سلاسةٍ بين اللون الأمامي ولون الخلفية، وهذا غير متوفر في GIF؛ وبالتالي، هذا يسبب مشكلة تأثير الهالة. تظهر الصور ذات تأثير الهالة أفضل عادةً عند استخدامها مع خلفيات بيضاء؛ أي لون خلفية آخر عالي التباين سيجعلها تبدو مشوهةً. لست متأكدةً تمامًا مما إذا كانت هناك طريقة لحل هذه المشكلة، لكنني لم أجد بعد صورة GIF ذات خلفية شفافة وحواف منحنية لم تكن بها هذه المشكلة. لقد رأيت الأشكال المستطيلة تعاني منها أيضًا. إذا كنت ترغب في استخدام صورتك/أيقونتك على خلفية غير بيضاء - مثلًا، على خلفية تذييل داكنة، قد يكون هذا لوحده يبعدك عن التعامل مع GIF، ولكن هناك أسباب أخرى تجعل استخدام SVG أفضل من GIF أيضًا، والتي سنغطيها في الأقسام التالية. ملاحظة: إذا كنت تقرأ هذه المقالة باستخدام المتصفح ولكنك لا ترى الحواف في الصورة الأولى على شاشة أصغر، فحاول تكبير الصفحة لترى التأثير. لماذا من الممكن ألا تكون قادرًا على رؤية الحواف على أحجام أصغر؟ الإجابة هي: ينعّم المتصفح الحواف كجزءٍ من عملية تغيير حجم الصورة. هل هذا يعني أنّه يمكنك استخدام هذا للتخلص من الحواف والاستمرار باستخدام GIF؟ نعم تستطيع. ولكن للقيام بذلك، يجب عليك استخدام صور GIF بحجم أكبر بكثير من الحجم الذي تريد أن تكون الصورة به، ثم تغيير حجمها. هذا يعني أيضًا أنك ستعرض صورًا للمستخدمين أكبر بكثير مما يحتاجون إليه، وبالتالي استهلاك المزيد من النطاق الترددي على الهاتف المحمول، بالإضافة إلى الإضرار بالحجم العام للصفحة وأدائها. رجاءً لا تفعل ذلك. نتيجة صورة GIF صورة SVG متحركة صور GIF قادرة على الشفافية الثنائية فقط. يسبب هذا التشوهات، المعروفة باسم تأثير الهالة التي تظهر كلما تمّ استخدام الصورة أو الأيقونة مع خلفية غير بيضاء كلما كان تباين لون الخلفية مع الصورة أعلى، كان تأثير الهالة أكثر وضوحًا مما يجعل الأيقونات غير قابلة للاستخدام عمليًا. تأتي صور SVG مع قناة ألفا ولا تعاني من أيّة مشاكل عند استخدامها مع ألوان خلفية مختلفة. تقنيات الصور المتحركة وأداؤها يمكنك تحريك صور SVG باستخدام CSS أو جافاسكربت أو SMIL، وتمنحك كلٌّ منها مستوىً مختلفًا من التحكم يمكنك الاستفادة منه لإنشاء جميع أنواع الصور المتحركة على عناصر SVG. لا توجد "تقنيات" لتحريك صور GIF. يتم تحريكها من خلال عرض سلسلة من الصور - صورة لكل إطار - بشكلٍ تسلسلي، بأسلوبٍ ثابتٍ وسرعةٍ ثابتةٍ. تعلم أنّ هذه الطريقة التي تعمل بها صور GIF فقط. ومن المؤكد أنّه يمكنك الإبداع مع أيقوناتك قبل تحويلها إلى صور GIF ثم "تسجيل" الحركات وتحويلها إلى GIF، ولكن ما مدى جودة مظهرها؟ وما مدى السيطرة على وقت الحركة التي ستحصل عليها بعد ذلك؟ لا شيء. لن تبدو الحركة سلسةً ما لم تتأكد من أن لديك 60 إطارًا على الأقل - أي 60 صورة - في الثانية لإنشاء صورتك الـ GIF. بينما مع SVG، فإنّ الحصول على صورٍ متحركةٍ سلسةٍ أسهل وأبسط بكثير من خلال الاستفادة من تحسينات المتصفح. حجم صور GIF أكبر من حجم صور PNG أو JPEG، وكلما طالت مدة حركة صورتك، زاد حجمها. ماذا لو أردت الآن تشغيل صورتك المتحركة لمدة 5 إلى 6 دقائق على الأقل؟ ماذا لو أردت تشغيلها لفترة أطول؟ ستحصل على الصورة. لنلقِ نظرةً أكثر تحديدًا على مثالٍ بسيط. يوجد أدناه صورتان: صورة SVG متحركة على اليسار وصورة GIF متحركة على اليمين. يتغير لون المستطيل في كلتا الصورتين بفترة ست ثوانٍ. يوجد العديد من الأشياء لملاحظتها هنا: تبدو صور GIF المتحركة سلسةً، لكن إذا ألقيت نظرةً قريبةً ستلاحظ أنّ مستطيل SVG يمر بمجموعة أكبر من الألوان عندما ينتقل من اللون الأولي إلى اللون النهائي. عدد الألوان التي يمر بها GIF محدودًا بعدد الإطارات. في الصورة أعلاه، تمر صورة الـ GIF بـ 60 إطارًا، أي 60 لونًا، بينما يمر SVG عبر الطيف بأكمله بين ظل اللون الوردي المستخدم واللون الأخضر النهائي. بالنسبة لتكرار الصور المتحركة مثل هذه، من الأفضل عمومًا تجنب قفزة اللون الظاهرة في الصورة المتحركة أعلاه، وإنشاء الصورة المتحركة بحيث تنعكس ما إن تصل إلى اللون الأخضر؛ بهذه الطريقة، ستنتقل بسلاسة إلى اللون الوردي ثم تبدأ الجولة الثانية من الصورة المتحركة من هناك أيضًا، مع تجنب قفزة الألوان القبيحة. مع CSS، يمكنك عكس حركة الصورة باستخدام قيمة اتجاه الحركة alternate. ولكن مع GIF، ستحتاج إلى العمل على عدد إطاراتك وربما ينتهي بك الأمر إلى مضاعفتهم لتحقيق ذلك؛ سيؤدي هذا بالطبع إلى زيادة حجم الصورة أيضًا. أحجام الصورتين الظاهرتين في الأعلى: حجم صورة GIF هو 21.23 كيلوبايت حجم صورة SVG هو 0.355 كيلوبايت هذا ليس فرقًا بسيطًا. ولكننا نعلم جميعًا أنه يمكننا تحسين صورنا. لذلك دعونا نفعل ذلك. يؤدي تحسين SVG باستخدام واجهة المستخدم الرسومية SVGO بالسحب والإفلات إلى تقليل حجم ملف الـ SVG إلى 0.249 كيلوبايت. لتحسين صورة الـ GIF، يمكنك استخدام واحدة من العديد من أدوات تحسين GIF عبر الإنترنت. لقد استخدمت ezgif.com لتحسين الصورة أعلاه. (توجد أدوات أخرى أيضًا؛ مثل gifsicle.) انخفض حجم الملف إلى 19.91 كيلوبايت. هناك العديد من الخيارات التي يمكنك الاختيار من بينها عند تحسين صور GIF. قمت بتحسين الصورة أعلاه بحيث يبقى عدد الإطارات نفسه، باستخدام ضغط Lossy GIF، الذي "يمكن أن يقلل من حجم ملف GIF المتحرك بنسبة 30 ٪ - 50 ٪ بتكلفة بعض التدرج / التشويش". يمكنك أيضًا تحسينها عن طريق إزالة كل إطار ذو الرقم n؛ مما يمكن أن يقلل من حجم الملف إلى أبعد حد، ولكن على حساب حركة الصورة التي لم تعد سلسةً بعد الآن. وفي حالة الصور المتحركة مثل الحالة المدروسة الآن، فإن إزالة الإطارات سيجعل التغيير في اللون "سريعًا" وملاحظًا. تتوفر أيضًا خيارات أخرى للتحسين مثل تقليل الألوان (الذي لن يكون مناسبًا للصور المتحركة المعتمدة على الألوان هنا) وخفض الشفافية. يمكنك معرفة المزيد حول هذه الخيارات في صفحة التحسين في موقع ezgif.com. للتلخيص: إذا كنت أردت أن تكون صورك الـ GIF المتحركة سلسةً، ستحتاج إلى المزيد من الإطارات في الثانية، وسيؤدي ذلك بالتالي إلى زيادة حجم الملف كثيرًا. بينما مع SVG، من المحتمل أن تحتفظ بحجم ملف أصغر بكثير. المثال أعلاه صغيرٌ، وأنا متأكد من وجود أمثلة أفضل، ولكني أردت أن يوضح المثال البسيط الفرق بين الصيغتين. حتى إذا كنت تحرّك المستطيل أعلاه باستخدام جافاسكربت أو حتى إطار عمل جافاسكربت — نظرًا لأن الصور المتحركة SVG لا تعمل في متصفح IE، مثلًا، من المحتمل أن يكون حجم ملف إطار العمل المقترن بحجم SVG أصغر أو يساوي على الأقل حجم صورة GIF. مثلًا، باستخدام GreenSock’s TweenLite، سيكون حجم SVG مع المكتبة المدمجة أقل من 13 كيلو بايت (والذي لا يزال أقل من حجم GIF)، إذ انّ حجم TweenLite المصغر هو 12 كيلو بايت. إذا انتهى بك الأمر إلى حجمٍ مساوٍ لحجم GIF، فإن الفوائد الأخرى لـ SVG ستزيد من الحجم وستحصل على المزيد منه. توجد بعض مكتبات جافاسكربت الأخرى التي تركز على مهام حركة معينة في وقت واحد، وتأتي بأحجام ملفات صغيرة بشكلٍ ممتاز (أصغر من 5 كيلوبايت)، مثل Segment التي تستخدم لتحريك مسارات SVG لإنشاء تأثيرات رسم خطية. حجم Segment المصغر هو 2.72 كيلو بايت. هذا ليس سيئًا للغاية، أليس كذلك؟ يمكن أن يكون هناك استثناءات، لذلك يجب عليك دائمًا الاختبار. ولكن بالنظر إلى طبيعة صور GIF وكيفية عملها، فمن المحتمل أن تجد أن SVG يُعدُّ خيارًا أفضل في معظم الحالات. ملاحظة: أداء SVG ليس في أفضل حالاته اليوم، ولكن نأمل أن يتغير هذا في المستقبل. توفر متصفحات IE/MS Edge أفضل أداء لعرض SVG بين جميع المتصفحات اليوم. على الرغم من ذلك، ستظل صور SVG المتحركة تبدو أفضل من صور GIF المتحركة، خاصةً عند التعامل مع الصور ذات الحركة الطويلة، لأنّ حجم ملف GIF - بافتراض تسجيلها بمعدل 60 إطارًا في الثانية - سيكون له تأثيرًا سلبيًا على الأداء العام للصفحة. تقدم المكتبات مثل GreenSock أداءً رائعًا أيضًا. نتيجة صورة GIF صورة SVG متحركة - صور GIF أكبر حجمًا عمومًا من صور SVG. حركة الصورة الأكثر تعقيدًا والأطول مدةً، تتطلّب عدد إطارات أكبر لإنشائها ولهذا يكون حجم الملف أكبر ويؤثر سلبًا على الأداء - ما لم تعمل حركة الصورة بمعدل 60 إطارًا في الثانية، فإنّ الحركة ستصبح مسننة وغير سلسة. أيضًا زيادة عدد الإطارات في الثانية سيؤدي إلى زيادة حجم الملف خاصةً للحركات الطويلة نتيجة: سيكون هناك حل بسيط يجب القيام به. إمّا أن تكون حركة صورة GIF ناعمة وسيتأثر الأداء وحجم الملف الكلي وحجم الصفحة بشكلٍ سلبي، أو ستعاني الصورة المتحركة GIF من إطارات أقل. سيتم المخاطرة بأحد أشكال الأداء في كلا الحالتين تستفيد صور SVG من تحسينات المتصفح عند تحريك العناصر. على الرغم من أنّ أداء المتصفح على عناصر SVG لا تزال في أفضل حالاتها، إلا أنّ الصور المتحركة ستبقى تعمل بشكلٍ جيد بدون الحاجة لتقديم تنازلات في أداء الصفحة لا يزال حجم ملف SVG معقولًا جدًا، إن لم يكن صغيرًا جدًا، مقارنةً بـ GIF، حتى عندما قد نحتاج إلى مكتبات معينة للصور المتحركة لإنشاء صور متحركة عابرة للمتصفحات إصلاح وتعديل الصور المتحركة إنّه من المحزن أن تستخدم صور GIF. ستحتاج إلى استخدام محرر رسومات مثل Photoshop أو Illustrator أو After Effects، على سبيل المثال لا الحصر. وإذا كنت مثلي، فلن يكون محرر الرسومات المكان الذي تصقل فيه مهاراتك، وستشعر أكثر أنّك في مكانك الصحيح أكثر عند إجراء تعديلات في الشيفرة، وليس في برامج تحرير الرسومات. ما الذي يحدث إذا كنت ترغب في تغيير توقيت صورتك المتحركة؟ أو إذا كنت تريد تغيير وظائف التوقيت لعنصرٍ واحدٍ أو عدة عناصر داخل صورتك؟ أو إذا كنت ترغب في تغيير الاتجاه الذي يتحرك فيه عنصرٍ ما؟ ماذا لو كنت تريد تغيير التأثير بالكامل وجعل العناصر في صورتك تفعل شيئًا مختلفًا تمامًا؟ ستحتاج إلى إعادة إنشاء الصورة أو الأيقونة مرةً أخرى. يتطلب منك أي تغيير الانتقال إلى محرر الرسومات والعمل مع الإطارات وواجهة المستخدم المعتمدة على الإطار. سيكون ذلك بمثابة تعذيب للمطورين، ومهمةً مستحيلةً لأولئك الذين لا يعرفون طريقتنا بالتعامل مع هذه المحررات بشكلٍ كافٍ لإجراء هذه التغييرات. مع SVG، فإن إجراء أي نوع من التغيير على الصورة المتحركة (الصور المتحركة) لا يُعدُّ سوى بضعة أسطر من الشيفرة. نتيجة (من وجهة نظر المطور) صورة GIF صورة SVG متحركة إصلاح وتعديل الصور المتحركة GIF يتطلّب إعادة إنشاء الصورة أو اللجوء إلى واجهة المستخدم في محرر الرسومات المعتمد على الإطارات للقيام بذلك، ويعدّ هذا مشكلة للمطورين في مواجهة التصميم عادةً، يمكن أن تتغير صور SVG ويتم التحكم بها بشكلٍ صحيح داخل شيفرة SVG - أو في أي مكان تم تعريف الصور المتحركة به، باستخدام عدة سطور من الشيفرة. حجم الملف، ووقت تحميل الصفحة والأداء في القسم السابق، ركزنا على أداء الصور المتحركة نفسها. في هذا المثال، أريد إلقاء بعض الضوء على أداء الصفحة ككل وكيفية تأثرها باختيار صيغة الصورة الذي تقوم به. في الحقيقة: كلما زاد حجم الملف، زاد التأثير السلبي على وقت تحميل الصفحة والأداء. بأخذ ذلك بالحسبان، لنرى كيف يمكن أن يساعد استخدام SVG بدلاً من GIF في تحسين إجمالي وقت تحميل الصفحة من خلال النظر إلى مثالٍ أكثر واقعيةٍ وعمليةٍ. في حديثي الأول عن SVG، منذ 18 شهرًا، ذكرت كيف يمكن استخدام SVG لاستبدال صور GIF المتحركة وكيف تؤدي إلى تحسين أداء الصفحة بشكلٍ عام. في ذلك الحديث، قدمت مثالًا واقعيًا لصفحة ويب واقعية استفادت مما توفره SVG وحصلت على الفوائد: الصفحة الرئيسية لـ Sprout. تحتوي صفحة الرئيسية لـ Sprout على صورتين متحركتين تم إنشاؤهما في البداية وعرضهما بشكل صور GIF. قبل عامين، كتب Mike Fortress مقالًا في مدونة Oak، يوضح فيه كيف قاموا بإعادة إنشاء صور GIF متحركة، خاصةً مخطط GIF (انظر الصورة أدناه) كصورة SVG متحركة. يشارك Mike في مقالته بعض الأفكار المثيرة للاهتمام حول أدائهم الجديد للصفحة كنتيجةٍ للتغيير إلى SVG: إنّه بالفعل فرقٌ كبيرً. مخطط Sprout هو المرشّح المثالي لـ SVG. لا يوجد سبب لتحريكها عن طريق تحويل الصور المتحركة إلى تسجيل GIF، عندما يمكن لـ SVG أن تحقق الكثير من الفوائد. يدرك Jake Archibald قوة صور SVG المتحركة أيضًا ، ويستخدمها لإنشاء الرسوم التوضيحية التفاعلية وتحريكها لاستكمال مقالاته. مقاله كتاب الطبخ دون اتصال يعتبر مثالًا ممتازًا (وبالمناسبة مقالًا ممتازًا). هل كان بإمكانه استخدام صور GIF للقيام بذلك؟ بالتأكيد. ولكن بالنظر إلى عدد الصور التي استخدمها، كان من الممكن أن تزيد صور GIF بسهولة الحجم الكلي للصفحة إلى 2 ميغابايت أو أكثر، بحيث يكون حجم كل GIF على الأقل مئات الكيلوبايت؛ في حين أن صفحة الويب بأكملها تبلغ حاليًا 128 كيلو بايت فقط مع جميع صور SVG المضمنة داخليًا، لأنّه يمكنك إعادة استخدام العناصر في SVG، لذا فإن أيّة عناصر متكررة لن تتسبب فقط في أن الصفحة بأكملها ستستعمل برنامج gzip كثيرًا، ولكن لكل صفحة سيصبح الحجم الكلي لصور SVG أصغر. الآن هذا رائع! سأبقي حالتي حول تحميل الصفحة والأداء هنا. ولكن لا يزال من المهم الإشارة إلى أنّه يمكن أن يكون هناك استثناءات. مرةً أخرى، في معظم الحالات، من المحتمل أن تجد أن SVG أفضل من GIF، لكنك ستحتاج دائمًا إلى الاختبار على أي حال. نتيجة صورة GIF صورة SVG متحركة صور GIF أكبر حجمًا بشكلٍ عامٍ من صور SVG مع الحركات المضافة لهم. وهذا يؤثر سلبًا على حجم الصفحة الكلّي ووقت التحميل والأداء. يمكن أن تُستعمل صور SVG وأن يُعاد استخدامها، مما يجعل حجم الملف أصغر عمومًا من GIF وهذا يحسّن من وقت تحميل الصفحة والأداء دعم المتصفح ربما تكون الميزة الوحيدة المتفوقة لصور GIF على صور SVG هي دعم المتصفح. تعمل صور GIF إلى حدٍ كبير في كل مكان، في حين أن دعم SVG أقل انتشارًا. على الرغم من أن لدينا العديد من الطرق لتوفير النسخ الاحتياطية للمتصفحات غير الداعمة - ويجب ألا يعوق دعم المتصفح الحالي أي شخص عن استخدام SVG، إنّ الصور الاحتياطية، إذا تم توفيرها كـ PNG أو JPG، ستكون ثابتة وبدون حركة. بالطبع ، يمكنك دائمًا تقديم GIF كخطوة احتياطية لـ SVG، ولكن يجب مراعاة الاعتبارات والعيوب المذكورة سابقًا. نتيجة صورة GIF صورة SVG متحركة تعمل صور GIF تقريبًا في كل مكان صور SVG يدعمها عدد أقل من المتصفحات، لكنها تأتي مع طرق كثيرة لتوفير صور احتياطية للمتصفحات التي لا تدعمها مخاوف سهولة الوصول (a11y#) انقل شيئًا ما إلى صفحة، أو أيّ مكان، لهذه القضية، لقد أضفت للتو تسليةً - شيءٌ ما من المؤكد أنّه سيجذب انتباه المستخدم بمجرد أن يبدأ التحرك. هكذا يعمل الدماغ البشري ببساطة. يعدُّ هذا أيضًا أحد الأسباب التي تركز عليها لافتات الإعلانات - وهي مبنية على - تركيزٍ قوي على الصور المتحركة. وهذا هو السبب في أنّ لافتات الإعلانات المتحركة مزعجةٌ للغاية. إنها تشتت الانتباه، خاصةً عندما تحاول أداء مهمة على صفحة تتطلب اهتمامك بالكامل، مثل قراءة مقال. تخيّل الآن صفحة بها مجموعة من الأيقونات المتحركة (أو الصور) التي لن تتوقف عن الحركة بغض النظر عما تفعله. لم نعد نتحدث عن صورة أو صورتين على الصفحة الرئيسية أو داخل مقالة هنا؛ نحن نتحدث عن متحكمات وعناصر واجهة المستخدم، والأيقونات الأصغر التي من المحتمل أن تكون موجودة في أماكن متعددة على الصفحة، وعلى صفحات متعددة. ما لم يكن من المفترض أن تكون الأيقونة عبارة عن رسوم متحركة بشكلٍ غير محدود - مثلًا، إذا كانت عبارة عن دوران متحرك أثناء مرحلة انتظار غير نشطة للمستخدم، فمن المحتمل أن تسبب مشكلة، وتصبح مصدر إزعاجٍ أكثر من كونها "شيئًا جميلًا". في الواقع، يمكن أن يصبح الأمر أكثر إزعاجًا لبعض الناس، لأن الحركة المستمرة يمكن أن تجعل بعض الناس حرفيًا يشعرون بالمرض. تناقش المصممة ومستشارة صور الويب المتحركة Val Head في مقالتها "تصميم رسوم متحركة للويب أكثر أمانًا من أجل حساسية الحركة" تأثيرات الصور المتحركة المفرطة الاستخدام في الويب على الأشخاص الذين يعانون من اضطرابات الدهليزية المتسببة بصريًا (منجم التركيز): تخيّل الآن ما إذا كانت الصور المتحركة لا تنتهي … مضاعفات مزدوجة. تشرح مقالة Val المشكلة بمزيدٍ من التفصيل، حيث تجمع ردود فعل من شخصين يواجهان هذه المشاكل بالفعل ويشاركان تجربتهما مع الصور المتحركة بأمثلةٍ مختلفةٍ. أحد الحلول التي يمكن أن تساعد في تجنب هذه المشاكل هو تزويد المستخدم بالقدرة على التحكم في الصور المتحركة حتى يتمكنوا من إيقافها عندما تصبح مزعجةً. يمكنك القيام بذلك باستخدام SVG. يمكنك التحكم بشكلٍ كاملٍ في الصور المتحركة وتشغيلها مرةً واحدة أو مرتين عند تحميل الصفحة - إذا كنت تحتاج حقًا إلى تشغيلها بمجرد قيام المستخدم "بالدخول" إلى صفحتك، ثم إظهارها عند تمرير مؤشر الفأرة لمرات متتالية، باستخدام سطورٍ قليلةٍ من الـ CSS أو جافاسكربت. لا تحتاج إلى المئات أو الآلاف من أسطر CSS أو جافاسكربت لإنشاء صورةٍ متحركةٍ للأيقونة، إلا إذا كانت أيقونتك مشهدًا معقدًا بالفعل فيها الكثير من المكونات المتحركة. لكنني أعتقد أنّه في هذه الحالة، لم تعد تمثل "أيقونةً" بعد الآن، وأنّها أصبحت عبارةً عن صورةٍ عاديةٍ أكثر. يمكنك الوصول إلى أقصى قدر من التحكم في إعادة التشغيل، والسرعة لكل تشغيلٍ لاحقٍ، وأكثر من ذلك بكثير، بفرض، بالطبع، أنّك تستخدم جافاسكربت للحصول على هذا المستوى من التحكم. أو يمكنك إضافة تبديل لمنح المستخدم القدرة على إيقاف تشغيل الصور المتحركة بلا حدود. لا يمكنك فعل ذلك باستخدام GIF … إلا إذا اخترت استبدال GIF بصورة ثابتة عند إجراء تبديلٍ معينٍ. قد يجادل البعض بأنّه يمكنك عرض نسخة ثابتة من الصورة – مثل صورة PNG مثلًا، ثم توفير إصدار GIF عند تمرير مؤشر الفأرة. ولكن هذا يسبب بعض المشاكل: إذا كانت الصورَ مضمنةٌ، فستحتاج إلى استبدال هذه الصور باستخدام جافاسكربت. هذا الإجراء لا يتطلب أي جافا سكربت إذا كنت تستخدم SVG. إذا كانت الصور عبارة عن صور أمامية (مضمنة في HTML باستخدام <img>)، وتحتاج إلى استبدال هذه الصور، فسينتهي بك الأمر إلى مضاعفة كمية طلبات HTTP لكلّ صورة. وإذا كانت صور الخلفية مضمنة في صفحة الأنماط (هذا غير مستحسن)، فإنّ الصور (خاصةً صور GIF) ستزيد حجم صفحة الأنماط وبالتالي تزيد الوقت الإجمالي لحظر عرض الصفحة. إذا كنت تبدّل/ عندما تبدّل مصادر الصورة عند تمرير مؤشر الفأرة، فهناك وميض ملحوظ بين الصورة الأولى والثانية في الاتصالات البطيئة. اتصالي بطيء؛ أحيانًا اتصال 3G بطيء، ولم أتذكر بعد وقتًا تم فيه استبدال صورة بأخرى عند تمرير مؤشر الفأرة، أو تم تغيير حجم منفذ العرض، أو أي شيء آخر، ولم أشاهد هذا الوميض. يزداد هذا الموقف سوءًا عندما تكون الصورة الثانية (GIF التي تحمّل عند تمرير مؤشر الفأرة) كبيرة الحجم إلى حدٍ ما — سيكون هناك وميض، تتبعه صورةً متحركةٌ بطيئةٌ غير متقنةٍ لـ GIF أثناء تحميلها بالكامل. هذا ليس جذابًا أبدًا. لذا، نعم، يمكنك تبديل مصادر الصورة للتحكم إذا أو عندما تشتغل الصور المتحركة GIF أو متى يتم ذلك، لكنك تفقد التحكم الدقيق في GIF وتؤثر على تجربة المستخدم مع واجهة المستخدم. يمكنك أيضًا التحكم في عدد المرات التي يتم فيها تشغيل الصور المتحركة في GIF - وهو أمرٌ رائعٌ، لكن هذا يعني أن الصور المتحركة ستعمل فقط عددًا محددًا من المرات. ثم لإعادة تشغيل الصور المتحركة عند تفاعل المستخدم، ستحتاج إلى اللجوء إلى الأسلوب أعلاه مع صور متعددة. يمكن تحقيق الصور المتعددة التي تحتاج إلى إصلاح، وطلبات HTTP المتعددة، والحل العام المُستهلَك غير الأمثل بصورة SVG واحدة. ضمّن صورة SVG واحدة على الصفحة. أنشئ الصورة المتحركة بالطريقة التي تريدها/تحتاجها. (أو أنشئ الحركة قبل تضمين الصورة.) شغّل وأوقف وتحكّم بالصورة المتحركة. وأمنح المستخدم القدرة على التحكم فيها أيضًا. لا توجد طلبات HTTP إضافية لكل صورة، ولا صيانة معقدة للخط الزمني للصورة المتحركة في محرر الرسومات، ولا توجد أي مخاوف تتعلق بسهولة الوصول أو مشاكل لا يمكن تجنبها ببضعة سطور من التعليمات البرمجية. نتيجة صورة GIF صورة SVG متحركة صور GIF لا يمكن إيقافها من قبل المستخدم بدون طلب صور إضافية وطلبات HTTP إضافية. لا تتم السيطرة بشكلٍ كاملٍ حتى يتم ذلك يمكن تخصيص صور SVG المتحركة بشكلٍ كامل لذا يمكن تفعيلهم وتعطيلهم والتحكم بهم من قبل المستخدم بدون الحاجة إلى طرق مستهلَكة سهولة الوصول إلى المحتوى صورة GIF صورة SVG متحركة صور GIF سهلة الوصول مثل صور PNG وJPEG باستخدام قيمة الخاصية `alt` لوصفهم. لا يمكن تمييز المحتوى الموجود داخل الصورة أو إتاحته مباشرةً لقارئات الشاشة بما يتجاوز الوصف العام للصورة يمكن الوصول إلى صور SVG ودلالتها. يمكن أيضًا وصف المحتوى المتحرك داخل الصورة وجعله قابلًا للقراءة من قِبل قارئات الشاشة باستخدام عناصر سهولة الوصول المدمجة في SVG، كما يمكن تحسينها باستخدام أدوار ARIA وخاصيّاتها أيضًا. (يمكنك أن تقرأ [هنا](https://www.sitepoint.com/tips-accessible-svg/) كل شيء عن جعل SVG قابلة للوصول) التفاعل لا يوجد الكثير لإضافته هنا، ولكن الحقيقة أنّه يمكنك التفاعل مع العناصر الفردية داخل SVG، أثناء أو قبل أو بعد تحريك الصورة، لكن هذا غير ممكن مع GIF. لذا، إذا كنت تستخدم GIF، فستفقد القدرة على فعل أي شيء يتجاوز تشغيل الصور المتحركة أو إيقافها، وحتى هذا لم يتم تنفيذه فعلاً باستخدام الـ SVG، كما رأينا، ولكن يتم تحقيق ذلك عن طريق مبادلة GIF بالخارج ببديلٍ ثابت. حتى تغيير ألوان العناصر داخل GIF سيتطلب صورًا إضافية للقيام بذلك. هذه ميزة أخرى لاستخدام SVG بدلاً من GIF. نتيجة صورة GIF صورة SVG متحركة لا يمكن أن تكون الحركات المحددة في صور GIF تفاعلية، لا يمكنك التفاعل مع العناصر الفردية داخل عنصر GIF، ولا يمكنك إنشاء روابط خارج العناصر الفردية أيضًا. محتوى SVG تفاعلي بالكامل. يمكنك إنشاء التفاعلات مثل تمرير ماوس الفأرة والضغط (والمزيد) التي تستجيب لها العناصر الفردية داخل صورة SVG. استجابة وتكيّف الصور المتحركة إنّ القدرة على تحريك صورة SVG مباشرةً من الشيفرة، بالإضافة إلى معالجة العديد من خاصياتها، تعطي وتضيف ميزةً أخرى على الصور المتحركة المعتمدة على GIF: القدرة على إنشاء صور متحركة جيدة الأداء، سريعة الاستجابة وقابلة للتكيّف، دون إضافة أي طلبات HTTP إضافية باستخدام بضعة أسطر من الشيفرة وبأحجام ملفات أصغر. كتبت سارة دراسنر مقالةً في مجلة Smashing Magazine تُظهر طرقًا مختلفة لتحريك SVG sprites. تتمثل إحدى هذه الطرق في وجود "مشاهد" متعددة داخل الـ SVG، وتحريكها باستخدام CSS، ثم تغيير "عرض" الـ SVG - عن طريق تغيير قيمة خاصية الـ viewBox - لإظهار مشهدٍ واحدٍ في وقتٍ واحدٍ، اعتمادًا على حجم منفذ العرض الحالي ومساحة الشاشة المتاحة. إذا كنت ترغب في إنشاء نفس الحركات باستخدام صور GIF، فستفقد إمكانيات التحكم في الصور المتحركة، كما ستحتاج إلى صور متعددة ربما تكون أكبر (في حجم الملف) من صورة الـ SVG الواحدة. ولكن إذا كنت لا ترغب في استخدام شيفرة SVG المتحركة، فيمكنك دائمًا إنشاء SVG sprite وتحريكه بالطريقة التي يمكنك بها تحريك أي صيغة صورة آخرى - باستخدام ()steps وعدة أسطر CSS. تتحدث سارة أيضًا عن هذه التقنية في مقالتها. لا يحتاج تحريك صور SVG أن يكون معقدًا، وهو يقدم أداءً أفضل بشكلٍ عام. نتيجة صورة GIF صورة SVG متحركة بما أنّه لا يمكن التحكم بالمحتوى داخل صورة GIF بالشيفرة، فلا يمكن جعل الصور المتحركة تتكيف أو تستجيب لتغيّرات منفذ العرض أو السياق بدون اللجوء إلى فصل الصور. بما أنّه يمكن تحريك محتوى SVG بشكلٍ مباشر باستخدام الشيفرة، فإنّه يمكن تعديل المحتوى والحركات بحيث يستجيب و/أو يتكيّف مع سياقات وأحجام منافذ عرض مختلفة، بدون الحاجة إلى اللجوء إلى أي أصول إضافية. كلمات أخيرة تتمتع صور GIF بدعم جيد جدًا للمتصفح، نعم، ولكن مزايا صور SVG تفوق مزاياها في جميع الجوانب تقريبًا. قد تكون هناك استثناءات، وفي هذه الحالات، تستخدم صور GIF بالتأكيد أو أي صيغة صور آخرى تقدم عملًا أفضل من SVG. قد تستخدم حتى فيديو أو HTML5 Canvas أو أيًا كان. يمكن أن توفر SVG الكثير من مزايا الأداء إلى القائمة عند موازنتها مع صيغ الصور الأخرى، وخاصةً GIF. وبالتالي، وبالنظر إلى كل ما سبق، أوصي بأنه في أي مكان يمكن استخدام SVG للصور المتحركة، يجب تجنّب استخدام صور GIF. أنت حر بالطبع في تجاهل توصيتي لكنك ستتخلى عن المزايا الكثيرة التي توفرها صور SVG المتحركة. ما لم توفر صور GIF الكثير من المزايا على صور SVG التي لا تحقق دعم المتصفح IE8 وأقل منه، فإنني أعتقد أن صور SVG ينبغي أن تكون هي السبيل للانطلاق. بعض المصادر لمساعدتك على البدء مع صور SVG المتحركة: عالم الصور المتحركة SVG. عدة طرق مختلفة لاستخدام SVG sprites في الصور المتحركة. إنشاء الصور المتحركة مع SVG. لدى GreenSock مجموعة من المقالات المفيدة حول تحريك SVG. Snap.svg ويُعرف أيضًا بأنّه "مكتبة jQuery للـ SVG". الصور المتحركة SVG باستخدام CSS وSnap.SVG. تصميم وتحريك صور SVG مع CSS. رسم خط متحرك في SVG. أرجو أن تكون قد وجدت هذه المقالة مفيدةً. شكرًا للقراءة. ترجمة -وبتصرف- للمقال Animated SVG vs GIF [CAGEMATCH]‎ لصاحبته Sara Soueidan
  2. تمتلك الرسوم الشعاعية vector graphics أهميةً واضحةً في حالات عديدة، إذ تتميز بحجم منخفض وقدرة كبيرة على تغيير أبعادها دون أن تتشوه عند تصغيرها أو تكبيرها، ونستعرض في مقالنا كيفية إضافة رسوميات مثل هذه إلى صفحات الويب وخاصةً صور SVG. لا بدّ قبل متابعة القراءة أن تكون على دراية بأساسيات HTML وبكيفية إدراج الصور في صفحاتك. ملاحظة: لا نهدف في هذا المقال إلى تعليمك إنشاء رسوميات SVG، وإنما فقط كيفية إدراجها في صفحات الويب. ما هي الرسوميات الشعاعية؟ ستتعامل خلال مسيرتك في عالم الويب مع نوعين من الصور: الصور النقطية Raster images: تعرَّف على صورة شبكة من البكسلات، إذ يحتوي ملف الصورة النقطية على معلومات تعرض موقع كل بكسل في الصورة واللون الدقيق لكل بكسل، ومن أكثر تنسيقات الصور النقطية انتشارًا على الويب هي بِت-ماب bmp. و png. و jpg. و gif.. الصور الشعاعية vector images: تُعرَّف باستخدام خوارزمية، إذ يحتوي ملف الصورة الشعاعية على تعريفات للشكل والمسار اللذين يستخدِمهما الحاسوب في عرض الصورة بالطريقة الصحيحة عندما يصيرها على الشاشة، ومن أمثلتها صور SVG التي تساعدك في إنشاء رسوم شعاعية مناسبة جدًا للاستخدام في الويب. حتى تدرك الفرق بين النوعين سنعرض عليك مثالًا يمكنك استعراضه مباشرة ضمن مستودع جيت-هاب المخصص، إذ يعرض الملف صورتان متطابقتان تمامًا لنجمتين حمراوين يحيط بهما ظل أسود إلى جوار بعضهما، وتكون الصورة اليمينية بتنسيق SVG واليسارية بتنسيق PNG، كما سيبدو الفرق واضحًا عندما تكبر الصورة في الصفحة، إذ تتشوه صورة PNG لأنها تحتوي على معلومات تحدِّد موقع كل بكسل بدقة كما تحدد لونه، فعندما تكبر هذه الصورة سيزداد حجم كل بكسل ليملأ حجمًا أكبر على الشاشة وستبدو الصورة مشوشةً، في حين لا يتغير شكل صورة SVG، لأن تغير أبعاد الصورة لن يؤثر في مظهرها نظرًا لاستخدام هذه الصور خوارزمية لعرض الشكل حتى بعد تضاعف حجمه. ملاحظة: إن كلتا الصورتين السابقتين في الواقع من نوع PNG (طريقة عرضهما في المقال)، إذ تمثِّل الصورة اليسارية صورةً نقطيةً، في حين تمثِّل الصورة اليمينية صورةً شعاعيةً. يُعَدّ حجم ملفات الصور الشعاعية أقل من مقابلاتها النقطية، لأنها ستحمل فقط عدة خوارزميات بدلًا من معلومات عن كل بكسل بمفرده. ما هي صور SVG؟ تُعَدّ SVG لغةً وصفيةً مبنيةً على أساس اللغة XML، وتشابه من حيث المبدأ لغة HTML، ما عدا أنها تضم عناصر مختلفة لتعريف الأشكال التي تريد عرضها في صفحتك والتأثيرات التي تريد تطبيقها على هذه الأشكال، فهي إذًا لغة لتوصيف الرسوم وليس المحتوى، وستجد عناصر إنشاء الأشكال البسيطة مثل الدائرة <circle> والمستطيل <rect> على أساس مثال عن أبسط العناصر، كما ستجد عناصر تعطي ميزات أكثر تقدمًا مثل <feColorMatrix> لتحويل الألوان باستخدام مصفوفة التحويل و <animate> لتحريك أجزاء من الرسم الشعاعي و <mask> لتطبيق قناع فوق صورتك. ستعطيك الشيفرة التالية على سبيل المثال صورةً لدائرة ومستطيل: <svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="black" /> <circle cx="150" cy="100" r="90" fill="blue" /> </svg> وستكون النتيجة كما يلي: قد يراودك شعور أنّ كتابة شيفرات الصور الشعاعية هين كما في المثال السابق، وبالطبع يمكنك كتابة شيفرات أمثلة بسيطة مثل تلك، ولكن سرعان ما ستجد صعوبةً بالغةً عند تصميم الصور الأعقد، إذ يستخدِم معظم المصممين برامج تحرير خاصة لإنشاء صور مثل هذه مثل "إنكسكيب Inkscape" و "إليستريتور illustrator"، كما تساعدك هذه البرمجيات في إنشاء رسومات متنوعة باستخدام أدوات متنوعة للرسم وإنشاء أشكال تقريبية للصور مثل ميزة "تتبع الخريطة النقطية Trace Bitmap" التي يتيحها برنامج "إنك سكيب". تمتلك صور SVG ميزات متقدمةً إضافةً إلى ما ذكرناه سابقًا: يمكن الوصول إلى النصوص ضمن صور SVG والتعامل معها، ولهذا الأمر فوائده فيما يتعلق بالسيو SEO. يمكن أن تنقل جزءًا من صورة إلى أخرى لأنها مكوّنات مستقلة على هيئة عناصر، وبإمكانك أيضًا تنسيقها باستخدام CSS وكتابة شيفرة للتحكم بها باستخدام جافاسكربت. لماذا سيفضِّل المطورون إذًا استخدام الصور النقطية على صور SVG؟ السبب هو بعض المساوئ: يمكن أن تتعقد شيفرتها بسرعة، مما يعني أنّ حجمها قد يزداد، وقد يتطلب تصييرها زمنًا أطول من قِبَل المتصفح. قد يكون إنشاء هذه الصورة أصعب من الصور النقطية تبعًا لطبيعة الصور التي تنوي إنشاءها. لا تدعم المتصفحات القديمة هذه الصور، وبالتالي لن تكون مناسبةً إذا قررت دعم تلك المتصفحات مثل النسخ القديمة لإنترنت إكسبلورر فهي مدعومة ابتداءً من النسخة IE9. يرى البعض أنّ الرسوميات النقطية أفضل عند إنشاء صور معقدة عالية الدقة مثل الصور الفوتوغرافية، وذلك للأسباب التي شرحناها آنفًا. إضافة صور SVG إلى صفحات الويب سنعرض في هذا القسم الطرق المختلفة التي يمكن اتباعها لإضافة صور SVG الشعاعية إلى صفحة الويب. الطريقة السريعة: استخدام العنصر يُنفَّذ الأمر بالإشارة إلى ملف الصورة الشعاعية من خلال السمة src، كما تحتاج إلى ضبط قيمتي الطول والعرض من خلال السمتَين width و height وخاصةً إذا لم ترث صورة SVG نسبة البُعدين aspect ratio، لذا راجع مقال إضافة الصور في صفحات HTML إذا لم تفعل ذلك من قبل. <img src="equilateral.svg" alt="triangle with all three sides equal" height="87" width="100" /> الحسنات: طريقة سريعة، صياغة قواعدية مألوفة، ويمكن تزويدها ببديل نصي من خلال السمة alt. يمكن تحويلها إلى رابط بسهولة عن طريق وضعها ضمن العنصر <a>. يمكن أن يخزِّن المتصفح ملف SVG تخزينًا مؤقتًا، مما يزيد من سرعة تحميل الصفحة إذا أردت تحميلها مجددًا في المستقبل. السيئات: لا يمكن التلاعب بالصورة عبر جافاسكربت. ينبغي استخدام قواعد CSS سطرية inline CSS ضمن شيفرة ملف SVG لتتمكن من التحكم بمحتوى الصورة، إذ لن تؤثر ملفات التنسيق الخارجية التي يستدعيها ملف SVG. لا يمكن إعادة تنسيق الصورة باستخدام أصناف CSS المجردة مثل :focus. استكشاف الأخطاء ودعم المتصفحات عند استخدامك متصفحات لا تدعم SVG مثل IE8 ومتصفحات نظام أندرويد بنسخة تحت 2.3، فيمكنك الإشارة إلى صورة PNG أو JPG عبر السمة src ومن ثم استخدم السمة srcset التي تميزها المتصفحات الحديثة فقط للإشارة إلى صورة SVG، وفي هذه الحالة لن تشغل صورة SVG سوى المتصفحات الحديثة التي تدعمها وستشغل المتصفحات الأقدم الصورة النقطية: <img src="equilateral.png" alt="triangle with equal sides" srcset="equilateral.svg"> يمكنك استخدام صورة SVG على أساس خلفية من خلال تنسيقات CSS، إذ ستجد في الشيفرة التالية أنّ المتصفحات القديمة ستتعامل فقط مع الصورة النقطية التي تفهمها، في حين ستميز الحديثة صورة SVG: background: url("fallback.png") no-repeat center; background-image: url("image.svg"); background-size: contain; لا يمكن كذلك التلاعب بالخلفية SVG التي ندرجها من خلال تنسيقات CSS باستخدام جافاسكربت، وتخضع للقيود نفسها التي يخضع لها استخدام قواعد CSS مع صور SVG التي يدرجها العنصر <img>. كيفية إدراج صور SVG ضمن صفحات HTML يمكنك فتح ملف SVG باستخدام محرر نصي، كما يمكن نسخ شيفرته ولصقها في ملف HTML، إذ تُدعى هذه العملية بالإدراج المباشر SVG inline أو inlining SVG، بحيث تُضاف هذه الشيفرة إلى HTML بين وسمَي البداية والنهاية للعنصر <svg>، وإليك مثالًا بسيطًا كما يلي: <svg width="300" height="200"> <rect width="100%" height="100%" fill="green" /> </svg> الحسنات: تقلل هذه العملية من طلبات HTTP، وبالتالي قد تقلل من زمن تحميل الصفحة. يمكنك استخدام السمة class والسمة id مع العنصر <svg>، كما يمكن تنسيقه باستخدام CSS ضمن العنصر ذاته أو في أيّ مكان تضع فيه قواعد تنسيق CSS الخاصة بملف HTML، وعمومًا يمكنك استخدام أي سمة وصفية للعنصر SVG على أساس خاصية من خواص CSS. يُعَدّ الإدراج المباشر لشيفرة SVG الطريقة الوحيدة التي تتيح لك استخدام قواعد CSS التفاعلية مثل الأصناف المجردة مثل :focus والرسوم المتحركة ضمن صور SVG، حتى ضمن صفحات التنسيق النمطية. يمكنك توصيف شيفرة SVG على أساس رابط بتغليفها داخل العنصر <a>. السيئات: تُعَدّ هذه الطريقة مناسبةً فقط إذا استخدمت SVG في مكان واحد، فالتكرار قد يسبب استخدامًا كثيرًا للموارد. سيزيد استخدام شيفرة SVG زائدة من حجم ملف HTML. لا يمكن للمتصفحات تخزين شيفرة SVG المباشرة كما تخزن شيفرة SVG المدرَجة ضمن الصور النمطية، وبالتالي لن تزيد سرعة تحميل الصفحات التي حُمِّلت سابقًا في هذه الحالة. بإمكانك تزويد صورة SVG بمحتوى بديل باستخدام العنصر <foriegnObject>، لكن ستنزل المتصفحات التي تدعم SVG أيضًا الصور البديلة أو الاحتياطية، ولهذا عليك التفكير مليًا في ضرورة دعم المتصفحات القديمة أو لا. إدراج صور SVG باستخدام العنصر <iframe> يمكنك أيضًا فتح صور SVG في متصفحك، وبالتالي يمكنك إدراج هذه الصورة في صفحتك باستخدام <iframe> على نحو مماثل تمامًا لما فعلناه في مقال آليات إدراج المحتوى والوسائط المتعددة في صفحة HTML، وإليك مراجعة سريعة: <iframe src="triangle.svg" width="500" height="500" sandbox> <img src="triangle.png" alt="Triangle with three unequal sides" /> </iframe> وبالطبع فهي ليست الطريقة الأفضل لإدراج SVG. السيئات: يملك لعنصر <iframe> آليةً لعرض محتوى بديل في حال حدثت مشكلة في عرضه، لكن ستعرض المتصفحات هذا المحتوى فقط إذا لم تدعم العنصر <iframe> بالكامل. إذا لم يكن لصفحتك وملف SVG أصلًا مشتركًا، فلن تتمكن من استخدام جافاسكربت في صفحتك الرئيسية للتلاعب بهذا الملف. تطبيق: العمل مع SVG سنحاول في هذا التطبيق العمل على بعض رسوميات SVG على سبيل التسلية، فلقد وضعنا في قسم المدخلات Input ضمن محرر الشيفرة في الأسفل بعض الأمثلة لتبدأ، كما يمكنك الاطلاع على عناصر SVG أخرى لتعمل عليها بالعودة إلى مرجع MDN إلى عناصر SVG، إذًا فهذا القسم لشحذ مهاراتك في البحث مع قليل من التسلية. إذا ارتكبت خطأً، فيمكنك مسح ما كتبته بالنقر على زر إعادة الضبط Reset. خلاصة قدمنا لك في هذا المقال جولةً سريعةً على الرسوم الشعاعية وملفات SVG، كما بيّنا فائدتها وكيفية إدراج صور SVG في صفحات الويب، فلم يكن القصد من هذا المقال تزويدك بدليل لتعلم SVG، وإنما لتعريفك بهذه التقنية إذا صادفتها لاحقًا خلال رحلتك في تطوير الويب، فلا تقلق إذًا إذا لم تجد نفسك خبيرًا بعد. سنناقش في آخر مقالات هذه السلسلة مفهوم الصور المتجاوبة responsive images بشيء من التفصيل، وسنلقي نظرةً على أدوات HTML التي تتيح لك إدراج صور تُعرَض جيدًا على مختلف الأجهزة. ترجمة -وبتصرُّف- للمقال Adding vector graphics to the web. اقرأ أيضًا نصائح لإنشاء وتصدير رسومات SVG للويب إضافة الصور في صفحة HTML كيفية إنشاء أشكال بسيطة باستخدام SVG
  3. حظيت مواصفات لغة التكامل المتزامن للوسائط المتعدّدة (Synchronized Multimedia Integration Language، أو SMIL اختصارا)، وهي معيار مختص بترميز رسوميات SVG ، بشهرة كبيرة لتوفيرها إمكانيات عديدة للتعامل مع رسوميات SVG المتحركة. للأسف دعم SMIL يتناقص بمرور الزمن على محركات WebKit القياسية ولم تكن مدعومة أساسًا على متصفحات Microsoft (وغالبًا لن تدعمها أبدًا في المستقبل). لكن لا تقلق، يمكن علاج ذلك. هنا سنكتشف بدائل للميزات الخاصة في SMIL، ونبيِّن طرقًا بديلة لأداء تلك المهام وجعلها تحظى بدعم لفترة أطول. ميزة SMIL: التحريك وفقًا لمسار أحد أهم مميزات SMIL المتعلقة بالحركة الواقعية هي القدرة على التحريك وفقًا لمسار محدد. القليل فقط من الأشياء تتحرك في خط مستقيم على أرض الواقع، لذلك القدرة على التحكم بالرسوميات على مسار محدد مسبقًا يساعد على محاكاة الحركة الواقعية. باستعمال الخاصية animateMotion، كان يمكنك تمرير مسار SVG وتحديد بيانات الحركة والاتجاه ثم تحديد العنصر المراد تحريكه بإسناد معرّفه للرابط xlink:href="#thingtoanimate"‎ كما في المثال التالي: <animateMotion xlink:href="#lil-guy" dur="3s" repeatCount="indefinite" fill="freeze" path="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" /> البديل باستخدام CSS لحسن الحظ، القدرة على التحريك وفقًا لمسار مدمجة في لغة CSS. رغم ذلك مجال الدعم المتوفر لها لا يزال محدودًا (متصفحات كروم، وأوبرا، وفيرفكس على سطح المكتب، وبعض متصفح أندرويد). بالنسبة لمتصفح سفاري، فالأمر تطلب الإبلاغ عن الأعطال لطلب ميزة التحريك وفقًا لمسار كخاصية CSS. يتطلب استخدام التحريك وفقًا لمسار على CSS تحديد مسار الحركة باستعمال نقاط مرور كالتالي: .move-me { offset-path: path('M3.9,74.8c0,0,0-106.4,75.5-42.6S271.8,184,252.9,106.9s-47.4-130.9-58.2-92s59.8,111.2-32.9,126.1 S5.9,138.6,3.9,74.8z'); } نتيجة المثال أعلاه يمكن الحصول على بيانات المسار ونقاط المرور من نتائج مخرجات تصميم SVG على Illustrator ثم تحسينها عن طريق أداةSVGOMG. سنتأكد في هذا المثال أن العنصر سيتبع المسار من نقطة البداية وصولًا لنهايته ويمكنك ملاحظة أنه مسار مغلق، أي أن العنصر سينتهي به المطاف عائدًا لنقطة البداية مكررًا مساره. حدّدت هنا قيم الإطارات المفتاحية وخُصّصت القيمة 100% فقط لأن القيمة الافتراضية محددة عند 0: @keyframes motionpathguy { 100% { motion-offset: 100%; } } ثم نحدد خيارات تحريك العنصر: .move-me { animation: motionpathguy 10s linear infinite both; } بديل: أسلوب GreenSock للتحريك إذا كنت تسعى لخيارات الدعم الأوسع والأكثر مرونة في التطبيق، فعليك باستخدام مكتبة GreenSock المكتوبة بجافاسكريبت. يوفّر ملحق Bezier-Plugin دعمًا يمتد حتى الإصدار السابع من متصفح مايكروسوفت بدون استعمال عناصر SVG، وحتى الإصدار التاسع في حال أردت استعمال عناصر SVG (وهو أشمل دعم متوفّر لتحريكات SVG). يجدر بنا ذكر أنك ستحتاج إلى إدراج مصفوفة لإحداثيات المسار: bezier: { type: "soft", values:[{x:10, y:30}, {x:-30, y:20}, {x:-40, y:10}, {x:30, y:20}, {x:10, y:30}], autoRotate: true } يمكنك استعمال خيار التدوير التلقائي على غرار SMIL. وإذا كنت تفتقد قدرات SMIL على التحكم بالانعكاس التلقائي أو تحديد موضع الدوران التلقائي وزاويته، تتيح لك المكتبة التحكم بالدوران حتى 90 درجة من الميلان أو أي درجة من التحكم قد تحتاجها. autorotate: [ قيمة الموضع الأول "x", قيمة الموضع الثاني "y", "rotationY" أو "rotation" قيمة الحركة الدائرية، عادةً , قيمة رقمية تمثل زاوية بداية الدوران، مثلًا "10", false أو true قيمة منطقية (radians/degree) لاختيار وحدة قياس الزاوية ] يمكنك التحكم بدوران العنصر على SMIL أثناء حركته بالتلاعب بالمسار أو المسار، أما في مكتبة GreenSock فيمكنك أداء ذلك بسهولة بإيقاف التدوير التلقائي وبرمجة الدوران بسلسلة تعليمات، أيضًا يمكنك التلاعب بخصائص عناصر SVG كما كنت تفعل على SMIL برغم أنه أقل أناقة وأصعب في التتبع أثناء تحضيره. TweenMax.set("#foo" { rotation: 90 // أو أي قيمة مناسبة }); يمكنك الاختيار بين القيم thru، أو soft، أو quadratic، أو cubic لتحديد نوع المسار. تعليمات الشرح لكل منها موجودة على مكتبة GreenSock البرمجية. نقطة قوة thru هي القدرة على التأثير على مدى انحناء عنصر. إذا عدَدْنا أن نقاط المرور هي إحداثيات للتنقل منها وإليها، مدى الانحناء سيحدد اتجاه المسار عند الانتقال بين تلك النقاط. مدى الانحناء 0 سيكون اتجاهًا مباشرًا، 1 سيكون مائلًا قليلًا، 2 سينتج مسارًا منحنيًا، 3 وأكثر سيجعل المسار ينغلق على نفسه. إليك مثال حي. مؤخرًا، أثبت GreenSock قدرته على تمرير بيانات المسار مثل CSS و SMIL. جاء ذلك في صيغة تمديد (Extension) لملحق MorphSVG الخاص بها. يُضاف الملحق ويُستعمَل كالتالي: TweenMax.to("#lil-guy", 3, { bezier: { MorphSVGPlugin.pathDataToBezier("#path", {align: "#lil-guy" }), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); <path id="path" d="M 25,50 C 37.5,25 37.5,25 50,0 75,50 75,50 100,100 50,100 50,100 0,100 12.5,75 12.5,75 25,50 Z" fill="none" /> إليك النتيجة حية. سيعيّن الوضع الافتراضي أعلى مجموعة العناصر المُراد تحريكها، أي العنصر المسمى lil-guy#، إلى المسار، أي أنّ الركن العلوي الأيسر هو ما سيمرّ على المسار. بصريًا ستبدو الحركة غير متناسقة لذا قمنا بجعل العنصر lil-guy# يستخدم نقطة مركزية باستعمال تعليمات TweenLite.set: TweenLite.set("#lil-guy", {xPercent:-50, yPercent:-50}); يمكنك موازنة تلك المسارات بتمرير كائن إلى الوسيط الثاني في التابع TweenLite.set، وتعيين قيم offsetX و offsetY في التابع pathDataToBezier. كن حذرًا هنا فقد تحتاج لتوسيع صندوق العرض (viewBox) في SVG حتى لاتتداخل العناصر قيد التحريك ببعضها، أو تفقد بعض أجزائها خارج الصندوق. // أزح إحداثيات المسار بمقدار 125 بكسلًا أفقيًا و 50 بكسلًا رأسيًا TweenMax.to("#lil-guy", 3, { bezier: { values: MorphSVGPlugin.pathDataToBezier("#path", { offsetX: 125, offsetY: 50, align: "#lil-guy" }), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); إليك النتيجة حية. يمكنك حتى تعريف مصفوفة إحداثيات لهذا التموضع: // ضاعف إحداثيات المسار بمقدار 1.25 // أزحه بمقدار 120 بكسل على المحور الأفقي // ارفعه بمقدار 30 بكسل على المحور الرأسي TweenMax.to("#lil-guy", 3, { bezier: { values: MorphSVGPlugin.pathDataToBezier("#path", { matrix:[1.5,0,0,1.5,120,-30], align:"lil-guy"}), type: "cubic" }, ease: Linear.easeNone, repeat: -1 }); إليك النتيجة حية. يوجد خيار آخر يتمثّل في تحديد قيمة المحاذاة إلى relative، وهو ما سيمنع العنصر من القفز خارج مساره بتثبيت الموضع لكل الإحداثيات المرتبطة إلى القيم x:0, y:0. في الأمثلة السابقة استعملنا المحاذاة بالتزامن مع مجموعة عناصر lil-guy#. لمعلومات محدثة عن هذه الميزة لملحق Bezier، تفقَّد التوثيق على مكتبة GreenSockالبرمجية. ميزة SMIL: تحوير الشكل سابقًا كان باستطاعتك تمرير بيانات المسار كقيم داخل خصائص الرسوميات بهدف تحوير الشكل. البديل: مكتبة Snap.svg أو SVG Morpheus توفر بعض المكتبات البرمجية مثل Snap.svg و SVG Morpheus القدرة على تحوير الشكل أو المسار. لكن يجب مطابقة عدد نقاط الشكل الأساسي والمحوَّر وإلا تشوَّه الشكل الناتج. بسبب ذلك، عليك مراقبة الشكل الناتج من التحوير باستمرار أثناء التصميم أو نسِّق مع مصممك لتحصل على بيانات تلك النقاط مع تلافي إضافة نقاط غير ضرورية حتى لا تتسبب بإبطاء الرسوميات الناتجة. بديل: ملحق MorphSVG من GreenSock ينبغي التأكيد على بهذا الملحق، إذ يمكنه تحوير الأشكال والمسارات بسلاسة باستعمال مقادير مختلفة من النقاط، كما في هذا المثال. لمَّا كان ملحق MorphSVG يُعدل على بيانات المسار، فستحتاج إلى استعمال خيار convertToPath إذا احتجت لتعديل الشكل: MorphSVGPlugin.convertToPath("ellipse"); // or circle, rect, etc هذا سيسمح لك بإجراء تعديلات معقدة على الأشكال وهي طفرة حقيقية على مستوى التحريك على الويب. يقدّم الملحق ميزات إضافية جديرة بالذكر. الأولى هي ميزة findShapeIndex متعددة الاستخدامات. لنقل إن الشكل الحالي المحَّر لا يعجبك (برغم أن إعادة الضبط التلقائي عادةً ما تفي بالغرض). ستُحمِّل الملحق الخاص (ليس عليك القلق بشأن زيادة حجم مشروعك، فلا داعي للملحق بعد مرحلة التطوير)، ثم تمرر قيمتين: معرَّف الشكل الأول، ومعرّف الشكل الثاني. ستظهر لديك واجهة رسومية يمكنك بها الانتقال بين القيم، وأيضًا ستستعمل التكرار على نحو افتراضي (repeat: -1) لتستمر إعادة الحركة بين الأشكال. findShapeIndex("#hex", "#star"); // findShapeIndex() يمكنك تعليق السطر البرمجي أعلاه لإلغاء تفعيل واجهة إليك النتيجة حية. بمجرد حصولك على تلك القيم الإضافية، يمكنك تحديد قيمة shapeIndex داخل مصفوفة morphSVG: TweenLite.to("#hex", 1, {morphSVG: { shape: "#star", shapeIndex: 1 }}); الميزة الثانية لهذا الملحق هي قدرته على تحليل المسارات، لا يوجد ملحق آخر يمكّنك من ذلك. أخيرًا يمكن إعادة استعمال قيمة المعرّف الخاصة ببداية الحركة بدون الحاجة لتخزينها. من الجدير بالذكر أنه عند الإطلاق الأول لهذا الملحق لم تكن هذه الميزات موجودة، لكن GreenSock ظلّت تدعمه بالميزات بلستمرار وبما أننا لم نعد ملزمين بعدد معين للنقاط يمكننا توسيع آفاقنا لمزيد من التأثيرات. هنا مثال على دخان. ميزة SMIL: أحداث التفاعل مع الصفحة وفَّر SMIL تأثيرات مثل التحويم على العناصر والضغط عليها وعند الرغبة باستعمال أي منها يمكنك تحديد الحدث باستعلام مثل begin="click"‎ أو begin="hover"‎: <animate xlink:href="#rectblue" attributeName="x" from="0" to="300" dur="1s" begin="click" values="20; 50" keyTimes="0; 1" fill="freeze" /> بديل: لغة JavaScript هنالك أحداث مدمجة ضمن اللغة مثل onmouseenter و onmouseleave لتأثيرات الحومان والضغط. يمكنك استعمالها لتفعيل رسوميات JavaScript. البديل: التعاون بين JavaScript و CSS يمكنك استعمال JavaScript لتغيير صنف عنصر ما أو تغيير تنسيقات CSS الخاصة به مباشرة. كمثال سنغير حالة الرسوميات لتتفعل بناءً على حدث ما: .st0 { animation: moveAcross 1s linear both; animation-play-state: paused; } @keyframes moveAcross { to { transform: translateX(100px); } } document.getElementById("rectblue").addEventListener("click", function() { event.target.style.animationPlayState = "running"; }); إما إذا اعتدت على استعمال jQuery فالاستعلام كالتالي: $(".st0").on("click", function() { $(this).css("animation-play-state", "running"); }); إليك النتيجة حية. تنفيذ هذا الاستعلام لن يعيد الرسوميات إلى نقطة البداية مباشرة كما فعل SMIL في المثال السابق. إذا أردت إنجاز ذلك فستحتاج إلى استعمال عدَّة خدع CSS مختصة بذلك. البديل: Greensock إعادة الحركة باستخدام مكتبة GreenSock أكثر بساطة. يمكننا إضافة الرسوميات إلى جدول زمني للتحكم بإيقاف واستئناف الرسوميات بالضغط على العنصر. طريقة التنفيذ هذه شبيهة بما اعتدته من SMIL حيث لا نحتاج للتعامل مع نسخ أو إعادة إدخال أي نقاط شجرية للصفحة أو تغيير خصائص العناصر: // TimelineLite إنشاء نسخة من var tl = new TimelineLite(); // إضافة رسوميات إلى جدول زمني tl.to(foo, 0.5, { left: 100 }); $(".st0").on("click", function() { tl.restart(); }); ميزة SMIL: تشغيل X بعد اكتمال Y يستطيع SMIL إنشاء أحداث بتوقيت أكثر تعقيدًا مثل begin="circ-anim.begin + 1s"‎ (بدء حركة عنصر بعد ثانية من بدء حركة عنصر آخر). وهذا مفيد بالأخص عند إنشاء رسوميات متسلسلة. بديل: CSS على CSS يمكنك إنشاء تسلسل للرسوميات بتحديد تأخير على الرسوميات اللاحقة: .foo { animation: foo-move 2s ease both; } .bar { animation: bar-move 4s 2s ease both; /* تتطابق القيمة ‏2s‏ مع مدة التكرار في العنصر الأول أعلاه */ } طريقة العمل قد تصبح مسببة للإزعاج إذ عليك تذكر تغيير الفجوة الزمنية الأولى وكذلك التأخير لكل عنصر. بديل آخر: برمجة CSS مسبقة (SASS) إعداد وإدارة تلك الفجوات الزمنية يمكن تسهيله إذا استعملت متغيرات Sass مثلًا: $secs: 2s; .foo { animation: foo-move $secs ease both; } .bar { animation: bar-move 4s $secs ease both; } هكذا ستتأكد أن تحديث قيمة واحدة لن يؤثر على التزامن. لكن إذا أردت تتبع الرسوميات عند اكتمالها، فجافاسكريبتيقدم دعمًا وظيفيًا أصليًّا باستعمال animationEnd: $("#rectblue").on("animationend", function() { $(this).closest("svg").find("#rectblue2").css("animation-play-state", "running"); }); #rectblue2 { animation: moveAcross 2s 1s ease both; animation-play-state: paused; } إليك النتيجة حية (قد تحتاج للنقرعلى زر إعادة التشغيل لرؤية الحركة). لتنفيذ التأخير يمكننا جدولة توقيت ظهور العناصر عبر خاصيات تأخير رسوميات CSS للعناصر أو باستعمال setTimeout: setTimeout(function timeoutHandler() { // أدرج الرسوميات هنا، بغض النظر عن لغة البرمجة المستخدمة }, 1000); // انتظر لثانية واحدة بديل آخر: Greensock هذا هو الخيار المفضل لديّ للحصول على تحكم دقيق بالمسار الزمني الخاص بالرسوميات، إذ يمكنك أداء ذلك بعدة طرق مختلفة. خط زمني بسيط: // TimelineLite أنشئ var tl = new TimelineLite(); // أضف الرسوميات لبداية الخط الزمني tl.to(foo, 0.5, { left: 100 }); // استعمل قيمة الموضع (+=1) لبدء الرسوميات التالية بعد ثانية واحدة من انتهاء الحالية tl.to(foo, 0.5, { left: 200 }, "+=1"); خط زمني بوصف نسبي: // أضف علامة متأخرة 0.5 ثانية لتحديد موضع الإطار التالي tl.add("العلامة") // استخدم العلامة لتحديد ظهور الرسوميات بعد الثانية التالية tl.to(foo, 0.5, { scale: 0 }, "العلامة+=1"); // أو استعمل العلامة لإنشاء واجهة للتفاعل tl.play("العلامة"); من الأفضل استعمال الوصف النسبي حيث تختار نقطة زمنية ما لتقوم بتفعيل العديد من الثأثيرات أو تأخيرها. حتى لو كانت خاضعة لتعديل زمني، وليس عليك القيام بأي إعادة لحسابات CSS. الفائدة من استعمال المسار الزمني هي القدرة على التحكم الدقيق بعدة عناصر من مكان واحد كما يمكنك استعمال خاصيّات مثل تأخير التكرارات. يقدم SMIL أيضًا خاصية repeatDur التي تمكنك من تحديد مدة التكرار المحدد، إذا لم ترغب بالقيمة الافتراضية "repeatDur="01:30 يمكنك التحكم بالسرعة بمساعدة GreenSock وبالتالي تعدي مدة التكرار باستعمال timeScale (n) أو repeat: -1. خلاف ذلك، يمكنك تحديد التكرار بالخاصية "repeatDur="indefinite. جدول بياني للبدائل بعدما انتهينا من استكشاف أفضل مميزات SMIL يجدر بنا الإشارة إلى مزيد من البدائل لخصائص SMIL والتي ربما استعملتها مسبقا. في ما يلي جدول للرجوع إليه للحصول بسرعة على بدائل الوظائف الأكثر سهولة. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } SMIL الشفرة البديلة التقنية البديلة keyTimes ‎@keyframes CSS keySplines cubic-bezier CSS restart restart()‎ GSAP calcMode="discrete"‎ steps()‎ CSS remove kill(); clear(); clearProps: "all"‎ GSAP freeze animation-play-state: paused CSS freeze pause()‎ GSAP fill animation-fill-mode CSS repeatCount="indefinite"‎ animation-iteration-count: infinite;‎ CSS repeatCount="indefinite"‎ repeat: -1 GSAP whenNotActive detect animation-play-state in JS CSS, vanilla JavaScript or jQuery animateMotion path motion-path CSS animateMotion path bezier GSAP animate values (path morphing) MorphSVG GSAP begin="hover"‎ mouseover, mouseenter, mouseout, mouseleave jQuery, vanilla JS begin="circ-anim.begin + 1s"‎ animation-delay: $vars;‎ SASS begin="circ-anim.begin + 1s"‎ timeline, position parameter ex "+=1"‎ GSAP ترجمة - وبتصرف - للمقال SMIL is dead! Long live SMIL! A Guide to Alternatives to SMIL Features لصاحبته Sarah Drasner.
  4. في الوقت الذي ستُلقي فيه نظرة على هذا المقال قد تكون معايير SMIL أصبحت شيئًا من الماضي، لكن مهلًا! في هذا المقال ستجد دليلًا لاستبدال بعض الميزات وتطويرها. لمحة عامة يمكن تحريك الرسوم المتجهة (SVG graphics) باستخدام عناصر التحريك المعرفة في مواصفات لغة التكامل المتزامن للوسائط المتعدّدة SMIL، تشمل تلك العناصر ما يلي: <animate>: يسمح لك هذا العنصر بتحريك خاصيات HTML وخاصيات الكائنات على مدى فترة زمنية محددة. <set>: وهو اختزال مناسب للتحريك، فهو يفيد في تعيين قيم التحريك لخاصيات HTML وخاصيات الكائنات مثل خاصية الظهور والرؤية. <animateMotion>: يعمل على تحريك العنصر على امتداد مسار الحركة. <animationColor>: تستطيع من خلال هذا العنصر تعديل القيم اللونية لخاصيات HTML وخاصيات الكائنات مع مرور الوقت. لاحظ إهمال العنصر <animateColor> لمجرد استخدام عنصر التحريك لاستهداف خصائص من الممكن أن تمتلك قيم لونية. بالرغم من ذلك لا يزال ذلك العنصر متاحًا في مواصفات SVG1.1، على العكس من SVG2 فهو مهمل ومحذوف بالكامل. بالإضافة إلى عناصر التحريك المعرفة في مواصفات SMIL تحتوي الرسوم المتجهة SVG ملحقات متوافقة مع مواصفات SMIL والتي تحتوي على خاصيات توسع نطاق عمل العنصر <animateMotion> وعناصر إضافية أخرى. تشمل ملحقات الرسوم المتجهة SVG ما يلي: <animateTransform>: يتيح لك تحريك إحدى خاصيات الرسوم المتجهة مع مرور الوقت، مثل خاصية transform. path (خاصية HTML): تسمح بتحديد أي خاصية من صيغ بيانات مسار الرسوم المتجهة SVG في خاصية المسار لعنصر animateMotion، (التحريك اعتمادًا على SMIL فقط يسمح بتفرع صيغ بيانات الرسوم المتجهة خلال مسار). سنتطرق بالحديث أكثر عن animateMotion في الفقرات القادمة. <mpath>: يستخدم بالاقتران مع عنصر animateMotion للإشارة إلى مسار حركة الذي سيستخدم كمسار لتحريك العناصر. مع العلم أن عنصر mpath مضمن داخل عنصر animationMotion قبل علامة الإغلاق. <keypoints> (خاصية HTML): تستخدم كخاصية لـ animateMotion لتوفير تحكم دقيق في سرعة حركة العناصر في مساراتها. <rotate> (خاصية HTML): تستخدم أيضًا كخاصية لـ animateMotion للتحكم في ما إذا كان الكائن يستجيب للدوران تلقائيًا بحيث يشير المحور السيني له في نفس الاتجاه (أو الاتجاه المعاكس) مثل متجه الظل الاتجاهي لمسار الحركة. هذه الخاصية هي مفتاح نجاح تحريك العناصر على امتداد مسار ما كما تتوقع للحركة أن تكون. مزيدًا من التوضيح في الجزئية الخاصة بشرح animationMotion. حركة رسوم SVG من الممكن أن تكون مشابهة لرسوم CSS والانتقالات عبرها حسب طبيعتيهما. مفاتيح الحركة تُضبط وبالتالي تتحرك العناصر وتتغير الألوان …إلخ. مع ذلك بإمكان رسوم SVG القيام بأمور لا تستطيع رسوم CSS القيام بها وهذا ما سنتطرق له لاحقًا. لماذا قد تستخدم الرسوم المُتجهة (SVG Animation)؟ من الممكن تصميم وتحريك الرسوم المتجهة (SVG) باستخدام CSS. بشكل أساسي التأثيرات الحركية التي تطبق على عناصر HTML من الممكن أيضًا تطبيقها على عناصر SVG. ولكن هناك بعض الخصائص التي يمكن تطبيقها على SVG ليست فعالة على CSS. مسار SVG على سبيل المثال يأتي مع مجموعة من البيانات (d=""‎ خاصية HTML) التي تعطي للمسار شكلًا. تلك البيانات يمكن تعريفها وتحريكها خلال SMIL ولكن الأمر لا ينطبق على CSS. ذلك لأن عناصر SVG تتصف بمجموعة من خاصيات HTML تُعرف بخاصيات للعرض. بعض تلك الخاصيات من الممكن معايرتها والتحكم فيها وتحريكها باستخدام CSS وهذا لا ينطبق على الخاصيات جميعها. وهكذا ترى أن العديد من تأثيرات الحركة يمكن تطبيقها حاليًا باستخدام CSS. وأما الفجوات في استخدام SVG CSS من الممكن تجاوزها عند استخدام JavaScript أو SVG المستمدة من SMIL. إذا كنت تفضل استخدام JavaScript فيستحسن أن تجرب snap.svg بواسطة Dmitry Baranovsky الذي يعد كمكتبة حافلة بالكثير من النصوص البرمجية الخاصة بـ SVG. ويمكنك الاطلاع على العديد من الأمثلة على ذلك. أما إذا كنت تفضل الخوض في مسار تعريفي أكثر بإمكانك استخدام عناصر التحريك التي سيتطرق لها هذا الدليل. ميزة أخرى تميز SMIL عن JS هي أن رسوم JS لا تعمل عند تضمين رسوم SVG كصور img أو استعمالها كصورة خلفية (background-image) في CSS. رسوم SMIL تعمل في كلا الحالتين أو هكذا ينبغي. وهذه ميزة عظيمة. لربما ستجد نفسك قد اخترت SMIL عن غيرها من الخيارات بسبب تلك الميزة. ومن هنا فهذا الدليل سيؤدي دور المساعد لتتعلم كيف تستخدم SMIL بدءًا من اليوم. دعم المتصفح والنسخ الاحتياطية دعم المتصفح لرسوم SMIL لائق للغاية. حيث أنه يعمل في جميع المتصفحات باستثناء Internet Explorer و Opera Mini. للحصول على نظرة شاملة حول دعم المتصفح، يمكنك الرجوع إلى جدول التوافق. إذا كنت بحاجة إلى توفير نسخة احتياطية لحركة الرسوم لـ SMIL، يمكنك اختبار دعم المتصفح أثناء التنقل باستخدام Modernizr. إذا لم يكن SMIL مدعومًا ، فيمكنك تقديم نوع من الاستعاضة (رسوم JavaScript متحركة، تجربة بديلة، …إلخ). تحديد الهدف من الحركة باستخدام xlink: href بغض النظر عن أي من عناصر التحريك الأربعة التي تختارها، فأنت بحاجة إلى تحديد هدف الحركة المحدد بواسطة هذا العنصر. لتحديد الهدف يمكنك استخدام خاصية xlink: href. تعطي خاصية HTML هذه مرجع URI للعنصر المستهدف في التحريك والذي سيجري تعديله بمرور الوقت. يجب أن يكون العنصر المستهدف جزءًا من مستند SVG الحالي. <rect id="cool_shape" ... /> <animate xlink:href="#cool_shape" ... /> إذا واجهت عناصر التحريك في SVG من قبل، فمن المحتمل أنك رأيتها متداخلة مع العنصر المفترض تحريكه. هذا ممكن تبعًا لمحددات: إذا لم تتوفر خاصية xlink: hrefHTML، فسيكون العنصر المستهدف هو العنصر الأصل المباشر لعنصر الحركة الحالي. <rect id="cool_shape" ... > <animate ... /> </rect> لذلك إذا كنت تريد "تضمين" الرسم المتحرك في العنصر الذي ينطبق عليه، فبإمكانك القيام بذلك. وإذا كنت تريد أن تبقي الرسم المتحرك منفصل في مكان آخر في المستند، فيمكنك القيام بذلك أيضًا، وحدّد الهدف من كل حركة باستخدام xlink: href. كلا الطريقتين تعملان بشكل جيد. تحديد الخاصية المستهدفة للحركة باستخدام attributeName وattributeType تشترك جميع عناصر التحريك أيضًا في خاصية HTML أخرى وهي attributeName. تُستخدم attributeName لتحديد اسم خاصية HTML التي تقوم بتحريكها. على سبيل المثال، إذا كنت ترغب في تحريك موضع مركز الدائرة <circle> على المحور السيني (x-axis)، حدد cx كقيمة لخاصية attributeName. تأخذ attributeName قيمة واحدة فقط، ولا تقبل قيم متعددة، لذلك يمكنك تنشيط خاصية HTML واحدة فقط في كل مرة. إذا كنت ترغب في تحريك أكثر من خاصية HTML واحدة فأنت بحاجة إلى تعريف أكثر من تحريك واحد للعنصر. لربما لا توجد طريقة أخرى ولهذا لـ CSS أفضلية عن SMIL. ولكن مرة أخرى، نظرًا للقيم المحتملة لخاصيات الحركة الأخرى (والتي سنتطرق لها بعد ذلك)، فمن المنطقي تحديد اسم خاصية HTML واحد فقط في المرة الواحدة، وإلا فقد تصبح قيم الخاصيات الأخرى معقدة للغاية بحيث لا يمكن التعامل معها. عند تحديد اسم خاصية HTML، يمكنك إضافة البادئة XMLNS (اختصار namespace XML) للإشارة إلى مجال اسم خاصية HTML. يمكن أيضًا تحديد مجال الاسم باستخدام الخاصية attributeType. على سبيل المثال، تعد بعض الخاصيات جزءًا من مساحة اسم CSS (مما يعني أنه يمكن العثور عليها كخاصية CSS أيضًا) والبعض الآخر XML فقط. يمكن العثور على جدول يوضح هذه الخاصيات هنا. خاصيات HTML في الجدول ليست كلها من خاصيات SVG إنها فقط تلك التي يمكن ضبطها باستخدام CSS. بعضها متاح بالفعل كخصائص CSS. إذا لم تُعيّن قيمة attributeType بشكل صريح أو عُيّنت على "تلقائي"auto، يجب أن يبحث المتصفح أولاً من خلال قائمة خصائص CSS عن اسم خاصية مطابق، وإذا لم يُعثر على أي منهما سيبحث في مجال اسم XML الافتراضية للعنصر. على سبيل المثال، يوضح المقتطف التالي التحكم في تحريك شفافية مستطيل SVG. نظرًا لأن خاصية HTML للشفافية opacity متوفرة أيضًا كخاصية CSS، تُعين attributeType على مجال اسم CSS: <rect> <animate attributeType="CSS" attributeName="opacity" from="1" to="0" dur="5s" repeatCount="indefinite" /> </rect> سنتجاوز خاصيات الحركة الأخرى في الأمثلة التالية أدناه. جميع خاصيات التحريك متعارف عليها ما بين جميع عناصر التحريك ما لم يذكر خلاف ذلك. تحريك خاصية HTML لعنصر من قيمة لأخرى على مدار فترة زمنية وتحديد الحالة النهائية: from وby وto وdur وfill ابدأ بتحريك دائرة من موقع إلى آخر عن طريق تغيير قيمة الخاصية cx الخاصة بها (والتي تحدد قيمة x لمركزها). عنصر <animate> سيتيح لك القيام بذلك حيث يستخدم لتحريك خاصية واحدة في كل مرة. عادةً ما تتحرك الخاصيات التي تأخذ قيم رقمية ولونية باستخدام هذا العنصر. تفقد الجدول للتعرف على الخاصيات التي يمكن تحريكها. للتغيير من قيمة إلى أخرى خلال فترة زمنية يمكنك استخدام الخاصيات From وto وdur. ستحتاج أيضًأ إلى تحديد بداية الحركة عن طريق خاصية begin. <circle id="my-circle" r="30" cx="50" cy="50" fill="orange" /> <animate xlink:href="#my-circle" attributeName="cx" from="50" to="450" dur="1s" begin="click" fill="freeze" /> يوضح المثال السابق طريقة تعريف دائرة وتحريكها من مركزها من الموضع الأولي عند 50 وحدة ثم إلى الموضع الجديد 450 وحدة على امتداد محور السينات (x-axis). تتحدد قيمة البداية begin بالنقر click أي أن الدائرة سوف تتحرك عند النقر عليها. ويمكنك أيضًا قيمة البداية كقيمة زمنية. على سبيل المثال، تعيين القيمة "begin="0s يعني أن حركة العنصر ستبدأ بمجرد تحميل الصفحة. بإمكانك تأخير حركة العنصر عند تحديد قيمة موجبة، مثلًا "begin="2s تعني أن حركة العنصر ستبدأ بعد ثانيتين من تحميل الصفحة. الأكثر إثارةً هو أنه بإمكانك تعيين قيمة البداية begin مثل s1+click لتبدأ حركة العنصر خلال ثانية واحدة بعد النقر عليه! علاوةً على ذلك بإمكانك استخدام قيم أخرى تسمح لك بمزامنة العنصر بدون حساب المدة الزمنية وزمن التأخير للعناصر المتحركة الأخرى. ستعرف المزيد لاحقًا. خاصية dur تكافئ animation-duration في CSS. الخاصيتان from وto تشبهان الإطارين المفتاحيين (keyframes)‏ from وto في قاعدة ‎@keyframe الخاصة بـ CSS: @keyframes moveCircle { from { /* start value */ } to { /* end value */ } } أما خاصية HTML التعبئة fill (والتي تحمل نفس اسم خاصية HTML "التعبئة" التي تحدد لون العنصر لسوء الحظ) فهي تشبه خاصية وضع ملء الرسوم fill-mode property والتي تحدد ما إذا كان على العنصر أن يعود لحالته الأولية بعد انتهاء عملية التحريك. تتشابه قيم SVG مع تلك الموجودة في CSS، باستثناء اختلاف التسميات: freeze: يُعني هذا التأثير بتجميد قيمة التأثير لآخر قيمة في الفترة النشطة. يبقى التأثير مجمدًا للفترة الزمنية المتبقية في المستند أو حتى إعادة تشغيل الحركة. remove: يقوم هذا التأثير بإزالة تأثير الحركة (أي أنه لم يعُد مُطبقًا) عند انتهاء المدة النشطة للحركة. بعد انتهاء زمن الحركة لم يعد الهدف متأثرًا بالحركة ما لم يُعاد تشغيل الحركة من جديد. حاول تغيير القيم في العرض الحي المباشر لترى كيف تتأثر الحركة: تستخدم خاصية by لتعيين إزاحة نسبية للحركة. كما يوحي الاسم فبإمكانك استخدام الخاصية HTML لتحديد مقدار الإزاحة التي تريد للحركة أن تتقدم بها. يكون تأثير الخاصية by مرئيًا عند تقدمك خلال مدة الحركة في خطوات منفصلة، على غرار الطريقة المعمول بها في CSS عبر steps()‎. المكافئ لدالة steps()‎ في CSS هو "calcMode="discrete في SVG، وسنتطرق لخاصية calcMode لاحقًا في المقالة. الحالة الأخرى عندما يكون تأثير by أكثر وضوحًا عند تحديد خاصية to. سيأتي مثال على ذلك لاحقًا. وأخيرًا وليس آخرًا، تأتي by بفائدة أخرى عند العمل مع الحركة المضافة والتراكمية. إعادة تشغيل الحركة باستخدام restart قد يكون من المفيد وقف إعادة تشغيل الحركة أثناء نشاطها. للقيام بذلك تمنح SVG خاصية restart المزودة بخيارات ثلاثة: always: تمكنك من إعادة تشغيل الحركة في أي وقت حيث أنها القيمة الافتراضية. whenNotActive: يمكن إعادة تشغيل الحركة فقط عندما لا تكون نشطة (أي بعد النهاية النشطة). أما محاولات إعادة تشغيل الحركة خلال المدة النشطة فيتم تجاهلها. never: لا يمكن إعادة تشغيل العنصر لما تبقى من المدة البسيطة الحالية لحاوية الزمن. (في حالة SVG نظرًا لأن حاوية الوقت الأصلية هي جزء من مستند SVG، فلا يمكن إعادة تشغيل الحركة للفترة المتبقية من مدة المستند). تسمية الحركة ومزامنتها افترض أننا نريد تحريك موضع ولون دائرة، بحيث يتغير اللون في نهاية الحركة. بإمكانك القيام بذلك عن طريق تحديد قيمة begin لحركة تغيير اللون لتكون مساوية لمدة الحركة dur، هذه هي الطريقة التي نفعلها عادة في CSS. SMIL مع ذلك، لديها ميزة لطيفة التعامل مع الأحداث. لقد ذكرنا قبل ذلك أن الخاصية begin تقبل قيمًا مثل click + 5s. تسمى هذه القيمة "قيمة الحدث (event value)، وتتكون في هذه الحالة من مرجع حدث متبوعًا بـ "قيمة الساعة". الجزء المثير للاهتمام هنا هو تسمية الجزء الثاني: "قيمة الساعة". لماذا ليست مجرد "قيمة زمنية"؟ حسنًا، الجواب هو أنه يمكنك استخدام قيمة الساعة حرفيًا مثل "10min" أو "01:33" أي ما يعادل "دقيقة و 33 ثانية"، أو حتى "02:30:03" (ساعتان، 30 دقيقة، و 3 ثوان). في وقت كتابة هذا التقرير، لم تُطبق قيم الساعة بالكامل في أي متصفح. لذا، إذا أردنا العودة إلى العرض الحي السابق واستخدمت click + 01:30، إذا بدأ متصفح يدعمه، ستبدأ الحركة خلال دقيقة و 30 ثانية بعد النقر فوق الدائرة. نوع آخر من القيم التي يمكن أن يقبلها هو معرف رسوم متحركة أخرى يتبعها مرجع حدث. إذا كان لديك حركتان (أو أكثر) (سواء طبقت على نفس العنصر أم لا!) وتريد مزامنتهما بحيث تبدأ إحداهما نسبة إلى الأخرى، يمكنك القيام بذلك دون الحاجة إلى معرفة مدة الحركة المتبقية. على سبيل المثال، في العرض الحي التالي، يبدأ المستطيل الأزرق في التحرك لمدة ثانية واحدة بعد بدء حركة الدائرة. و ذلك عن طريق إعطاء معرف كل حركة ID، ثم استخدام هذا المعرف مع الحدث begin كما هو موضح في التعليمات البرمجية التالية: <circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" /> <rect id="blue-rectangle" width="50" height="50" x="25" y="200" fill="#0099cc"></rect> <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="5s" begin="click" fill="freeze" d="circ-anim" /> <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.begin + 1s" fill="freeze" id="rect-anim" /> البداية "begin="circ-anim.begin + 1s هي الجزء الذي يخبر المتصفح ببدء الحركة للمستطيل بعد ثانية واحدة من بداية الدائرة. تفقد العرض التوضيحي التالي: يمكنك أيضًا بدء الحركة للمستطيل بعد انتهاء حركة الدائرة باستخدام حدث النهاية end بتتبع الشيفرة التالية: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.end" fill="freeze" id="rect-anim"/> يمكنك حتى بدء تشغيله قبل نهاية حركة الدائرة باستخدام الشيفرة التالية: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.end - 3s" fill="freeze" id="rect-anim"/> تكرار الحركة باستخدام repeatCount إذا كنت ترغب في تشغيل الحركة أكثر من مرة، فيمكنك القيام بذلك باستخدام خاصية repeatCount. يمكنك تحديد عدد المرات التي ترغب في تكرارها، أو استخدام الكلمة المفتاحية الأساسية غير المحددة لجعلها تتكرر إلى ما لا نهاية infinite. لذلك، إذا أردنا تكرار الحركة للدائرة مرتين، ستكون الشيفرة كما يلي: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="5s" begin="click" repeatCount="2" fill="freeze" id="circ-anim" /> يمكنك التحقق من العرض الحي هنا. في المثال الحي، عين عدد التكرار ليكون 2 على الدائرة، وبشكل غير نهائي في المربع infinite. لاحظ طريقة إعادة تشغيل الحركة من القيمة الأولية from من القيمة بدلاً من القيمة التي وصلت إليها في نهاية الحركة. لسوء الحظ، لا تتضمن SMIL طريقة للرجوع إليها بين قيم البداية والنهاية مثل CSS التي تتيح لنا القيام بذلك. في CSS، تحدد خاصية اتجاه الحركة animation-direction ما إذا كانت الحركة يجب أن تنفذ بشكل معاكس على بعض أو كل الدورات أو التكرارات. Animation-direction: alternate: تعني القيمة البديلة أن عمليات تكرار دورة الحركة ذات القيم الفردية يتم تشغيلها في الاتجاه الطبيعي، وأما القيم الزوجية فتكون في اتجاه عكسي. هذا يعني أن الدورة الأولى ستكون من البداية إلى النهاية، ثم ستليها الدورة الثانية من النهاية إلى البداية، ثم الدورة الثالثة من البداية إلى النهاية، وهكذا. في SMIL للقيام بذلك، يجب عليك استخدام JavaScript لتغيير قيم الخاصيات from وto بشكل صريح. كتب جون مكبارتلاند من Big Bite Creative منشورًا لفترة من الوقت يشرح فيه كيف فعل ذلك من أجل تحريك رمز القائمة الذي عمل عليه. حل آخر هو تحديد القيمة النهائية كقيمة متوسطة ومن ثم تكون القيمة النهائية هي نفسها القيمة الأولية. على سبيل المثال، يمكنك تعيين الحركة لتبدأ من from قيمة وتنتهي بنفس القيمة مع to وكذلك باستثناء أنك تحدد ما كنت قد حددته ليكون قيمة نهائية كقيمة وسيطة بين from وto. في CSS، سنفعل ذلك باستخدام شيء مثل هذا: @keyframes example { from, to { left: 0; } 50% { left: 300px; } } المكافئ في SMIL هو استخدام خاصية values، والتي سنشرحها قريبًا. ومع ذلك، فإن الحل المذكور أعلاه قد يعمل أو لا يعمل وفقًا لنوع الحركة التي تتبعها، وما إذا كنت تقوم بسلسلة الحركة أم لا، أو تكرارها، أو القيام برسوم متحركة إضافية. إليكم رسمًا جميلًا بسيطًا من قِبل Miles Elam يستخدم فيه بعض أوقات البدء المتأخرة: تقييد وقت التكرار باستخدام repeatDur قد تصبح حركة العنصر المستمرة مزعجة أو غير متآلفة مع الاستخدام في حالة استمرار الحركة لفترة طويلة. لذلك، قد يكون من الجيد ضبط وقت التكرار على فترة زمنية معينة، وإيقاف التكرار بعد مرور بعض الوقت بالنسبة لبداية المستند. هذا هو المعروف باسم وقت العرض. يشير وقت العرض التقديمي إلى أن الموضع في الخط الزمني بالنسبة للمستند يبدأ من جزء معين. يُحدد باستخدام خاصية repeatDur. يشبه بناء الجملة الخاص بقيمة الساعة، ولكن بدلاً من أن يكون متصلاً بحدث حركة آخر أو حدث تفاعلي، فهو يتعلق ببداية المستند. على سبيل المثال، ستؤدي الشيفرة التالية إلى إيقاف تكرار الحركة لمدة دقيقة و 30 ثانية بعد بدء المستند: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="2s" begin="0s" repeatCount="indefinite" repeatDur="01:30" fill="freeze" id="circ-anim" /> وهنا تستطيع مشاهدة العرض الحي: مزامنة الحركة على أساس عدد التكرارات الآن لنرجع خطوة إلى المزامنة بين موضوعين في التحريك. في الواقع، في SMIL يمكنك مزامنة الحركة بحيث تبدأ حركة إحداهما بناء على عدد تكرار حركة الأخرى. على سبيل المثال، يمكنك بدء رسم متحرك بعد تكرار رقم آخر، بإضافة أو طرح مقدار الوقت الذي قد ترغب في إضافته. المثال التالي يبدأ في تحريك للمستطيل في التكرار الثاني لحركة الدائرة: <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="circ-anim.repeat(2)" fill="freeze" id="rect-anim" /> يوضح العرض التالي بداية حركة المستطيل بعد ثانيتين من ثاني تكرار لحركة الدائرة: يمكنك الاطلاع على نموذج لأساسيات SVG بإصدارها الثاني من إعداد David Eisenberg. التحكم في قيم الإطارات المفتاحية للحركة: keyTimes وvalues في CSS يمكننا تحديد القيم التي نريد أن تأخذها حركة الرسوم الخاصة بنا في إطار معين أثناء التحريك. على سبيل المثال، إذا كنت تحرك العنصر بإزاحة لليساربدلًا من تنشيطه من 0 إلى 300 مثلاً، يمكنك تحريكه بحيث يأخذ قيمًا معينة مثل هذا: @keyframes example { 0% { left: 0; } 50% { left: 320px; } 80% { left: 270px; } 100% { left: 300px; } } الإطارات 0٪ و 20٪ و 80٪ و 100٪ هي إطارات الحركة، والقيم الموجودة في كل إطار تحدد قيمته. التأثير الموصوف أعلاه هو أحد العناصر التي ترتد عن الحائط، ثم تعود إلى الموضع النهائي. في SMIL، يمكنك التحكم في القيم لكل إطار بطريقة مماثلة، لكن بناء الشيفرة مختلف تمامًا. لتحديد إطارات مفتاحية، يمكنك استخدام خاصية keyTimes ثم لتحديد قيمة الخاصية المتحركة لكل إطار، يمكنك استخدام خاصية values. اصطلاحات التسمية في SMIL مريحة للغاية. إذا أردنا العودة إلى الدائرة المتحركة التي رافقتنا في الأمثلة السابقة، واستخدمنا قيمًا مماثلة لتلك الموجودة في إطارات CSS الأساسية أعلاه، فإن الشيفرة سيبدو كما يلي: <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="2s" begin="click" values="50; 490; 350; 450" keyTimes="0; 0.5; 0.8; 1" fill="freeze" id="circ-anim" /> إذن ماذا فعلنا هناك؟ أول ما يجب ملاحظته هنا هو تحديد أوقات الإطار الرئيسي والقيم الوسيطة كقوائم. خاصية keyTimes هي قائمة مفصولة بفواصل منقوطة لقيم الوقت المستخدمة للتحكم في سرعة الحركة. في كل مرة في القائمة يتوافق مع قيمة في قائمة خاصية values، ويحدد متى تُستخدم القيمة في وظيفة التحريك. تُحدد كل قيمة زمنية في قائمة keyTimes كقيمة نقطة عائمة بين 0 و 1 (ضمنًا)، مما يمثل إزاحة متناسبة في المدة البسيطة لعنصر الحركة. لذا تشبه أوقات المفاتيح تلك الموجودة في CSS، إلا أنه بدلًا من تحديدها كنسب مئوية، فإنك تحددها ككسر. ما يلي هو العرض الحي للشيفرة أعلاه. انقر على الدائرة لبدء الحركة. لاحظ أنه إذا استخدمت قائمةvalues، فإن الحركة ستطبق القيم بالترتيب على مدار فترة الحركة. إذا حددت قائمة values، فسيتم تجاهل أي من الخاصيات from وto وby. في هذه المرحلة، تجدر الإشارة أيضًا إلى أنه يمكنك استخدام خاصية values بدون خاصية keyTimes - تنتشر القيم تلقائيًا بالتساوي خلال الوقت لكل قيمة calcMode بخلاف paced (راجع القسم التالي). التحكم في سرعة الحركة باستخدام التخفيف المخصص: calcMode و keySplines سنتطرق إلى موازنة CSS-SMIL مرة أخرى لأن بناء SMIL ومفاهيمه سيكون أسهل بكثير لفهم ما إذا كنت ستعتاد بالفعل على التحريك بواسطة CSS. في CSS، يمكنك اختيار تغيير سرعة الحركة الافتراضية الموحدة وتحديد وظيفة تخفيف مخصصة تتحكم في الحركة، باستخدام خاصية animation-timing-function. يمكن أن تكون وظيفة التوقيت واحدة من الكلمات المفتاحية المحددة مسبقًا، أو وظيفة مكعب cubic bezier. يمكن إنشاء ذلك باستخدام أداة مثل هذه المعدة بواسطة Lea Verou. في SMIL، تُحدد سرعة الحركة باستخدام خاصية calcMode. سرعة الحركة الافتراضية هي linear لجميع عناصر الحركة باستثناء animateMotion (سنصل إليها لاحقًا في المقالة). بالإضافة إلى قيمة linear، يمكنك تعيين القيمة إلى: discrete أوpaced أوspline. discrete: تحدد أن وظيفة الحركة ستقفز من قيمة إلى أخرى دون أي تقاطع. هذا مشابه للدالة steps()‎ في CSS. paced: يشبه linear، إلا أنه سيتجاهل أي أوقات تقدم وسطية تحددها keyTimes. ويحسب المسافة بين القيم اللاحقة ويقسم الوقت وفقًا لذلك. إذا كانت قيمك كلها بترتيب خطي linear، فلن تلاحظ الفرق. ولكن إذا كانت ذهابًا وإيابًا، أو إذا كانت ألوانًا (والتي يعامل معها كقيم متجه ثلاثي الأبعاد)، فسترى بالتأكيد القيم الوسيطة. فيما يلي عرض حي من Amelia Bellamy-Royds، يُظهر الفرق بين قيم calcMode الثلاث المذكورة حتى الآن: spline: وهي القيمة الرابعة المقبولة بواسطة calcMode. يتشابك من قيمة واحدة في قائمة values إلى القيمة التالية وفقًا لوظيفة الوقت المحددة بواسطة cubic Bezier spline. تعرف نقاط الشريحة في خاصية keyTimes، وتحددد نقاط التحكم لكل فاصل زمني في خاصية keySplines. ربما لاحظت الخاصية HTML الجديدة في الجملة الأخيرة: خاصية keySplines. لذا، ماذا تفعل خاصية keySplines؟ مرة أخرى، إلى ما يعادلها في CSS. في CSS، يمكنك تحديد سرعة الحركة داخل كل إطار رئيسي، بدلاً من تحديد سرعة حركة واحدة للحركة بأكملها. يمنحك هذا تحكمًا أفضل في كيفية متابعة كل حركة للإطار الرئيسي. مثال باستخدام هذه الميزة هو إنشاء تأثير ارتداد الكرة. قد تبدو الإطارات المفتاحية لذلك كما يلي: @keyframes bounce { 0% { top: 0; animation-timing-function: ease-in; } 15% { top: 200px; animation-timing-function: ease-out; } 30% { top: 70px; animation-timing-function: ease-in; } 45% { top: 200px; animation-timing-function: ease-out; } 60% { top: 120px; animation-timing-function: ease-in; } 75% { top: 200px; animation-timing-function: ease-out; } 90% { top: 170px; animation-timing-function: ease-in; } 100% { top: 200px; animation-timing-function: ease-out; } } بدلاً من تسهيل الكلمات المفتاحية، كان بإمكاننا استخدام الدالة ()cubic-bezier ذات الصلة: ease-in = cubic-bezier(0.47, 0, 0.745, 0.715) ease-out = cubic-bezier(0.39, 0.575, 0.565, 1) لنبدأ بتحديد الأوقات الرئيسية وقائمة القيم للدائرة البرتقالية لتخضع لنفس تأثير الارتداد: <animate xlink:href="#orange-circle" attributeName="cy" from="50" to="250" dur="3s" begin="click" values="50; 250; 120;250; 170; 250; 210; 250" keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1" fill="freeze" id="circ-anim" /> ستبدأ الحركة عند النقر، وستتوقف بمجرد وصولها إلى القيمة النهائية. بعد ذلك، من أجل تحديد وتيرة كل إطار رئيسي، سنضيف خاصية keySplines. تأخذ خاصية keySplines مجموعة من نقاط التحكم bezier المرتبطة بقائمة keyTimes، وتحديد وظيفة bezier المكعبة التي تتحكم في سرعة الفاصل الزمني. قيمة الخاصية HTML هي قائمة مفصولة بفواصل منقوطة لوصف نقطة التحكم. كل وصف لنقطة التحكم عبارة عن مجموعة من أربع قيم: y1 x1 x2 y2، تصف نقاط التحكم bezier لشريحة وقت واحدة. يجب أن تكون جميع القيم في النطاق من 0 إلى 1، وتستبعد الخاصية HTML ما لم تُعين calcMode على شكل spline. بدلاً من أخذ دوال cubic-bezier كقيم، تأخذ keySplines إحداثيات نقطتي التحكم المستخدمة لرسم المنحنى. يمكن رؤية نقاط التحكم في لقطة الشاشة التالية المأخوذة من أداة Lea. تعرض لقطة الشاشة أيضًا إحداثيات كل نقطة، كل لون بنفس لون النقطة نفسها. بالنسبة لخاصية keySplines، هذه هي القيم التي سنستخدمها لتحديد سرعة الحركة الموجودة في keyframe. يسمح SMIL بفصل هذه القيم إما بفواصل بمسافة بيضاء اختيارية أو بمسافة بيضاء فقط. قيم keyTimes التي تحدد الجزء المرتبط هي "نقاط الربط" bezier، وقيم keySplines هي نقاط التحكم. وبالتالي، يجب أن يكون هناك مجموعة واحدة أقل من نقاط التحكم من keyTimes. إذا عدنا إلى مثال الكرة المرتدة، تُعرض إحداثيات نقطة التحكم للدالتين ease-in و ease-out كما هو موضح في الصور التالية: لترجمة ذلك إلى عنصر متحرك في SVG، نحصل على الشيفرة التالي: <animate xlink:href="#orange-circle" attributeName="cy" from="50" to="250" dur="3s" begin="click" values="50; 250; 120;250; 170; 250; 210; 250" keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1" keySplines=".42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1; .42 0 1 1; 0 0 .59 1;" fill="freeze" id="circ-anim"/> وهنا تتابع العرض الحي: إذا كنت ترغب فقط في تحديد دوال التسارع (easing function) بأكملها دون أي قيم وسيطة، فلا يزال يتعين عليك تحديد الإطارات المفتاحية باستخدام خاصية keyTimes، ولكن عليك فقط تحديد إطارات المفاتيح للبداية والنهاية، وهي1 ؛ 0، وليس القيم المتوسطة values. الحركات المضافة والتراكمية: addictive وaccumulate في بعض الأحيان، من المفيد تحديد رسم متحرك يبدأ من حيث انتهت الحركة السابقة؛ أو آخر يستخدم المجموع التراكمي للحركات السابقة كقيمة للمتابعة. لذلك، يحتوي SVG على خاصيتين مناسبتين: addictive وaccumulate. افترض أن لديك عنصرًا تريد أن "يزداد" عرضه، أو خطًا تريد زيادة طوله، أو عنصرًا تريد نقله خطوة بخطوة من موضع إلى آخر، عبر خطوات منفصلة. هذه الميزة مفيدة بشكل خاص للحركة المتكررة. تمامًا مثل أي حركة أخرى، ستحدد قيم from وto. ومع ذلك، عند تعيين additive إلىsum، ستكون قيمتهما متناسبة مع القيمة الأصلية للخاصية HTML المتحركة. لذا، بالعودة إلى دائرتنا، يكون الموضع الأولي لـ cx هو 50. عندما تقوم بتعيين from = "0"‎ وto = "100"‎، فإن الصفر إذا كان في الواقع هو 50 الأصلي، و 100 هو في الواقع 50 + 100؛ بمعنى آخر، من الناحية العملية يشبه from = "50" to = "150"‎. من خلال القيام بذلك، نحصل على النتيجة التالية: هذا هو كل ما تفعله خاصية additive. إنه تحدد فقط ما إذا كان يجب أن تكون القيم from وto متناسبة مع القيمة الحالية أم لا. تأخذ الخاصية HTML واحدة من قيمتين فقط: sum وreplace. الأخير هو القيمة الافتراضية، وهذا يعني بشكل أساسي أن القيم from وtoسوف تحل محل القيم الحالية /الأصلية، والتي قد تؤدي في النهاية إلى قفزة غريبة قبل بدء الحركة. (حاول استبدال sum بـreplace في المثال أعلاه للحصول على مقارنة أفضل). ومع ذلك، ماذا لو أردنا إضافة القيم بحيث يبدأ التكرار الثاني من قيمة نهاية القيمة السابقة؟ هذا هو المكان الذي تأتي فيه خاصية accumulate. تتحكم خاصية accumulate فيما إذا كانت الحركة تراكمية أم لا. القيمة الافتراضية هي none، مما يعني أنه عند تكرار الحركة على سبيل المثال، ستبدأ من البداية. ومع ذلك، يمكنك تعيينها علىsum، والتي تحدد أن كل إعادة للتكرار بعد الأول يبني على القيمة الأخيرة للتكرار السابق. لذلك، إذا أردنا العودة إلى الحركة السابقة وتحديد accumulate = "sum"‎، فسنحصل على النتيجة المفضلة التالية: لاحظ أنه يتم تجاهل خاصية accumulate إذا كانت قيمة الخاصية HTML الهدف لا تدعم الإضافة، أو إذا كان العنصر المتحرك لا يتكرر. سيتم تجاهله أيضًا إذا عُينت وظيفة الحركة مع خاصية to فقط. تحديد نهاية الحركة باستخدام end كما أنه بإمكانك تحديد بداية حركة الرسوم فبإمكانك أيضًا تحديد نهايتها باستخدام خاصية end. على سبيل المثال، يمكنك تعيين حركة عنصر ما لتتكرر بشكل دائم ومن ثم إيقاف الحركة عند بداية حركة عنصر آخر. تأخذ خاصية end قيم شبيهة للقيم التي تأخذها begin. بإمكانك تحديد قيم مطلقة أو نسبية للوقت أو تطبيق إزاحة أو تكرار أو غيرها. فمثلًا في العرض الحي التالي تتحرك الدائرة ذات اللون البرتقالي ببطء في دورة تستمر 30 ثانية بالاتجاه الآخر لمسطح العمل. الدائرة ذات اللون الأخضر ستتحرك فقط عند النقر عليها. حركة الدائرة البرتقالية ستنتهي عند بدء حركة الدائرة الخضراء. انقر على الدائرة الخضراء وانظر كيف ستتوقف حركة الدائرة البرتقالية: يمكن تحقيق نفس التزامن للحركة عند تطبيق حركتين على نفس العنصر. على سبيل المثال، افترض تعيين حركة تغيير لون عنصر ما من قيمة لأخرى بشكل لانهائي. بعدها عند النقر على العنصر فإنه يتحرك للناحية الأخرى من مسطح العمل. والآن أوقف حركة تغيير اللون عند النقر على العنصر ومن بعدها تتوقف الحركة كليًا. تعيين فترات الحركة باستخدام قيم كلًا من begin وend في الواقع، تقبل كل من الخاصية begin وend قائمة القيم شبه المفصولة. ستتوافق كل قيمة في خاصية begin مع قيمة في خاصية end، وبالتالي تتشكل فواصل متحركة نشطة وغير نشطة. يمكنك أن تفكر في هذا على أنه يشبه سيارة متحركة، حيث تكون إطارات السيارة نشطة ومن ثم غير نشطة لفترات زمنية، اعتمادًا على ما إذا كانت السيارة تتحرك أم لا. يمكنك أيضًا إنشاء تأثير سيارة متحركة من خلال تطبيق الحركة على السيارة: أحدها يترجم السيارة أو يحركها على طول مسار يمثل أيضًا حركة مضافة وتراكمية، والأخرى تدور إطارات السيارة في فواصل يمكن مزامنتها مع عملية التحويل. مثال يوضح أوقات البدء والانتهاء المتعددة (أي الفواصل الزمنية) هو العرض الحي التالي، حيث يدور المستطيل استنادًا إلى الفواصل الزمنية المحددة، ويتغير من نشط إلى غير نشط وفقًا لذلك. (أعد تشغيل العرض الحي إذا فاتتك الحركة). لاحظ أنه في المثال أعلاه، استخدمت عنصر<animateTransform> لتدوير المستطيل حول مركزه. سنتحدث عن هذا العنصر بمزيد من التفصيل في القسم التالي أدناه. لاحظ أيضًا أنه، حتى إذا قمت بتعيين تكرار repeatCount بشكل غير نهائي indefinite، سيتجاوز من خلال قيم end ولن يتكرر بتلك الصورة النهائية. تقييد المدة النشطة لعنصر باستخدام min وmax مثلما يمكنك تقييد وقت تكرار الحركة، يمكنك أيضًا تقييد المدة النشطة الخاصة بها. تحدد خاصيات min وmax الحد الأدنى والحد الأقصى لقيمة المدة النشطة على التوالي. حيث أنها توفر لنا وسيلة للسيطرة على الحد السفلي والعلوي من فترة العنصر النشط. تأخذ كلا الخاصيتين قيمة الساعة كقيمة. بالنسبة لـ min، يحدد طول الحد الأدنى لقيمة المدة النشطة، ويقاس بالوقت الفعلي للعنصر. يجب أن تكون القيمة أكبر من أو تساوي 0، وهي القيمة الافتراضية ولا تقيد المدة النشطة على الإطلاق. بالنسبة إلىmax، تحدد قيمة الساعة طول الحد الأقصى لقيمة المدة النشطة، وتُقاس في وقت العنصر النشط. يجب أن تكون القيمة أكبر من 0. القيمة الافتراضية لـ max هي indefinite. وهذا لا يقيد المدة النشطة على الإطلاق. إذا حددت كل من الخاصيتين min وmax، فيجب أن تكون قيمة max أكبر من أو تساوي قيمة min. وإلا فسيتم تجاهل كلا الخاصيتين. ولكن ما الذي يحدد المدة النشطة لعنصر ما؟ ذكرنا مدة التكرار من قبل، بالإضافة إلى "المدة البسيطة"، وهي مدة الحركة دون أي تكرار (محدد باستخدام dur)، فكيف تعمل كل هذه الأشياء معًا؟ من الذي يتجاوز ماذا؟ ثم ماذا عن الخاصية end التي سيتم تجاوزها ومن ثم ببساطة تنتهي الحركة؟ الطريقة التي يحدث بها ذلك هي أن المتصفح سيقوم أولاً بحساب المدة النشطة بناءً على قيم dur و repeatCount وrepeatDur وend. بعد ذلك، تعمل المدة المحسوبة مقابل قيم min وmax المحددة. إذا كانت النتيجة ضمن الحدود، تكون قيمة المدة المحسوبة الأولى صحيحة ولن تتغير. وإلا قد تحدث حالتان: إذا كانت المدة الزمنية المحسوبة الأولى أكبر من قيمة max، تعرف المدة النشطة للعنصر بأنها تساوي قيمة max. إذا كانت المدة المحسوبة الأولى أقل من قيمة min، تصبح المدة النشطة للعنصر مساوية للقيمة min ويكون سلوك العنصر كما يلي: إذا كانت مدة التكرار (أو المدة البسيطة إذا لم يتكرر العنصر) للعنصر أكبر من min، يُشغل العنصر بشكل طبيعي لمدة نشطة (min مقيدة). بخلاف ذلك، يعمل العنصر بشكل طبيعي خلال مدة التكرار (أو المدة البسيطة إذا لم يتكرر العنصر) ثم يُجمد أو يختفي عتمادًا على قيمة خاصية fill. هذا يتركنا مع تساؤل عن طريقة قيام المتصفح بحساب المدة النشطة فعليًا. من أجل الإيجاز، لن نخوض في التفاصيل هنا. ولكن هناك جدول شامل للغاية في المواصفات التي تعرض التكوينات المختلفة لخصائص dur، وrepeatCount، وrepeatDor وend، ثم توضح المدة الفعلية التي ستستند إليها كل مجموعة. يمكنك التحقق من الجدول وقراءة المزيد حول هذا الموضوع في هذا القسم من المواصفات أخيرًا، إذا حدد عنصر للبدء في الحركة قبل العنصر الآخر (على سبيل المثال مع قيمة إزاحة سالبة بسيطة)، يُقاس الحد الأدنى للمدة من وقت البدء المحسوب وليس بداية الملاحظة. هذا يعني أن قيمة min قد لا يكون لها أي تأثير ملحوظ. أمثلة على <animate>: تحوير المسارات إحدى الخاصيات التي يمكن تحريكها في SMIL (ولكن ليس في CSS)هي الخاصية d (اختصار لـ data) الخاصة بـ SVG <path>‎. تحتوي الخاصية d على البيانات التي تحدد الخطوط العريضة للشكل الذي ترسمه. تتكون بيانات المسار من مجموعة من الأوامر والإحداثيات التي تخبر المتصفح عن مكان وكيفية رسم النقاط والأقواس والخطوط التي تشكل المسار النهائي. يسمح لنا تنشيط هذه الخاصية HTML بتحويل مسارات SVG وإنشاء تأثيرات ربط الأشكال. ولكن لكي تتمكن من تحوير الأشكال، يجب أن يكون لأشكال المسار البداية والنهاية وأي مسار وسطي نفس عدد الرؤوس /النقاط بالضبط، ويجب أن تظهر بنفس الترتيب. إذا لم يتطابق عدد النقاط، فلن تعمل الحركة. والسبب في ذلك هو أن تغيير الشكل يحدث فعليًا عن طريق تحريك الرؤوس، وتحريف مواقعها، لذلك إذا كانت نقطة واحدة مفقودة أو غير متطابقة، فلن تُقرب المسارات. لتحريك مسارSVG، يمكنك تحديد attributeName لتكون d، ثم اضبط قيم from وto التي تحدد أشكال البداية والنهاية، ويمكنك استخدام خاصية values لتحديد أي قيم وسيطة تريد أن يمر الشكل فيما بينها. من أجل الإيجاز، لن نخوض في تفاصيل كيفية القيام بذلك هنا. بدلًا من ذلك، يمكنك قراءة هذا المقال الممتاز من تأليف Noah Blon، إذ يشرح كيف قام بتحوير الأشكال لإنشاء حركة التحميل باستخدام <animate>. بإمكانك الاطلاع على العرض الحي للمقال: وهنا مثال آخر لتحوير الأشكال من إعداد Felix Hornoiu: يمكنك حتى تحوير قيم المسار المستخدم كـ clipping mask مثال على ذلك من إعداد Heather Buchel: الحركة على طول المسارات الافتراضية: العنصر <animateMotion> يعد عنصر<animateMotion> عنصر الحركة المفضل في SMIL. يمكنك استخدامه لنقل عنصر على طول المسار. عن طريق تحديد مسار الحركة باستخدام إحدى الطريقتين اللتين سنتطرق لهما بعد ذلك، ثم لإعداد العنصر بحيث يتحرك على طول هذا المسار. يقبل عنصر<animateMotion> نفس الخاصيات المذكورة سابقًا، بالإضافة إلى ثلاث خاصيات أخرى: keyPoints، و rotate، وpath. أيضًا، هناك اختلاف واحد فيما يتعلق بخاصية calcMode، حيث تكون القيمة الافتراضية لـ <animateMotion> هي paced، وليست linear. تحديد مسار الحركة باستخدام خاصية path تستخدم خاصية path لتحديد مسار الحركة. حيث يُعبر عنها بنفس التنسيق وتُفسر بنفس طريقة الخاصية d في العنصر path. يتمثل تأثير الحركة لمسار الحركة في إضافة مصفوفة تحويل تكميلية إلى مصفوفة التحويل الحالية للكائن المشار إليه والتي تتسبب في ترجمة على طول المحورين x و y لنظام إحداثيات المستخدم الحالي بواسطة قيم X و Y المحسوبة على زمن. بمعنى آخر، يُحسب المسار المحدد بالنسبة إلى الموضع الحالي للعنصر، باستخدام بيانات المسار لتحويل العنصر إلى موضع المسار. بالعودة إلى دائرتنا، سنقوم بتحريكها على طريق يشبه ما يلي: بإمكانك تطبيق تلك الحركة على الدائرة باستخدام الشيفرة التالي: <animateMotion xlink:href="#circle" dur="1s" begin="click" fill="freeze" path="M0,0c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3 c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7 c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5 c1.9-2.1,3.7-5.5,6.5-6.5" /> هناك أمر واحد ركزنا عليه هنا: الإحداثيات في بيانات المسار. يبدأ المسار عن طريق تحريك (M) إلى النقطة مع الإحداثيات (0، 0)، قبل أن يبدأ في رسم منحنى (c) إلى نقطة أخرى. من المهم أن نلاحظ أن النقطة (0، 0) هي في الواقع موضع الدائرة، بغض النظر عن مكانها - ليست الزاوية العليا اليسرى من نظام الإحداثيات. كما ذكرنا أعلاه، فإن الإحداثيات في خاصية path تتعلق بالموضع الحالي للعنصر! نتيجة الشيفرة أعلاه هي: إذا كنت ترغب في تحديد المسار الذي يبدأ من نقطة أخرى غير (0، 0)، ستقفز الدائرة فجأة بالمقدار المحدد في نقطة البداية. على سبيل المثال، افترض أنك رسمت مسارًا في Illustrator ثم قمت بتصدير بيانات المسار لاستخدامها كمسار حركة (هذا ما فعلته في المرة الأولى التي قمت فيها بهذا)؛ قد يبدو المسار المُصدّر كالتالي: <path fill="none" stroke="#000000" stroke-miterlimit="10" d="M100.4,102.2c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3 c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7 c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5 c1.9-2.1,3.7-5.5,6.5-6.5"/> نقطة بداية المسار في هذه الحالة هي (100.4، 102.2). إذا أردنا استخدام هذه البيانات كمسار للحركة، ستقفز الدائرة بمقدار 100 وحدة تقريبًا إلى اليمين و102 وحدة تقريبًا لأسفل، ثم تبدأ الحركة على طول المسار بالنسبة للموضع الجديد. لذلك، تأكد من وضع ذلك في الاعتبار عند إعداد مسار الحركة للحركة الخاصة بك. في حالة استخدامها، تحدد الخاصيات from وby وto وvalues شكلًا على مساحة العمل الحالية التي تمثل مسار الحركة. تحديد مسار الحركة باستخدام عنصر <mpath> هناك أيضًا طريقة أخرى يمكنك من خلالها تحديد مسار الحركة. بدلًا من استخدام خاصية HTML المسار النسبي path، يمكنك الرجوع إلى مسار خارجي باستخدام عنصر <mpath> التابع لعنصر <animateMotion>، والذي يشير إلى المسار الخارجي باستخدام الخاصية xlink: href. <animateMotion xlink:href="#circle" dur="1s" begin="click" fill="freeze"> <mpath xlink:href="#motionPath" /> </animateMotion> يمكن تحديد مسار الحركة <path> في أي مكان في المستند؛ يمكن تعريفه حرفيًا فقط داخل عنصر <defs> ولا يُعرض على سطح العمل على الإطلاق. في المثال التالي، المسار ظاهر وواضح لأنه في معظم الحالات قد ترغب في إظهار المسار الذي يتحرك فيه العنصر. لاحظ أنه، وفقا للمواصفات: مرة أخرى، "يتضاعف" موضع الدائرة أو "يتحول" بواسطة الإحداثيات في بيانات المسار. في المثال التالي، لدينا مسار في منتصف اللوحة. تُوضع الدائرة في بداية المسار. ومع ذلك، عند تطبيق مسار الحركة، لا تبدأ الدائرة حركتها من موضعها الحالي. تفقد العرض الحي للحصول على شرح أفضل. انقر على الدائرة لتحريكها. انظر كيف تتبع الدائرة نفس شكل المسار، ولكن على موضع مختلف؟ هذا يرجع إلى حقيقة أن موضع الدائرة يُحول بواسطة قيم بيانات المسار. تتمثل إحدى طرق الالتفاف حول ذلك في البدء بوضع الدائرة في (0، 0)، بحيث عند استخدام بيانات المسار لتحويلها، ستبدأ وتستمر كما هو متوقع. هناك طريقة أخرى تتمثل في تطبيق تحويل "يعيد تعيين" إحداثيات الدائرة بحيث تُحسب على الصفر قبل تطبيق المسار. فيما يلي نسخة معدلة من العرض الحي أعلاه، وذلك باستخدام مسار مغلق وتكرار الحركة بشكل غير نهائي. تجاوز القواعد لـ <animateMotion> نظرًا لوجود أكثر من طريقة واحدة لفعل نفس الشيء مع animateMotion، فمن المنطقي أن يكون هناك قواعد تجاوز لتحديد القيم التي تتجاوز القيم الأخرى. قواعد التجاوز لـ animateMotion كالتالي: فيما يتعلق بتعريف مسار الحركة، يتجاوز عنصر mpath خاصية path، التي تتجاوز values، والتي بدورها تتجاوز from وby وto. فيما يتعلق بتحديد النقاط التي تتوافق مع خاصيات keyTimes، فإن مسارkeyPoints يتخطى path، والذي يتجاوز values، والذي بدوره يتخطى from وby وto. تحديد اتجاه عنصر على طول مسار الحركة باستخدام rotate في المثال السابق، حدث أن العنصر الذي كنا نتحرك فيه على طول المسار هو دائرة. ولكن ماذا لو كنا نحرك عنصرًا له اتجاه معين، على سبيل المثال، رمز سيارة؟ رمز السيارة في المثال التالي من إعداد Freepik. في هذا المثال، استبدلت الدائرة بمعرف "السيارة"، الذي يحتوي على العنصر الذي يُكون المجموعة. بعد ذلك، من أجل تجنب مشكلة الحركة على طول المسار المذكور أعلاه، ثم تطبيق تحويل على السيارة بحيث يترجمها بمقدار معين، بحيث ينتهي الموضع الأولي عند (0، 0). القيم الموجودة داخل التحويلات هي في الواقع إحداثيات النقطة التي يبدأ فيها رسم المسار الأول للسيارة (مباشرة بعد أمر النقل M). ثم تبدأ السيارة تتحرك على طول مسار الحركة. لكن… هكذا تبدو الحركة: اتجاه السيارة ثابت، ولا يتغير لمطابقة مسار الحركة. لتغيير ذلك، سنستخدم خاصية rotate. تأخذ خاصية rotate إحدى القيم الثلاث: auto: تشير إلى أن الكائن يدور بمرور الوقت بزاوية الاتجاه (أي متجه الظل الاتجاهي) لمسار الحركة. auto-reverse: تشير إلى أن الكائن يدور بمرور الوقت بزاوية الاتجاه (أي متجه الظل الاتجاهي) لمسار الحركة بإضافة 180 درجة. رقم: يشير إلى أن العنصر الهدف يحتوي على تحويل دوران ثابت مطبق عليه، حيث تكون زاوية الدوران هي العدد المحدد من الدرجات. لإصلاح اتجاه السيارة في المثال أعلاه، سنبدأ بتعيين قيمة الدوران على auto. سننتهي بالنتيجة التالية: أما في حال أردت تدوير السيارة خارج المسار، قيمة auto-revesre ستتكفل بذلك. يبدو هذا أفضل، لكن لا تزال لدينا مشكلة واحدة وهي أن السيارة تبدو وكأنها تتحرك للخلف على طول المسار! لتغيير ذلك، نحتاج إلى قلب السيارة على طول محورها y. يمكن القيام بذلك عن طريق تحجيمه بعامل "-1" على طول هذا المحور. لذلك، إذا طبقنا التحويل على g باستخدام معرف السيارة car، فستتحرك السيارة للأمام كما هو متوقع. سيرتبط التحجيم مع الترجمة السابقة التي طبقناها سابقًا. <g id="car" transform="scale (-1, 1) translate(-234.4, -182.8)"> وبالتالي، ستكون النتيجة كما هي موضحة في العرض: التحكم في مسافة الحركة على طول مسار الحركة باستخدام keyPoints توفر خاصية keyPoints القدرة على تحديد التقدم على طول مسار الحركة لكل من قيم keyTimes المحددة. إذا حددت ذلك، فإن keyPoints تؤدي إلى تطبيق keyTimes على القيم الموجودة في keyPoints بدلاً من النقاط المحددة في خاصية values أو النقاط الموجودة في خاصية path. تأخذ keyPoints قائمة مفصولة بفواصل منقوطة لقيم الفاصلة العائمة بين 0 و 1 وتشير إلى مدى طول مسار الحركة التي يجب أن يتحرك فيها الكائن في الوقت المحدد بواسطة قيمة keyTimes المقابلة. تُحدد الحسابات عن بعد من خلال خوارزميات المتصفح. تقابل كل قيمة تقدم في القائمة قيمة في قائمة خاصية keyTimes. عند تحديد قائمة نقاط KeyPoints، يجب أن يكون هناك بالضبط العديد من القيم في قائمة keyPoints كما هو الحال في قائمة keyTimes. أحد الأشياء المهمة التي يجب ملاحظتها هنا هو ضبط قيمة calcMode على linear لكي تعمل KeyPoints. يبدو أيضًا أنه يجب أن يعمل بشكل منطقي مع الحركة، إذا كانت النقاط الرئيسية تتحرك ذهابًا وإيابًا، لكنها لا تعمل. فيما يلي مثال من إعداد Amelia Bellamy-Royds (تفقد صفحتها الشخصية) توضح فيه استخدام keyPoints لتقليد السلوك فتبدأ الحركة على مسار من إزاحة محددة مسبقًا، لأننا لا نملك هذه القدرة حاليًا بشكل افتراضي في SMIL. تحريك النص على طول مسار افتراضي يختلف نقل النص عبر مسار افتراضي عن نقل عناصر SVG الأخرى عبر المسارات. لتحريك النص، سيتعين عليك استخدام عنصر <animation>، وليس عنصر <animateMotion>. أولاً، لنبدأ بوضع النص على طول المسار. يمكن القيام بذلك عن طريق تداخل عنصر<textPath> داخل عنصر <text>. سيتحدد النص الذي سيوضع على طول مسار داخل عنصر<textPath>، وليس كتابع لعنصر<text>. ستقوم textPath بعد ذلك بالإشارة إلى المسار الفعلي المراد استخدامه، تمامًا كما فعلنا في الأمثلة السابقة. يمكن أيضًا تقديم المسار المشار إليه على مسطح العمل أو تعريفه داخل <defs>. تحقق من الشيفرة في العرض الحي التالي: لتحريك النص على طول هذا المسار، سنستخدم العنصر <animate> لتحريك خاصية startOffset. تمثل startOffset إزاحة النص على المسار. 0٪ هي بداية المسار؛ 100 ٪ تمثل نهايته. لذلك، على سبيل المثال، إذا ضبطت الإزاحة على 50٪، فسيبدأ النص في منتصف المسار. ومن هنا ستتضح الأمور للذهاب قدمًا. عن طريق تنشيط startOffset، سنقوم بإنشاء تأثير نقل النص على طول المسار. تحقق من الشيفرة في العرض الحي التالي. تحولات الحركة: عنصر <animateTransform> ينقل عنصر <animateTransform> خاصية HTML تحويل على عنصر مستهدف، مما يسمح للحركة بالتحكم في التحوير والتحجيم و/أو التدوير و/أو الربط. يستغرق نفس الخصائص المذكورة للعنصر <animation>، بالإضافة إلى خاصية HTML إضافية: type. تستخدم خاصية type لتحديد نوع التحويل الذي تُطبق الحركة عليه. وتأخذ أحد القيم الخمسة: translate وscale وrotate وskewX وskewY. تأخذ الخاصيات from وby وto قيم يعبّرعنها باستخدام تركيب الجملة نفسه المتاح لنوع التحويل المحدد: بالنسبة لـ"type="translate، يُعبر عن كل قيمة فردية كـ [<tx> [,<ty> بالنسبة لـ "type="scale، يُعبر عن كل قيمة فردية كـ [<sx> [,<sy> بالنسبة لـ "type="rotate، يُعبر عن كل قيمة فردية كـ[<rotate-angle> [<cx> <cy> بالنسبة لـ "type="skewX و"type="skewY، يُعبر عن كل قيمة فردية كـ <skew-angle> إذا لم تكن معتادًا على بناء جملة SVG لخاصية transform، ومن أجل إيجاز هذه المقالة، ولأن تفاصيل بناء الجملة وكيفية التعامل معها خارج نطاقها، بإمكانك قراءة مقال فهم أنظمة تنسيق SVG والتحولات (الجزء 2): خاصية HTML التحويل، قبل الانتقال إلى هذا الدليل. بالعودة إلى العرض الحي السابق، حيث قمنا بتدوير المستطيل الوردي باستخدام عنصر <animateTransform>. تبدو شيفرة الدوران كما يلي: <rect id="deepPink-rectangle" width="50" height="50" x="50" y="50" fill="deepPink" /> <animateTransform xlink:href="#deepPink-rectangle" attributeName="transform" attributeType="XML" type="rotate" from="0 75 75" to="360 75 75" dur="2s" begin="0s" repeatCount="indefinite" fill="freeze" /> تحدد خاصيات from وto زاوية الدوران (البداية والنهاية) ومركز الدوران. في كليهما، يبقى مركز الدوران كما هو بالطبع. إذا لم تُحدد المركز، فسيكون ذلك هو الركن العلوي الأيسر من سطح العمل SVG. العرض الحي للرمز أعلاه هو ما يلي: هنا مثال آخر ممتع لـ animateTransform من إعداد Gabriel: إن تنشيط عملية تحويل واحدة أمر بسيط، ومع ذلك، يمكن أن تصبح الأمور فوضوية ومعقدة حقًا عند تضمين تحويلات متعددة، خاصة لأن أحد تحويلات الحركة animateTransform يمكنه تجاوز الآخر، لذلك بدلاً من إضافة التأثيرات وتسلسلها، قد ينتهي بك الأمر على العكس تمامًا. هذا بالإضافة إلى طريقة تنسيق SVG للأنظمة والتحولات في الواقع (راجع المقالة المذكورة سابقًا حول الموضوع). الأمثلة واسعة، وخارج نطاق هذه المقالة. لتحويل SVGs، يوصى باستخدام تحويلات CSS. تعمل التطبيقات على جعل هذا الأخير يعمل بشكل مثالي مع SVG، لذلك قد لا تضطر أبدًا إلى استخدام SMIL لتنشيط التحويلات في SVG على الإطلاق. عنصر <set> يوفر عنصر set وسيلة بسيطة لتعيين قيمة الخاصية HTML لمدة محددة. يدعم جميع أنواع الخاصيات، بما في ذلك الأنواع التي لا يمكن تحريفها بشكل معقول، مثل قيم السلسلة والقيمة المنطقية. عنصر set غير مضاف ولا يُسمح بالخاصيات المضافة والإجمالية، وسيتم تجاهلها عند تحديدها. نظرًا لاستخدام <set> لتعيين عنصر إلى قيمة محددة في وقت معين، فإنه لا يقبل جميع الخاصيات المذكورة لعناصر التحريك السابقة. على سبيل المثال، لا يحتوي على خاصية from أو by، لأن القيمة التي تتغير لا تتغير تدريجيًا خلال الفترة الزمنية. بالنسبة لـ set، يمكنك تحديد العنصر الذي تستهدفه، واسم الخاصية HTML ونوعها، وقيمة to، ويمكن التحكم في توقيت الحركة: begin وdur وend وmin وmax وrestart وrepeatCount وrepeatDur وfill. فيما يلي مثال يضبط لون المستطيل الدوّار إلى اللون الأزرق عند النقر فوقه. يظل اللون أزرق لمدة 3 ثوانٍ، ثم يعود إلى اللون الأصلي. في كل مرة ينفر فوق المستطيل، تعمل حركة set، ويتغير اللون لمدة ثلاث ثوانٍ. العناصر وخاصيات HTML وخاصيات الكائنات التي يمكن تحريكها لا يمكن تحريك كل خاصيات SVG، ولا يمكن تحريك كل الخاصيات التي يمكن تحريكها باستخدام جميع عناصر التحريك. للحصول على قائمة كاملة بجميع الخاصيات المتحركة، وجدول يربط الخاصيات بالعناصر التي تحركها، يرجى الرجوع إلى هذا القسم من مواصفات SVG Animation. أخيرًا لدى SMIL الكثير من الإمكانيات، وبالكاد تعرض المقال لمعلومات سطحية جدًا ولم يتطرق إلا إلى الأساسيات والتقنيات الخاصة بكيفية عملها فيSVG. يمكن إنشاء الكثير من التأثيرات المؤثرة للغاية، خاصة تلك التي تنطوي على تحوير الأشكال وتحويلها. لتكن حدودك هي السماء؛ عليك أن تكمل أنت الآن فامض بشغف! ولا تنس مشاركة ما تصنعه مع الآخرين. شكرًا لقراءتك! ترجمة وبتصرف للمقال A Guide to SVG Animations (SMIL)‎ لصاحبته Sara Soueidan
  5. يتضمن العمل مع أشكال SVG (الرسوميات المتجهية متغيرة الحجم) في سير عمل تصميم الويب المتجاوب مرحلة تصميم ومرحلة تطوير. يتعامل المصممون عادةً مع مرحلة التصميم وقد يعرفون أو لايعرفون كيفية كتابة الشيفرة. ونظرًا لطبيعة SVG كتنسيق صورة وتنسيق مستند معًا، فإنّ كل خطوة تتم في محرر الرسومات أثناء عملية إنشاء SVG تؤثر بشكلٍ مباشر على الشيفرة الناتجة وبالتالي على عمل المطور المسؤول عن تضمين SVG أو كتابته كنص برمجي أو تحريكه. عادةً، خلال عملي اليومي أنا المطور الذي يسلّم المصممون له أصول التصميم، وصور SVG هي جزء من هذه الأصول. احتاجت معظم الأصول التي تم تسليمها في مشاريعي السابقة إلى المزيد من العمل و/أو جولة ثانية من التحرير في محرر الرسومات قبل أن أتمكن من كتابتها كنصوص برمجية، لأنّ شيفرة SVG الناتجة لم تُحسَّن بما فيه الكفاية لنوع العمل - خاصةً الرسوم المتحركة - التي تم استئجاري للقيام بها. سبب ذلك هو أنّ العديد من المصممين الذين عملت معهم يعرفون القليل جدًا - إن كانوا يعرفون - عن شيفرة SVG. ينشؤون رسوميات متجهة وأصول واجهة المستخدم كل الوقت، لكن بالنسبة لهم فإنّ SVG ليس سوى تنسيق صورة ولا يعرفون الكثير عن الشيفرة المتولّدة عند تصدير أصولهم كمستندات SVG. هناك بعض الخطوات التي يمكن للمصممين اتخاذها أو تجنبها - مجموعة من "افعل ولا تفعل" - يمكن أن تساعد في جعل الشيفرة المتولدة أنظف. أودّ أن أشارك بعضها في هذه المقالة، إذا كنت تعرف أي شيء آخر يرجى مشاركته في التعليقات الموجودة في نهاية المقال. النصائح التي سنتحدث عنها قابلة للتطبيق في Adobe Illustrator -محرر الرسومات المفضل لي- وكذلك محررات الرسومات الأخرى. لكن بما أنني شخصيًا أستخدم AI فهذا ما سأركّز عليه خلال هذه المقالة. سنتحدث أيضًا عن خيارات تصدير SVG الحالية المتوفرة في AI وأيّ منها تختار ولماذا. لكن لاحظ أنّ هذه الخيارات ستتغير في المستقبل، وبعدها سيتم تحديث هذه المقالة لتعكس هذه التغييرات. تعتمد هذه المقالة على حديثي "SVG لمصممي ومطوري الويب" - حديث قمت به في CSSDevConf 2015 الشهر الماضي. لذا، لنبدأ. إذا كنت تستخدم برنامج Sketch لإنشاء SVG، هناك أيضًا بعض الأشياء التي يمكن أن تقوم بها لتصدير شيفرة أنظف. شارك Sean Kesterson بعض النصائح في هذه المقالة. 1- أنشئ الأشكال البسيطة باستخدام عناصر شكل بسيطة وليس عناصر <path> هناك سبب لوجود أشكال أساسية مختلفة في SVG لإنشاء أشكال أساسية بشكلٍ جيد. يمكن للشخص إنشاء أي شكل عمليًّا باستخدام عنصر <path>، أليس كذلك؟ عناصر الشكل البسيطة (<line>، <circle>، <rect>، <ellipse>، <polygon> و<polyline>) موجودة لعدة أسباب، وأحد هذه الأسباب هو أنّها سهلة القراءة وسهلة الصيانة وقابلية للتحرير باليد من بدائلها <path>. تأتي الأشكال الأساسية مع مجموعة من الخاصيات التي تسمح لك بالتحكم في ميزات الشكل، مثل الموضع (x، y، cx، cy) والأبعاد (width وheight)، بينما لا يكون لعناصر <path> مثل هذه الخاصيات. مثلًا، يعرض المقتطف التالي الاختلاف بين دائرة تم إنشاؤها وتصديرها كشكلٍ بسيط، مقابل دائرة تم إنشاؤها وتصديرها كمسار: <circle fill="#FFFFFF" stroke="#000" cx="28.1" cy="28.1" r="27.6"/> <!-- مقابل --> <path fill="#FFFFFF" stroke="#000" d="M55.7,28.1 c0,15.2-12.4,27.6-27.6,27.6 S0.5,43.3,0.5,28.1 S12.9,0.5,28.1,0.5 S55.7,12.9,55.7,28.1z"/> إذا أردت تحريك شكلك عن طريق تحريك موضع الدائرة أو تكبيرها، يمكنك القيام بذلك عن طريق تحريك موضع المركز عبر الإحداثيات x و y أي (cx وcy) ونصف قطر الدائرة (r). بينما إذا كنت تعمل مع دائرة متولدة كمسار، يجب عليك استخدام تحويلات CSS/SVG (التحريك وإعادة التحجيم) للقيام بذلك. ثمّ بفرض أردت تحريك ذلك المسار وتتطلب منك الحركة تطبيق المزيد من التحويلات، يمكن أن يصبح لديك ببساطة فوضى تحويلات. ميزة أخرى لاستخدام الأشكال البسيطة هي أنّه في معظم الحالات، الشيفرة المطلوبة لإنشاء شكل باستخدام عناصر شكل بسيطة هي أقلّ من المطلوبة لإنشاء نفس الشكل باستخدام عنصر <path> (شاهد المقتطف اعلاه للمقارنة)، لذا فإنّ استخدام أشكال بسيطة سيؤدي أيضًا إلى حجم ملف أصغر، وهذا أفضل دائمًا. 2 - حوّل النص إلى حدود خارجية..أو لا تحوّله لتحويل النص إلى حدود خارجية: اختر النص الذي تريد تحويله اختر النوع (Type) -> إنشاء حدود خارجية (Create Outlines) الإيجابيات النص المحوّل إلى حدود خارجية سيحافظ على نوع الخط المستخدم، بدون الحاجة إلى استخدام خط ويب لعرضه. هذا يعني أنك تحفظ القليل من طلبات HTTP الإضافية ولا تخاطر بعرض نصك بالخط الاحتياطي الذي لا يبدو جيدًا بشكلٍ كافٍ لاستبدال الخط الجميل الذي اخترته. يعدّ تحويل النص إلى حدود خارجية والحفاظ على نوع الخط المستخدم جيّدًا للحفاظ على هوية العلامة التجارية عندما تُعرّف بنوع خط مستخدم، مثلًا في شعار، أقوم دائمًا بتحويل نص الشعار إلى حدود خارجية وهذا جيد للحفاظ على الخط لنصوص برمجية معينة عندما تستخدم العناوين. السلبيات النص المحوّل إلى خطوط خارجية ليس نصًا حقيقيًا: إنّه مجموعة من المسارات التي تشكل الحدود الخارجية (الشكل) للنص. وبالتالي يصبح النص غير واقعي ولا يمكن الوصول إليه، وغير قابل للبحث وغير قابل للتحديد. إذا تمّ تحويل النص إلى حدود خارجية في عنوان نص برمجي أو حتى شعار، فإنّ استخدام نص alt (إذا تم تضمين الشعار كصورة) أو عناصر سهلة الوصول لـ SVG مثل (<title> و&>) هو فكرة جيدة لتوفير نص بديل لقارئات الشاشة. أوصي بشدّة بقراءة كل شيء عن جعل SVG سهل الوصول في هاتين المقالتين لـLéonie Watson: - نصائح لإنشاء SVG سهلة الوصول - استخدام ARIA لتحسين سهولة الوصول لـSVG يمكن أن يسبب تحويل النص إلى حدود خارجية زيادةً كبيرةً في حجم ملف SVG، حسب تعقيد الخط المستخدم. تُظهر الصورة أدناه الاختلاف في حجم (وسهولة القراءة) لـSVG مع النص المحوّل إلى حدود خارجية (يسار) والنص الذي يتم تصديره كـ SVG <text>‎ (يمين). لا يمكن التحكم بالمسارات أو تحريكها بسهولة مثلما يتم ذلك في عناصر <text> (المتضمنة عناصر <tspan>). إذ تحتوي الأخيرة على مجموعة من الخاصيات التي تمنحك المزيد من التحكم في رسومك المتحركة، بينما تبقى بيانات المسار محدودة بهذا الشأن. 3- تبسيط المسارات يعرَّف المسار بمجموعة من النقاط والتي بدورها يتم تحديد كلّ منها بزوج من الإحداثيات. كلّما قلّ عدد النقاط، قلّت بيانات المسار (خاصية d)، وبالتالي انخفض حجم ملف SVG الكلي. هذه الخطوة الجيدة يجب اتخاذها دائمًا لأنّ حجم الملف الأصغر أفضل للأداء. لتبسيط مسار: اختر المسار اذهب إلى كائن (Object) -> مسار (Path) -> تبسيط (Simplify) عدّل عدد النقاط. تأكّد من أن أنّك فحصت المعاينة حتى تتمكن من معرفة كيف يتغير المسار أثناء تغيّر عدد النقاط. عدّل العدد حتى تحصل على أقل عدد من النقاط أثناء المحافظة (أو التضحية) على أفضل مظهر مرئي للمسار الذي تحتاجه. يوجد فيديو تعليمي لشركة Adobe يشرح العملية، لذا إذا كنت أكثر انسجامًا مع مقاطع الفيديو، يمكنك الاطلاع عليه هنا. يمكنك أيضًا تبسيط المسارات باستخدام أداة Warp Tool. أنا لست مصممة ولكن أستخدم عادةً خوارزمية تبسيط Ai لتبسيط مساراتي، لذا إذا كنت مصممًا متمرّسًا، من المحتمل أنّك تعرف أكثر بكثير عن أداة Warp tool مني. يوجد مقال في مجلة Smashing حول هذه الأداة، يمكنك الاطلاع عليها إن أردت. 4- تجنب دمج المسارات إذا لم تكن بحاجة للتحكم في المسارات الفردية يميل العديد من المصممين إلى جمع المسارات أو دمجها كلما أمكن ذلك. لدمج المسارات: اختر الطرق التي تريد دمجها اذهب إلى نافذة (Pathfinder <- (Window اختر خيار الدمج (Merge) من بين قائمة الخيارات أسفل اللوحة (الأيقونة الثالثة من اليسار، المبينة في لقطة الشاشة أدناه). قد يكون هناك فوائدٌ لجمع المسارات، لكن تجنبها عندما تحتاج أنت أو المطور للتحكم و/أو تحريك المسارات بشكلٍ منفصل. تم تصميم بعض الرسوم المتحركة بحيث يتم تحريك عناصر متعددة بشكلٍ منفصلٍ، أو في بعض الأحيان قد تريد فقط تصميم المسارات باستخدام ألوان تعبئة مختلفة. إذا قمت بجمع المسارات، فلن يكون ذلك ممكنًا بعد الآن. تحتاج إلى التأكّد من معرفتك لما يحتاجه المطور (أو أنت إذا كنت ستتعامل مع مرحلة التطوير أيضًا) ولما يريد القيام به مع الأشكال التي تعمل عليها، واتخاذ قرار الدمج أو عدم الدمج وفقًا لذلك. هذا سيوفر لكما الكثير من الوقت والخلاف. 5- إنشاء مرشّحات باستخدم مرشّحات SVG، وليس تأثيرات Photoshop إذا كنت تستخدم المرشّحات في قسم تأثيرات Photoshop ضمن خيار تأثير، فسيقوم Illustrator بتصدير التأثيرات التي تنشؤها كصور نقطية. مثلًا، إذا قمت بإنشاء ظل إسقاط باستخدام تأثير الضبابية Blur في فوتوشوب، فإن الظلّ المسقط المتولّد سيكون صورة نقطية مضمنة داخل SVG إما مضمنة داخليًا أو خارجيًا، باستخدام عنصر <image>. أنت بالتأكيد لا تريد ذلك عند العمل مع SVG. تحتاج لتوليد مؤثراتك كشيفرة SVG إلى استخدام مرشّحات SVG المتاحة: اذهب إلى تأثير (Effect) -> مرشّحات (SVG Filters (SVG اختر واستخدم أحد المرشّحات المتاحة في اللائحة. 6- اجعل لوح الرسم (Artboard) مناسبًا لرسمتك هل قمت يومًا بتضمين SVG في صفحة، وإعطائه ارتفاعًا وعرضًا محددين ثمّ وجدت أنه كان معروضًا بحجم أصغر من الحجم الذي حددته؟ في معظم الحالات، يكون السبب في ذلك هو وجود مساحة بيضاء داخل منفذ العرض (viewport) الخاص بـ SVG. يتم عرض منفذ العرض بالحجم الذي تحدده في صفحة الأنماط (style sheet) الخاصة بك، لكن المساحة الإضافية داخلها - حول الرسم - تتسبب في "تقليص" صورتك، لأنّ هذه المساحة البيضاء تأخذ مساحةً داخل منفذ العرض. لتجنّب ذلك، تحتاج إلى التأكّد من أنَّ لوح الرسم الخاص بك كبير بما فيه الكفاية ليناسب الرسمة بداخله، ولكن ليس أكبر منها. أبعاد لوح الرسم هي أبعاد منفذ عرض SVG المصدَّر، وأي مساحة بيضاء في لوح الرسم سيتم إنشاؤها كمساحة بيضاء داخل منفذ العرض. ليتناسب لوح الرسم مع رسمتك: حدد كامل الرسمة (أنا أستخدم الاختصار cmd/ctrl + A) اذهب إلى كائن (Object) -> ألواح الرسم (Artboards) واختر الخيار تناسب مع حدود العمل الفني (Fit to Artwork Bounds option). 7- استخدم اصطلاحات تسمية، وتجميع وطبقات جيّدة أعلم أنّ هذا يبدو كأنّه غير عقلاني، لكن يجب التأكيد عليه لعدة أسباب: ستتم ترجمة معرّفات وأسماء الفئات التي تستخدمها في محرر الرسومات إلى معرّفات وأسماء الفئات في الشيفرة المتولّدة. كلّما كانت هذه الأسماء أكثر منطقيةً وأكثر وضوحًا في تصنيف العناصر الخاصة بكل منها، سيكون هناك تعارضًا أقل عندما يعمل المطوّر مع الشيفرة. أنا لا أقول الآن أنّه يجب عليك التفكير في الأسماء المثالية - أنا متأكّدة أنّه لكلّ منّا طرق مختلفة لتسمية الأشياء ويمكن أن تكون التسمية واحدة من أصعب المهام، لكن تسمية المجموعات بشكلٍ مناسب تقطع شوطًا طويلًا. مثلًا، إذا كنت ترسم سيارة، فإنّه من المناسب استخدام معرّف العجلة لتسمية الطبقة أو مجموعة تغليف الأشكال المكوّنة للعجلة. إذا كنت تقوم بتجميع كل العجلات في مجموعة واحدة، فقد تعطيها معرّف العجلات. تؤثّر الأسماء البسيطة في التعبير عن العناصر والمجموعات وتحفظ الكثير من الوقت، خاصةً إذا كان المطوّر سيحرر الشيفرة ويعالجها يدويًا. لا يقوم Illustrator بعمل أفضل في تسمية الأشياء، لذا فإنّ تحديد الأسماء يساعد في تقليل كمية المخلّفات التي ينتجها. وبالتأكيد، سيكون هناك بعض التحرير الإضافي المطلوب للتخلّص من الخطوط السفلية المزعجة التي يصرّ Ai على توليدها، لكن استخدام الأسماء الصحيحة يساعد في جعل هذه العملية أسهل قليلًا. كما ذُكر سابقًا، ستُظهر النسخة التالية من Illustrator تحسّنًا كبيرًا في طريقة توليد SVG، متضمنةً المعرّفات المتولّدة. استخدم الطبقات لتجميع العناصر ذات الصلة. تُترجم الطبقات إلى مجموعات في الشيفرة، لذا يجب تسميتها بشكلٍ جيّد أيضًا. أنشئ طبقات/مجموعات لتجميع العناصر ذات الصلة معًا، خاصةً تلك التي قد تكون متحركة بالكامل. إذا لم يتم ذلك بالفعل في مرحلة التصميم فمن الممكن قضاء الكثير من الوقت في إعادة ترتيب وتجميع العناصر يدويًا من قِبل المطوّر. تأكّد من التجميع بشكلٍ مناسب لتوفير الوقت. يُعدّ التحدّث مع المطور في مرحلة التصميم وتصميم كيفية ستُنفّذ الرسوم المتحركة معًا هما أكبر موفران للوقت. إذا كانت الصور التي تقوم بإنشائها ستُستخدم لإنشاء SVG sprite، فإنّ الأسماء التي تستخدمها يمكن أن تُستخدم وستُستخدم من قِبل معظم أدوات الأتمتة لتوليد ملفات جديدة. لذا فإنّ استخدام أسماء واضحة ومناسبة سيؤدي إلى أسماء ملفات أنظف. 8- اختر أفضل خيارات تصدير مناسبة للويب بدءًا من Illustrator CC 2015.2 الذي تمّ إصداره في تشرين الأول 2015، يوجد تدفق عمل جديد لتصدير SVG (ملف> تصدير> SVG) لتصدير ملفات SVG مُحسّنة للويب لتدفقات عمل تصميم الشاشة والويب لديك. يمكنك أيضًا أن تختار تصدير الأغراض الفردية أو كامل لوح الرسم. راجع هذه المقالة لمزيدٍ من التفاصيل. في وقت كتابة هذا المقال، يأتي Illustrator مع مجموعة من خيارات التصدير التي تسمح لك بتوليد شيفرة SVG أفضل بشكلٍ عام. لتصدير الـ SVG الخاص بك: اختر ملف (File) -> حفظ كـ (Save As) اختر SVG من القائمة المنسدلة اضغط حفظ (Save) بمجرد النقر على حفظ، سيظهر مربع حوار يحتوي على مجموعة من الخيارات التي يمكنك تخصيصها، والتي ستؤثّر على شيفرة SVG المتولّدة: الخيارات الموضّحة في الصورة أعلاه هي الخيارات المستحسنة لتوليد SVG للويب. يمكنك بالطبع اختيار تحويل النص إلى حدود خارجية إذا لم تكن ترغب باستخدام خط ويب، وكما ترى يوفر لك Illustrator خيارًا أيضًا للقيام بذلك عند التصدير. يحدد خيار موقع الصورة (Image Location) فيما إذا سيتم تضمين أي صور نقطية داخليًا في الـ SVG الخاص بك أو خارجيًا مع رابط يدلّ عليه في الـ SVG. ومجددًا، هذا يعتمد على ما تحتاجه. يمكن أن تزيد الصور المضمنة داخليًا في الـ SVG حجم الملف بشكلٍ كبيرٍ. آخر مرة أرسل مصممٌ لي SVG مع صورة مضمنة فيه، كان حجم الملف أكثر من 1 ميغابايت! بعد حذف تلك الصورة (وبسبب تأثيرات Photoshop المستخدمة المذكورة سابقًا)، انخفض حجم الملف إلى أكثر من 100 كيلو بايت! لذا، اختر بحكمة. يمنحك خيار خصائص CSS الحرية لاختيار كيف تريد إنشاء الأنماط داخل الـ SVG: استخدام خاصيات التقديم، الأنماط المضمنة داخليًا، أو داخل وسم <style>. هذا أيضًا مسألة تفضيل وتعتمد على الطريقة التي تنوي بها التعامل مع SVG بمجرد تضمينها. إذا لم تكن الشخص الذي سيفعل ذلك، فتأكد من التشاور مع المطور لتحديد الخيار الذي يناسب احتياجاته على أفضل وجه. كلّما قلّ عدد المنازل العشرية، قلّ حجم ملف SVG. يجب أن تكون منزلة عشرية واحدة كافية بشكلٍ عام، لذا سأتّبع ذلك. لاحظ أنّه إذا اخترت 3 أو 4 منازل عشرية، مثلًا، ثمّ استخدمت أداة تحسين لتحسين SVG وخفض هذا الرقم إلى 1، فقد ينتهي بك الأمر إلى SVG معطوب، لذا من الأفضل اختيار هذا الخيار في وقت مبكر. هناك المزيد في لائحة الخيارات التي قمت بتغطيتها. كتب Michaël Chaize من Adobe مقالةً ممتازةً حول لائحة التصدير توضّح ما يفعله كل خيار تمامًا. أوصي بشدّة بمراجعة مقالته: تصدير SVG للويب مع Illustrator CC الآن، في وقت كتابة هذا المقال، سيبقى Illustrator يولّد شيفرةً غير ضرورية مثل البيانات الوصفية للمحرر، والمجموعات الفارغة، من أمورٍ أخرى، لذا ستحتاج إلى تحسين الـ SVG بشكلٍ أكبر بعد تصديره، سواء كان ذلك باليد، أو باستخدام أداة تحسين SVG مستقلة. لكن قبل أن ننتقل إلى جزء التحسين، أريد أن أشير إلى أنّك قد ترغب أو لا ترغب في التحقق من خيارٍ إضافي أثناء حفظ SVG: خيار "استخدم ألواح الرسم" ، في لائحة الحفظ: يعدّ هذا الخيار مفيدًا عندما تعمل مع صور SVG متعددة (مثل الأيقونات) وتستخدم لوح رسم لكلّ أيقونة. سيؤدي تصدير ألواح رسم متعددة إلى توليد ملفات svg. متعددة، ملف لكل لوح رسم (واحد لكل أيقونة). سيتم تعطيل هذا الخيار بشكلٍ افتراضي إذا كنت تعمل مع لوح رسم واحد. يعتمد اختيار تصدير ملف SVG واحد أو عدة ملفات SVG على كيفية تضمين SVG. مثلًا، إذا كنت تريد إنشاء SVG sprite لنظام أيقونات SVG، فهناك عدة طرق يمكنك من خلالها إنشاء واستخدام الـ sprite، وكلّ منها تتطلب منهجًا مختلفًا: تتطلّب إحدى التقنيات فصل الأيقونات في البداية، بينما تتطلّب الأخرى أن تكون الأيقونات جزءًا من صورة واحدة. سأكتب منشورًا مفصّلًا حول SVG sprite وخيارات لوح الرسم، لكن حتى ذلك الحين، يمكنك أن تأخذ نظرة عامة حول التقنيات المختلفة لـ SVG sprite في المقالة التالية التي كتبتها لـ24Ways.org: نظرة عامة حول تقنيات إنشاء SVG sprite للتحسين أو لعدم التحسين يوصى عادةً بتحسين SVG بعد تصديره من محرر رسومات باستخدام أداة تحسين مستقلة. أداة التحسين الحالية الأكثر شيوعًا هي الأداة المعتمدة على NodeJS والتي تسمى SVGO. لكن قد لا يكون من الأفضل دائمًا تحسين SVG، خاصة إذا كنت تنوي تحريكه. إذا كنت تنوي كتابة SVG كنص برمجي و/أو تحريكه، فمن المحتمل أن تقوم بإعداد بنية وثيقة معينة - غلاف المجموعات، وأسماء المعرفات التي لا تستخدمها/تشير إليها داخل الـ SVG لكنك تنوي استخدامها في جافاسكربت أو غيرها. ستتغير البنية إذا قمت بتحسين الـ SVG باستخدام SVGO (أو أي أداة تحسين أخرى). عادةً ما تزيل أدوات التحسين أي مجموعات ومعرّفات غير مستخدمة، بالإضافة إلى أنّها تطبّق العديد من التغييرات على الـ SVG للتأكد من تحسينه بشكلٍ جيد. لقد قمت بتحسين ملف SVG مرةً بعد تطبيق رسم متحرك عليه باستخدام <animate>. كان ملف الـ SVG معطوبًا والحركة بداخله، لأنّه تم تغيير البنية بالكامل. وهذا شيء يجب تذكره قبل تحسين SVG. تجنّب التحسين مستخدمًا أداة تحسين، إذا قمت بتحرير و/أو توليد SVG يدويًا ببنية معينة تحتاجها، وحسّن يدويًا قدر الإمكان. يمكن إزالة بعض مخلفات التحرير في بداية ونهاية الـ SVG يدويًا بسهولة، والمخلفات الأخرى مثل البيانات الوصفية والفئات المتولّدة من قِبل برامج التحرير التي لا تحتوي على خيارات تحسين SVG - مثل Sketch - قد يكون من الصعب تحسينها يدويًا. عمومًا، أنا لا أستخدم Sketch لتوليد SVG معقدة. أستخدم Illustrator أو Inkscape؛ إذ يأتي الأخير مع لائحة تصدير افتراضية تعطيك الكثير من الخيارات لتحسين الـ SVG قبل تصديره (انظر الصورة أدناه). يولّد Inkscape أنظف شيفرة SVG في وقت كتابة هذا المقال. أي إذا اخترت خيار تحسين SVG، لكن ضبابية واجهة المستخدم على شاشة شبكة العين وكذلك اعتمادها على X11 على OS X يجعل من الصعب استخدامه، لذلك أنا متمسكة حاليًا بـ Illustrator. إذا كنت تحتاج/تريد تحسين الـ SVG الخاص بك فإنني أنصحك بأداة SVGO، إذ يأتي SVGO مع مجموعة من الإضافات التي يمكن دمجها مع أي نوع من تدفقات العمل تقريبًا. 9- تواصل. تواصل مبكرًا ربما كان أهم نصيحة يمكنني تقديمها هو التواصل والقيام بذلك مبكرًا في عملية التصميم. أفترض أنّك الآن - المصمم الذي ينشئ SVG - لست الشخص نفسه المسؤول عن تطوير SVG (كتابة نص برمجي، التحريك، التضمين، …إلخ). تتطلّب كل واحدة من النصائح السابقة تقريبًا معرفة مرحلة التطوير وما ينوي المطور القيام به مع الـ SVG - كيف ينوون تضمينه، وكتابته كنص برمجي، وتصميمه، وتحريكه. لذا إذا لم تكن أنت نفس الشخص الذي يصنع القرارات لكلا المرحلتين، وما لم تكن تريد تضييع الكثير من الوقت في تكرار وتحرير الـ SVG، تحتاج إلى التأكّد من معرفتك لما يحتاج لمطور أن يفعله مع الـ SVG وما المنهجية (أو المنهجيات) التي سيتبعها. إذا كنت تعمل في مشروع له موعد نهائي ضيق، فمن المحتمل أنك لا تستطيع أن تضيع وقتًا كبيرًا في إجراء تغييرات ومراجعات على أصول الصور، عندما يمكنك تجنب ذلك عن طريق التواصل مبكرًا. يمكن أن يكون المصممون والمطورون أفضل أصدقاء لبعضهم بعضًا. تتطلّب طبيعة SVG أن تكون مراحل التصميم والتطوير مفتوحة على بعضها بعضًا، وهذا بدوره يتطلب من المصمم (المصممين) والمطور (المطورين) التحدّث قبل بدء عملية التصميم وطوال العملية أيضًا . ترجمة -وبتصرف- للمقال Tips for Creating and Exporting Better SVGs for the Web لصاحبته Sara Soueidan
  6. هذا الدرس عبارة عن مدخل إلى SVG. سنتعلم فيه المعلومات الأولية التي تحتاجها لرسم أشكال SVG بسيطة باستخدام لغة XML الأساسية. فإن لم تستخدم SVG من قبل فهذا هو الدرس المناسب لك. في الماضي كان تنسيق الصور الوحيد المعتمد من قبل جميع المتصفحات هو تنسيق GIF وهو ملف صورة مطوّر من قبل CompuServe. ثم ظهرت ملفات صور JPEG التي تسمح بضغط الصور دون ضياع للتفاصيل مع حجم صغير مقارنة بملفات GIF. بعد فترة من الزمن ظهرت الحاجة إلى رسومات فكتور ثنائية الأبعاد على الإنترنت. وبعد دخول عدد من تنسيقات الصور إلى المنافسة في رابطة الويب W3C تم تطوير تنسيق SVG أخيرًا عام 1999. سوف أريكم الآن كيفية إنشاء أشكال باستخدام SVG. هذا الدرس سيشرح كيفية استخدام SVG في صفحات الويب. ما هو SVG؟ إن مصطلح SVG هو اختصار إلى Scalable Vector Graphics أي رسومات فكتور القابلة لتغيير الحجم وهو عبارة عن تنسيق صور قائم على لغة XML من أجل الويب. وعلى عكس تنسيقات GIF وPNG وJPEG فإن تنسيق SVG قابل لتعديل الحجم بسهولة دون أي ضياع للدقة ولتفاصيل الرسومات. إن ملف XML الذي يحوي صور SVG يمكن إنشاؤه وتخصيصه وتكامله مع بقية لغات W3C القياسية الأخرى مثل DOM وXSL باستخدام أي محرر نصوص. كما يمكن إنشاء صور SVG بصريًّا باستخدام برامج الرسم والفكتور كبرنامج أدوبي إليستريتور Adobe Illustrator. لماذا نستخدم SVG؟ يمكن إنشاؤها وتعديلها باستخدام أي محرر نصوص. يمكن طباعتها بدقة عالية جدًّا. يمكن استخدامها من أجل الرسومات المتحركة. موصى بها من قبل W3C. تعمل مع بقية لغات W3C القياسية مثل DOM. مظهرها عظيم للعروض البصرية. يمكن تعديل حجمها إلى أي حجم نريد بدون أي تشوه قد يطرأ عليها. SVG على صفحات HTML يمكن تضمين SVG بسهولة داخل ملفات HTML باستخدام وسم SVG. كما في أسطر الأوامر التالية. <svg width=" " height=" "> [element code here..] </svg> كماترى فإن SVG لها وسمها الخاص. يجب أن يتم تحديد طول وعرض الرسم وذلك لاحتواء عنصر الرسم. العناصر التالية يمكن أن تستخدم للرسم داخل مساحة العمل الخاصة. Circle Rectangle Ellipse Line Polyline Polygon Path Text فلنبدأ الآن بتعلم استخدام هذه العناصر في الرسم. إنشاء الدائرة في SVG دوائر الـ SVG يمكن تنفيذها باستخدام وسم circle. كهذا المثال. <svg height="300" width="300"> <circle cx="60" cy="60" r="50" style="fill: blue; stroke: black; stroke-width: 2px;" /> </svg> النتيجة هي صورة الدائرة الظاهرة في الصورة التالية. في هذا المثال استخدمت وسم circle ثم cx (إحداثيات x) وcy (إحداثيات y) والتي تحدد مركز الدائرة المرسومة. ثم وضعت القيمة 50 للمتغير r (نصف القطر) والذي سيحدد طول الخط الواصل بين مركز الدائرة ومحيطها. أخيرًا أضفت أنماط للون التعبئة والحدود وعرض الحدود. إنشاء مستطيل في SVG يمكن تنفيذ رسم المستطيل عبر وسم rectangle ويمكن تحديد قيم مختلفة من الارتفاع والعرض. <svg height="300" width="300"> <rect width="250" height="100" rx="11" ry="11" style="fill: yellow; stroke: green; stroke-width: 4px;"/> </svg> النتيجة النهائية هي صورة SVG عبارة عن مستطيل كما في الصورة التالية. قمتُ بتحديد العرض والارتفاع باستخدام وسم rectangle. ثم أضفت rx وry التي تحدد استدارة حدود المستطيل. إذا قمت بإزالة القيمتين الأخيرتين فستحصل على حواف حادة. ثم نضيف أنماطًا عبر لون التعبئة والحدود وعرض الحدود. إنشاء القطع الناقص (شكل بيضوي) في SVG يتم تنفيذ هذا الشكل عبر وسم ellipse. القطع الناقص ليس له ارتفاع وعرض متساويين وعلى عكس الدائرة فإن نصف القطر cx وcy مختلفان. انظر الكود البرمجي التالي. <svg height="300" width="300"> <ellipse cx="190" cy="70" rx="100" ry="50" style="fill:red; stroke:green;stroke-width:2"/> </svg> صورة القطع الناقص (الشكل البيضوي) النهائية كما في الصورة التالية. إن cx وcy يحددان مركز شكل القطع الناقص بينما rx وry يحددان قطري الشكل. وكما ترى فإن rx يحدد عرض الشكل بينما ry يحدد ارتفاع الشكل. ثم نضع الأنماط من ألون التعبئة والحدود وعرضها كما في كل مرة. إنشاء خط في SVG يمكن إنشاء خط SVG باستخدام وسم line. كما هو واضح من الاسم فإن هذا الوسم يرسم خطوطًا، كما في المثال التالي. <svg height="300" width="300"> <line x1="0" y1="0" x2="100" y2="150" style="stroke:#000; stroke-width:5" /> </svg> النتيجة النهائية ستظهر كما في الصورة التالية. في هذا المثال يمثّل x1 الاحداثي x فيما يمثّل y1 الاحداثي y وهو ما يحدد نقطة بداية الخط. فيما تحدد الاحداثيات x2 وy2 نقطة النهاية. وباستخدام ميزات الانماط وضعتُ لون الحدود أسود ولعرض 5بكسل. إنشاء الخطوط المتعددة في SVG يمكن تنفيذ هذه الخطوط عبر وسم polyline. حيث يستخدم لرسم الأشكال المكونة من خطوط مستقيمة كهذا المثال. <svg height="300" width="300"> <polyline points="60,50 150,120 100,220 200,170" style="fill:none;stroke:black;stroke-width:3" /> </svg> والنتيجة كما هي واضحة في الصورة. وباستخدام الاحداثيات x وy يمكنك تعيين كل نقطةمن النقاط الفردية لإنشاء أي شكل تريده. وكما ترى هنا لدي أربع نقاط تم وصلها ببعضها لتشكيل الخطوط. وأضفت حدودًا سوداء وبعرض 3 بكسل. إنشاء شكل مضلع في SVG يمكن تنفيذه عبر وسم polygon. هذا العنصر سيرسم شكلًا مكونًا من أكثر من ثلاثة جوانب. شاهد الترميز التالي. <svg height="300" width="300"> <polygon points=" 60,20 100,40 100,80 60,100 20,80 20,40" style="fill:cyan;stroke:red;stroke-width:1" /> </svg> النتيجة النهائية كما في الصورة. في هذا الشكل نقاط يتم تحديدها عبر الاحداثيات x وy لكل جانب من جوانب الشكل من النقطة الأولى إلى النقطة الأخيرة. في المثال، أنشأتُ شكلًا مسدّسًا بست جوانب. كما ترى هناك 6 نقاط متصلة ببعضها محددة بالاحداثيات x وy. ثم حددت لون التعبئة باللون السماوي مع لون حدود أحمر وبعرض 1 بكسل. إنشاء مسارات في SVG يمكن تنفيذه عبر وسم path. هذا العنصر سيرسم مسارًا مخصّصًا وأشكالًا تتكون من منحنيات، خطوط وأقواس. من بين جميع عناصر SVG هذا هو العنصر الأصعب للتعلم. مسارات SVG تستخدم الأوامر التالية. M للحركة L للخط V للخط العمودي H للخط الأفقي C للمنحني S للمنحني الناعم T لمنحنيات البيزير التربيعية A للأقواس البيضوية Z لإغلاق المسار وتحدد الأحرف الكبيرة الموقع بدقة بينما تحدد الأحرف الصغيرة الموقع بشكل تقريبي. كما في المثال التالي. <svg height="300" width="300"> <path d="M 30 40 C 140 -30 180 90 20 160 L 120 160" style="fill: none; stroke: black; stroke-width: 6px;" /> </svg> النتيجة ستكون كالصورة التالية من خلال الترميز في الأعلى سترى بأنني استخدمت حرف d. ميزة حرف d هذا ستكون دائمًا أمر التحريك. ثم استخدمت حرف M الذي يعني التحرك نحو اتجاه معين. وقبل رسم أي شيء عليك أن تحرك المؤشر الافتراضي إلى الموقع المفضّل. في هذا المثال حرّكتُ المحور x إلى 30 والمحور y إلى 40. المنحني يبدأ عند 140,-30 كنقطة للبداية. تاليًا نزلت نقاط المنحني للأسفل واليمين عند النقطة 180,90 وتنتهي عند 20,160 ولإنهاء المسار أنشأت خطًّا عند النقطة 120,160. إنشاء النص في SVG يمكن تنفيذ هذا الأمر من خلال الوسم المغلق text. هذا العنصر يستخدم لرسم النص في صورة SVG. <svg height="300" width="300"> <text x="20" y="30" fill="blue" font-size="20">This a great sample for Text SVG! </text> </svg> النتيجة ستكون كالتالي. في المثال استخدمت موقع المحور x للنص عند 20. هذا سيضع النص على بعد 20 بكسل من اليسار بينما وضعت المحور y عند 30 ما يجعل النص على بعد 30 بكسل عن الحافة العلوية. ثم لوّنت النص باللون الأزرق وجعلت حجمه عند 20 بكسل. هذا سيظهر العبارة التالية "This a great sample for Text SVG!". ترجمة -وبتصرف- للمقال How to Create Simple Shapes with SVG لصاحبه Editorial Team
  7. يعتبر تحسين الصور (Image Optimization) من بين أكثر الخطوات بساطة وتأثيرا والتي يمكنك اتباعها من أجل تحويل موقعك من جيد إلى رائع. إلا أن القيام بذلك بشكل خاطئ سيؤدي حتما إلا نتائج عكسية كإثارة سخط زوارك، التأثير سلبا على عائداتك المادية فضلا عن خفض تصنيف السيو SEO الخاص بك. من حسن الحظ أن توفر العديد من الأدوات المتقدمة يجعل من القيام بهذا الجزء المهم من عملية التحسين العام للمواقع بشكل صحيح أمرا من السهولة بمكان. سنعمل في هذا المقال على التعمق في هذا الموضوع من خلال تغطية كل ما ستحتاجه لضمان دفع أداء موقعك إلى أقصى حدوده فيما يتعلق بكيفية تقديم المحتوى الجرافيكي. لنبدأ من خلال تعريف المصطلحات والتطرق لمختلف صيغ الصور التي تدخل في سياق الموضوع. نظرة حول صيغ الصور المستخدمة على الإنترنت كما يعرف كل من أمضى بعض الوقت مستخدما خاصية Save-as على برنامج فوتوشوب، هنالك كم هائل من صيغ الصور في العالم الرقمي، لكن عندما يتعلق الأمر بوضع هذه الصور على الإنترنت فإننا نتعامل مع عدد محدود نسبيا من الخيارات. تنقسم هذه الصيغ إلى نوعين أساسيين: Vector graphics (الرسومات المُتَّجِهة): الصور التي يتم تمثيلها بالاعتماد على المعادلات الرياضية من خلال استخدام الأشكال الهندسية مثل النقط، الخطوط والمنحنيات. Raster graphics (الرسومات النقطية): الصور المكونة من خلال شبكة بكسل مستطيلة الشكل. توضيح للاختلاف بين الرسومات المتجهة (على يمينك) والنقطية (على يسارك) في سياق تحسين الصور سنولي اهتماما أكبر للصور النقطية، إلّا أننا سنلقي نظرة سريعة على موضوع الصور المُتّجهة قبل أن ذلك. الصور المتجهة (Vector Images) يتم تمثيل الصور المُتّجهة حسابيا وبالاعتماد على معادلات رياضية ما يعطيها العديد من الإيجابيات دون إدخال أي تحسينات: عدم ترابط جودة الصورة ودقتها: يمكن تكبير وتصغير الصور المُتّجهة إلى أي حجم دون التسبب في تشويهها أو في ضياع التفاصيل حيث يتم عرضها بالجودة الكاملة في أي دقة كيفما كانت. سهولة التعديل: تقدم الصور المُتّجهة نفسها على طبق من ذهب لإمكانية التعديل والتغيير دون تخريبها. حجم ملف صغير: تتكون الصور المُتّجهة من سلسلة أوامر برمجية ما يعني صغر حجم ملفاتها. لطالما جعلت النقاط التي أسلفنا الذكر من الرسوميات المُتّجهة خيارا ممتازا في مجال تصميم الرسوميات (designing graphic) سواء الرسوم التوضيحية، الخلفيات أو أيقونات الشعارات. من ناحية تحسين الصور يمكن اعتبار أن الصور المُتّجهة تأتي جاهزة بشكل مثالي دون الحاجة إلى أي تعديلات أو تحسينات، يبقى المشكل في استخدامها مقتصرا على ضمان توافقيتها مع المتصفحات ودعم هذه الأخيرة لاستخدامها ما أدى إلى شيوع ممارسة غير سلسة بعض الشيء تتجلى في إنشاء المصممين لأعمالهم على حزم تصميم داعمة للرسوميات المتجهة مثل: Adobe Illustrator أو Inkscape ثم الاضطرار إلى تصدير (export) أحجام مختلفة فضلا عن صيغ غير مُتَّجِهة من أجل استعمالها على الإنترنت. تصميم تطبيق الرسوميات المتجهة Sketch المقدم من Bohemian Coding يمكن لتَبَني صيغة صور الويب SVGs Scalable Vector Graphics (الرسومات المتجهة متغيرة الحجم) على الصعيد العالمي أن يجعل من الأمور أكثر سهولة في هذا الصدد، إلا أنه من المؤسف أننا لم نصل بعد إلى هذا المستوى فيما يتعلق بدعمها. بأخذ هذا بعين الاعتبار وبالنظر إلى سنوات من التقدم التدريجي التصاعدي، يمكن أن نقول أن دعم توافقية هذه الصيغة أصبح قريبًا، من المرتقب أيضا أن نشهد أخيرا وفي السنوات القليلة القادمة انتشار واسعا لاستخدام الرسوميات المتجهة على أرض الواقع. حتى ذلك اليوم، من الوارد أنك ستحتاج إلى تصدير (export) ملفات الصيغ المتجهة إلى صيغ نقطية من أجل عرضها على الإنترنت، سنولي اهتمامنا فيما يلي إلى هذا النوع الأخير من الصيغ. الصور نقطية (Raster Images) تحظى الصور النقطية بالدعم الكامل من المتصفحات فضلا عن الحاجة لإجراء تعديلات كثيرة ومتقدمة تماما عكس نظيرتها المتجهة. هنالك في المجمل ثلاث صيغ ملفات ستصادفها أغلب الوقت إضافة إلى واحدة أخرى حديثة العهد بادية في الأفق يجدر أخذها بعين الاعتبار. لنقم بتغطية هذه الصيغ بالتتابع. GIFs تعتبر صيغة GIFs) Graphics Interchange Format) أقدم الصيغ في عالم الصور الرقمية، حيث تم ابتكارها سنة 1987، تتميز بصغر حجم ملفها، محدودية لوحة الألوان الخاصة بها: 256 لونا فضلا عن دعمها للشفافية ما جعلها العماد الأساس للعمل الرقمي خلال بدايات الإنترنت، والحل الذي يتم اعتماده بخصوص الصور التي تتضمن نصا ما أو ألونا مسطحة (flat color). تعتبر الصور التي تتضمن النصوص و/أو الألوان المسطحة استعمالا كلاسيكيا لصيغة GIFs رغم تحقيق هذه الصيغة عودة لا بأس بها خلال موجة جنون استخدام صور GIFs الحركية مؤخرا إلا أنها تفقد المزيد من مستخدميها بشكل متواصل لفائدة صيغة PNGs. JPEGs تعتبر صور JPEGs الصيغة العالمية لعرض الصور منذ الأيام الأولى للإنترنت، يتم استعمالها حاليا في ما يزيد عن %70 من المواقع الإلكترونية على الصعيد العالمي. تتميز هذه الصور بمبدأ الضغط الفَقُود (lossy compression) ما يجعل منها مرشحا ممتازا لعمليات التحسين المتقدمة فضلا عن ملائمتها المثالية للصور التي تحتوي على مجال واسع من الألوان والتدرجات (gradients)، يعتبر عدم دعم هذه الصيغة للشفافية (transparency) نقطة ضعفها الوحيدة. حفظ كل من تدرج الألوان المتقن فضلا عن مجال اللون الديناميكي بشكل جيد باستخدام JPEGs PNGs تم ابتكار الرسومات من صيغة PNGs (رسومات الشبكة المحمولة Portable Network Graphics) كحل لمشاكل الترخيص المحتملة عند استخدام GIFs، توفر صيغة PNGs خاصية الضغط غير الفَقُود (lossless compression)، دعم الشفافية (transparency) فضلا عن جودة صورة عالية. تعتبر صيغة 8 بت (8-bit format) بديلا مثاليا لصيغة GIFs كما أنها تتميز عن هذه الأخيرة بصغر حجم ملفها، في حين أن صنفي 24 بت و32 بت (24-bit and 32-bit) يوفران بديلا ممتازا لصيغة JPEGs، يبقى المشكل الوحيد هو كبر حجم الملف الناتج في هذه الحالة. يجعل الدعم الكامل للشفافية من صيغة PNGs خيارا جيدا للعديد من الاستعمالات. WebP في حين تتميز صيغ الصور النقطية الثلاث التي تمت مناقشتها سابقا بإمكانية نشرها على معظم المتصفحات الشهيرة نلاحظ غياب أي ابتكار حقيقي في هذا المجال منذ مدة من الزمن. من المحتمل أن يتغير ذلك مع مشروع WebP الخاص بجوجل (Google’s WebP project)، والذي يتمحور حول طرح صيغة صور جديدة والتي تمكن من تخفيض حجم الملف بنسبة تصل إلى %25، رغم أن متصفح Chrome يدعم هذه الصيغة بشكل تلقائي يبقى الدعم على مستوى عالمي أمرا غير متوافر. نصل مما سبق إلى خلاصة مفادها أن الصور المتجهة مثالية للغاية للعديد من الاستعمالات، لكن في سياق الاستعمال اليومي في إنشاء المحتوى ستستعمل مزيجا من صيغ GIFs، PNGs و JPEGs على الأقل في المستقبل القريب. لنتطرق إلى الأسباب التي تجعل من تحسين الصور بهذه الصيغ أمرا غاية في الأهمية. ضرورة التحسينات أدى توافر سرعة إنترنت عالية في العديد من الدول إلى عدم الاهتمام بتحسين الصور في بعض الأوساط. عادة ما يتم طرح هذا النوع من الأسئلة: ما الفرق الذي ستحدثه بضع كيلوبايت إضافية في وقت يستطيع معظم المستخدمين مشاهدة الأحداث الرياضية بشكل مباشر على أجهزتهم المحمولة؟ ألم نتجاوز بعد مرحلة القلق حول هذا النوع من البديهيات التافهة؟ لسوء الحظ فإن الإجابة ستكون بالنفي القاطع، تعتبر السرعة أمرا أساسيا خصوصا في الهواتف المحمولة. حقائق جديدة حول الهواتف المحمولة يتوجه الإنترنت بشكل متواصل نحو هيمنة استخدام الهواتف المحمولة. ينتج عن ذلك أمران أساسيان يجب أن تأخذهما بعين الاعتبار فيما يخص تحسين الصور: لم تعد الصور تعتبر كإضافات تزيين محببة للرؤية تستخدم لملء الفراغ في الأجهزة ذات الشاشات الكبيرة، يجب أن يتم التعامل معها على أن لها دورا محددا تلعبه في ظل الأجهزة ذات شاشات صغيرة جدا. رغم أن سرعات التحميل على الهواتف المحمولة في تصاعد مستمر إلا أنها لا زالت تقبع خلف تلك الخاصة بالحواسيب كما أن استخدامها لا يزال مُكلفًا، لكل بكسل أهمية قصوى. بالنظر إجمالا إلى هذا السياق، لنلق نظرة على ثلاث أسباب تجعل من تحسين الصور ضرورة وليس أمرا إضافيا فقط: يريد المستخدمون صفحات سريعة استنادا إلى أبحاث موقع HTTP Archive، تعد الصور من بين الأسباب الرئيسية في جعل معدل حجم الصفحات يصل إلى 1.25MB شأنها في ذلك شأن استخدام JavaScript بشكل مفرط، ما يعتبر بعيدا كل البعد عن المعدلات الرائجة أيام تحدي الخمس كيلوبت (the 5K Challenge). تؤدي ضخامة حجم الصفحات المتزايدة إلى نتائج سلبية، حيث أن %73 من مستعملي الإنترنت على الهواتف المحمولة اشتكوا من مواجهتهم مشاكل مع المدة الزمنية المستغرقة لتحميل الصفحات على أجهزتهم. في نفس الوقت، يتوقع نصف مستخدمي الويب أن يتم تحميل موقع ما في غضون ثانيتين، إلا أن هذا المعدل عند استعمال جهاز محمول يكون حوالي 7 ثوان، ما يعني بكل بساطة عدم موافاة تطلعات المستخدمين. باختصار، قد يؤدي ملء موقعك بصور غير ضرورية إلى سخط زوارك حتى قبل حصولهم على فرصة للتعرف على المحتوى الذي تقدمه. تؤدي كمية الصور الكبيرة إلى التأثير سلبا على التصنيف على محركات البحث تأكيدا لشكوك العديدين سابقا في سنة 2010، صرحت جوجل بأن السرعة تعتبر عاملا رسميا في تصنيف المواقع. يجب أن يتم تحميل صفحة موقعك في غضون ثانية أو أقل، لا تعتبر 200 كيلوبت التي تضيفها صورة القائمة الرأسية في موقعك إزعاجا وعدم احترام لمستخدمي الهواتف المحمولة فحسب بل قد تؤدي إلى عدم إيجادهم لموقعك على مُحرّكات البحث. تؤثر الصفحات البطيئة على عائداتك المادية قم بتجميع النقطتين السابقتين لتحصل على الوصفة السحرية للعديد من الثغرات لتسرب وضياع مداخيلك. تشير أبحاث Strangeloop إلى أن تأخيرا بسيطا بمقدار ثانية واحدة في تحميل الصفحة قد يؤدي إلى خفض معدل التحويل بنسبة %7. هل ترى أنك في وضعية تسمح لك بالتخلي عن قيمة الأرباح هذه فقط من خلال عدم تحسين منتوجك؟ ترجمة -وبتصرف- للمقال: The Complete Guide to Mastering Image Optimization for WordPress لصاحبه: TOM EWER. حقوق الصورة البارزة: Designed by Freepik.
×
×
  • أضف...