إنشاء صور متحركة مقسّمة باستخدام نص

نظرة عامة أساسية حول كيفية إنشاء صور متحركة مجزّأة للكلمات والحروف

في هذه المشاركة، أريد مشاركة أفكار حول طرق حلّ الصور المتحركة للنص المُقسّم والتفاعلات على الويب التي تكون بسيطة وسهلة الاستخدام وتعمل على جميع المتصفّحات. جرِّب الإصدار التجريبي.

العرض التوضيحي

إذا كنت تفضّل مشاهدة الفيديوهات، يمكنك الاطّلاع على نسخة من هذه المشاركة على YouTube:

نظرة عامة

يمكن أن تكون الصور المتحرّكة للنص المُقسَّم رائعة. سنتناول في هذه المشاركة بشكلٍ سطحي فقط إمكانيات استخدام الصور المتحركة، ولكنّها توفّر أساسًا لبناء المحتوى عليها. والهدف هو إضافة الحركة تدريجيًا. يجب أن يكون النص مقروءًا بشكل تلقائي، مع إضافة الرسوم المتحركة فوقه. يمكن أن تصبح تأثيرات الحركة للنص المُقسَّم مفرطة وقد تتسبب في انزعاج المستخدم، لذلك لن نتعامل إلا مع علامات HTML أو نطبّق أنماط الحركة إذا كان المستخدم لا يمانع ذلك.

في ما يلي نظرة عامة على سير العمل والنتائج:

  1. احرِص على إعداد المتغيّرات المشروطة للحركة المنخفضة في CSS وJavaScript.
  2. احرِص على إعداد أدوات تقسيم النص في JavaScript.
  3. تنسيق الشروط والأدوات عند loading الصفحة
  4. كتابة عمليات النقل والحركات في CSS للأحرف والكلمات (الجزء المثير)

في ما يلي معاينة للنتائج الشَرطية التي نسعى إليها:

لقطة شاشة لأدوات مطوري البرامج في Chrome مع فتح لوحة "العناصر" وضبط الإعداد "تقليل الحركة" على "تقليل" وعرض h1 بدون تقسيم
يفضّل المستخدم المحتوى الذي يقلّل من الحركة: النص مقروء / غير مُقسَّم

إذا كان المستخدم يفضّل استخدام الصور التي لا تتحرّك كثيرًا، نترك ملف HTML كما هو ولا نطبّق عليه أي تأثيرات متحركة. إذا كانت الحركة جيدة، سنقطعها إلى أجزاء. في ما يلي معاينة لرمز HTML بعد أن قسمت JavaScript النص حسب الحرف.

لقطة شاشة لأدوات مطوّري البرامج في Chrome مع فتح لوحة "العناصر" وضبط الإعداد "تقليل الحركة" على "تقليل" وعرض h1 بدون تقسيم
لا يمانع المستخدم استخدام الصور المتحركة، وتم تقسيم النص إلى عناصر <span> متعددة

إعداد الشروط المتعلّقة بالحركة

سيتم استخدام طلب البحث عن الوسائط @media (prefers-reduced-motion: reduce) المتاح بسهولة من CSS و JavaScript في هذا المشروع. طلب البحث عن الوسائط هذا هو الشرط الأساسي لتحديد ما إذا كان سيتم تقسيم النص أم لا. سيتم استخدام طلب البحث عن الوسائط في CSS لمنع الانتقالات والصور المتحركة، بينما سيتم استخدام طلب البحث عن الوسائط في JavaScript لمنع التلاعب بتنسيق HTML.

تحضير الشرط في CSS

لقد استخدمت PostCSS لتفعيل بنية المستوى 5 من طلبات البحث عن الوسائط، حيث يمكنني تخزين قيمة منطقية لطلب بحث عن الوسائط في متغيّر:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

تحضير الشرط في JavaScript

في JavaScript، يقدّم المتصفّح طريقة للتحقّق من طلبات البحث عن الوسائط، وقد استخدمت إعادة التشكيل لاستخراج النتيجة المنطقية وإعادة تسميتها من عملية التحقّق من طلب البحث عن الوسائط:

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

يمكنني بعد ذلك اختبار motionOK، ولن أغيّر المستند إلا إذا لم يطلب المستخدِم تقليل الحركة.

if (motionOK) {
  // document split manipulations
}

يمكنني التحقّق من القيمة نفسها باستخدام PostCSS لتفعيل بنية @nest من مسودة "التداخل" 1. يتيح لي ذلك تخزين كل منطق الرسوم المتحركة ومتطلبات أسلوبها في مكان واحد، سواءً بالنسبة إلى الوالدَين أو الأطفال:

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

باستخدام السمة المخصّصة PostCSS وتعبير منطقي JavaScript، أصبحنا جاهزين ل ترقية التأثير بشكل مشروط. ينقلنا ذلك إلى القسم التالي حيث سأشرح لغة JavaScript لتحويل السلاسل إلى عناصر.

تقسيم النص

لا يمكن إضافة تأثيرات متحركة بشكل فردي إلى أحرف النص أو الكلمات أو السطور أو غير ذلك باستخدام CSS أو JS. لتحقيق التأثير المطلوب، نحتاج إلى صناديق. إذا أردنا إضافة تأثيرات متحركة إلى كل حرف، يجب أن يكون كل حرف عنصرًا. إذا أردنا إضافة تأثيرات متحركة لكل كلمة، يجب أن تكون كل كلمة عنصرًا.

  1. إنشاء دوال مساعدة في JavaScript لتقسيم السلاسل إلى عناصر
  2. تنظيم استخدام هذه المرافق

دالة خدمية لتقسيم الأحرف

يمكنك البدء باستخدام دالة تأخذ سلسلة وتُخرج كل حرف في صفيف.

export const byLetter = text =>
  [...text].map(span)

ساعدت بنية الانتشار من ES6 حقًا في إنجاز هذه المهمة بسرعة.

دالة خدمية لتقسيم الكلمات

على غرار تقسيم الأحرف، تأخذ هذه الدالة سلسلة وتُعرِض كل كلمة في صفيف.

export const byWord = text =>
  text.split(' ').map(span)

تسمح لنا طريقة split() في سلاسل JavaScript بتحديد الأحرف التي سيتم تقطيعها. مررتُ على مسافة فارغة، ما يشير إلى حدوث انقسام بين الكلمات.

استخدام مربّعات الأدوات

يتطلّب التأثير مربّعات لكل حرف، ونرى في هذه الدوال أنّه يتم استدعاء map() باستخدام دالة span(). في ما يلي دالة span().

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

من المهمّ ملاحظة أنّه يتمّ ضبط سمة مخصّصة باسم --index باستخدام موضع المصفوفة. من الرائع أن تتوفّر لك مربّعات للحركات المتحرّكة للحروف، ولكن إنّ توفّر فهرس لاستخدامه في CSS هو إضافة صغيرة على ما يبدو لها تأثير كبير. ومن أبرز التأثيرات الكبيرة التي نتجت عن ذلك هو الانخفاض المفاجئ. سنتمكن من استخدام --index كطريقة لتقليل الرسوم المتحركة للحصول على شكل متفاوت.

خاتمة حول الخدمات

وحدة splitting.js المكتملة:

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

export const byLetter = text =>
  [...text].map(span)

export const byWord = text =>
  text.split(' ').map(span)

بعد ذلك، عليك استيراد دالتَي byLetter() وbyWord() واستخدامهما.

عملية التنسيق المُقسَّمة

مع توفّر أدوات التقسيم الجاهزة للاستخدام، يعني ذلك ما يلي:

  1. تحديد العناصر التي يجب تقسيمها
  2. تقسيمها واستبدال النص بعلامات HTML

بعد ذلك، تتولى خدمة CSS عرض العناصر أو المربّعات بتأثيرات متحركة.

العثور على العناصر

اخترت استخدام السمات والقيم لتخزين معلومات عن المقصود بالحركة وكيفية تقسيم النص. أحببتُ وضع هذه الخيارات التعريفية في رمز HTML. يتم استخدام السمة split-by من JavaScript للعثور على العناصر وإنشاء مربّعات للحروف أو الكلمات. يتم استخدام السمة letter-animation أو word-animation من CSS لاستهداف عناصر الأبناء وتطبيق عمليات التحويل والحركات.

في ما يلي نموذج لرمز HTML يعرض السمتَين:

<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>

العثور على العناصر من JavaScript

لقد استخدمت بنية محدد CSS لتحديد وجود السمة من أجل جمع قائمة بالعناصر التي يجب تقسيم نصها:

const splitTargets = document.querySelectorAll('[split-by]')

العثور على العناصر من CSS

لقد استخدمت أيضًا أداة اختيار مدى توفّر السمة في CSS لمنح جميع الرسومات المتحركة للرسائل الأنماط الأساسية نفسها. لاحقًا، سنستخدم قيمة السمة لإضافة مزيد من الأنماط المحدّدة لتحقيق تأثير معيّن.

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

تقسيم النص في مكانه

بالنسبة إلى كلّ استهداف من استهدافات التقسيم التي نعثر عليها في JavaScript، سنقسّم نصها استنادًا إلى قيمة السمة ونربط كلّ سلسلة بعنصر <span>. يمكننا بعد ذلك استبدال نص العنصر بالمربّعات التي أنشأناها:

splitTargets.forEach(node => {
  const type = node.getAttribute('split-by')
  let nodes = null

  if (type === 'letter') {
    nodes = byLetter(node.innerText)
  }
  else if (type === 'word') {
    nodes = byWord(node.innerText)
  }

  if (nodes) {
    node.firstChild.replaceWith(...nodes)
  }
})

خاتمة عملية التنسيق

index.js في مرحلة الاكتمال:

import {byLetter, byWord} from './splitting.js'

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    const type = node.getAttribute('split-by')
    let nodes = null

    if (type === 'letter')
      nodes = byLetter(node.innerText)
    else if (type === 'word')
      nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}

يمكن قراءة JavaScript باللغة الإنجليزية التالية:

  1. استورِد بعض الدوال المساعِدة.
  2. تحقّق مما إذا كانت الحركة مناسبة لهذا المستخدم، وإذا لم تكن كذلك، لا داعي لإجراء أيّ شيء.
  3. لكل عنصر تريد تقسيمه.
    1. تقسيمها حسب الطريقة التي يريدون تقسيمها بها
    2. استبدِل النص بعناصر.

تقسيم الحركات والانتقالات

من خلال معالجة المستندات أعلاه، أصبح بإمكانك استخدام CSS أو JavaScript لإنشاء العديد من الصور المتحركة والتأثيرات المحتملة. في أسفل هذه المقالة، يمكنك الاطّلاع على بعض الروابط التي تساعدك في التعرّف على فرص تقسيم المحتوى.

حان الوقت لإظهار ما يمكنك فعله باستخدام هذه الميزة. سأشارك 4 صور متحركة و انتقالات مستندة إلى CSS. 🤓

تقسيم الأحرف

لقد تبيّن لي أنّ ملف CSS التالي مفعّل كقاعدة لتأثيرات تقسيم الحرف. لقد وضعتُ جميع الانتقالات والصور المتحركة خلف طلب الوسائط المتحركة، ثم منحَتُ كل حرف فرعي جديد span خاصية عرض بالإضافة إلى نمط لإجراء ما يلي مع المسافات البيضاء:

[letter-animation] > span {
  display: inline-block;
  white-space: break-spaces;
}

إنّ أسلوب المساحات البيضاء مهمّ لكي لا يُدمج محرّك التنسيق الفواصل التي لا تحتوي إلا على مساحة. ننتقل الآن إلى الميزات الممتعة التي تتضمّن حالة.

مثال على تقسيم الأحرف في الانتقال

يستخدم هذا المثال انتقالات CSS لتأثير النص المُقسّم. مع الانتقالات، نحتاج إلى حالات ليتمكّن المحرّك من إنشاء مؤثرات متحركة بينها، واخترت ثلاث حالات: عدم التمرير فوق الكلمات، التمرير فوق الجملة، التمرير فوق حرف.

عندما يمرّر المستخدم مؤشر الماوس فوق الجملة، أي الحاوية، أُقلّل حجم كل العناصر التابعة كما لو أنّ المستخدم دفعها بعيدًا. بعد ذلك، عندما يمرِّر المستخدم مؤشر الماوس فوق أحد الأحرف، أُبرزه.

@media (--motionOK) {
  [letter-animation="hover"] {
    &:hover > span {
      transform: scale(.75);
    }

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:hover {
        transform: scale(1.25);
      }
    }
  }
}

مثال على تحريك الأحرف المُقسَّمة

يستخدم هذا المثال حركة @keyframe مُحدَّدة مسبقًا لتحريك كل حرف بشكلٍ لا نهائي، ويستفيد من فهرس السمة المخصّصة المضمّنة لإنشاء تأثير تدرّجي.

@media (--motionOK) {
  [letter-animation="breath"] > span {
    animation:
      breath 1200ms ease
      calc(var(--index) * 100 * 1ms)
      infinite alternate;
  }
}

@keyframes breath {
  from {
    animation-timing-function: ease-out;
  }
  to {
    transform: translateY(-5px) scale(1.25);
    text-shadow: 0 0 25px var(--glow-color);
    animation-timing-function: ease-in-out;
  }
}

تقسيم الكلمات

لقد كان Flexbox بمثابة نوع حاوية لي في هذه الأمثلة، ما أتاح لي الاستفادة من وحدة ch كطول مناسب للفراغ.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
أدوات تطوير Flexbox تعرِض الفجوة بين الكلمات

مثال على كلمات مُقسَّمة في الانتقال

في مثال الانتقال هذا، أستخدم التمرير بمؤشر الماوس مرة أخرى. بما أنّ التأثير يخفي في البداية المحتوى إلى أن يتم تمرير مؤشر الماوس فوقه، تأكّدت من أنّ التفاعل والأنماط لا يتم تطبيقها إلا إذا كان الجهاز مزوّدًا بإمكانية تمرير مؤشر الماوس.

@media (hover) {
  [word-animation="hover"] {
    overflow: hidden;
    overflow: clip;

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:not(:hover) {
        transform: translateY(50%);
      }
    }
  }
}

مثال على تحريك الكلمات المُقسَّمة

في مثال الحركة هذا، أستخدِم CSS @keyframes مرة أخرى لإنشاء حركة متقطّعة لانهائية على فقرة عادية من النص.

[word-animation="trampoline"] > span {
  display: inline-block;
  transform: translateY(100%);
  animation:
    trampoline 3s ease
    calc(var(--index) * 150 * 1ms)
    infinite alternate;
}

@keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
}

الخاتمة

الآن بعد أن عرفت كيف فعلت ذلك، كيف ستفعل ذلك؟ 🙂

لننوّع أساليبنا ونتعرّف على جميع الطرق لإنشاء تطبيقات على الويب. أنشئ نموذجًا على Codepen أو استضِف عرضًا توضيحيًا خاصًا بك، وشاركه معي على Twitter، وسأضيفه إلى قسم "الريمكسات التي أنشأها المجتمع" أدناه.

المصدر

المزيد من العروض التوضيحية والأفكار

الريمكسات التي أنشأها المستخدمون