स्प्लिट टेक्स्ट ऐनिमेशन बनाना

स्प्लिट लेटर और वर्ड ऐनिमेशन बनाने के तरीके के बारे में बुनियादी खास जानकारी.

इस पोस्ट में, मैं आपको वेब के लिए स्प्लिट टेक्स्ट ऐनिमेशन और इंटरैक्शन को हल करने के तरीकों के बारे में सोचना चाहता हूं. डेमो आज़माएं.

डेमो

अगर आप वीडियो पसंद करते हैं, तो यहां इस पोस्ट का YouTube वर्शन दिया गया है:

खास जानकारी

स्प्लिट टेक्स्ट ऐनिमेशन शानदार हो सकता है. हम इस पोस्ट में ऐनिमेशन की संभावना की परत के बारे में बस शुरुआत करेंगे, लेकिन इससे आपको आगे बढ़ने में मदद मिलेगी. इसका लक्ष्य समय के साथ ऐनिमेट करना होता है. टेक्स्ट ऐसा होना चाहिए जिसे डिफ़ॉल्ट रूप से पढ़ा जा सके और ऐनिमेशन सबसे ऊपर बना हो. स्प्लिट टेक्स्ट मोशन इफ़ेक्ट बहुत ज़्यादा और खराब हो सकते हैं. इसलिए, हम सिर्फ़ एचटीएमएल में बदलाव करेंगे या मोशन स्टाइल सिर्फ़ तब लागू करेंगे, जब उपयोगकर्ता के लिए मोशन सही हो.

यहां वर्कफ़्लो और नतीजों के बारे में खास जानकारी दी गई है:

  1. सीएसएस और JS के लिए कम किए गए मोशन कंडीशनल वैरिएबल तैयार करें.
  2. JavaScript में टेक्स्ट को बांटने की सुविधाएं तैयार करें.
  3. पेज लोड होने पर, शर्तों और काम की शर्तों को व्यवस्थित करें.
  4. अक्षरों और शब्दों (मुख्य हिस्सा!) के लिए सीएसएस ट्रांज़िशन और ऐनिमेशन लिखें.

शर्तों के साथ जो नतीजे देखने हैं उनकी झलक यहां दी गई है:

Chrome DevTools का स्क्रीनशॉट, जिसमें एलिमेंट पैनल खुला हुआ है और मोशन को कम करके 'कम करें' पर सेट किया गया है. साथ ही, h1 को बिना स्प्लिट दिखाया गया है
उपयोगकर्ता को कम मोशन में टेक्स्ट का सुझाव पसंद है: टेक्स्ट पढ़ा जा सके / स्प्लिट हो

अगर कोई उपयोगकर्ता कम मोशन को प्राथमिकता देता है, तो हम एचटीएमएल दस्तावेज़ को अकेला छोड़ देते हैं और कोई ऐनिमेशन नहीं करते. अगर मोशन ठीक है, तो हम उसे छोटे-छोटे टुकड़ों में काटेंगे. यहां एचटीएमएल की झलक दी गई है कि JavaScript ने टेक्स्ट को अक्षर के हिसाब से बांटने के बाद क्या किया है.

Chrome DevTools का स्क्रीनशॉट, जिसमें एलिमेंट पैनल खुला हुआ है और मोशन को कम करके 'कम करें' पर सेट किया गया है. साथ ही, h1 को बिना स्प्लिट दिखाया गया है
टेक्स्ट को कई <span> एलिमेंट में बांटा गया है और उसे हिलने-डुलने से कोई परेशानी नहीं है

मोशन कंडीशनल तैयार किया जा रहा है

इस प्रोजेक्ट में, सीएसएस और JavaScript की मदद से, आसानी से उपलब्ध @media (prefers-reduced-motion: reduce) मीडिया क्वेरी का इस्तेमाल किया जाएगा. यह मीडिया क्वेरी हमारी मुख्य शर्त है, ताकि यह तय किया जा सके कि टेक्स्ट को बांटा जाए या नहीं. सीएसएस मीडिया क्वेरी का इस्तेमाल ट्रांज़िशन और ऐनिमेशन को रोकने के लिए किया जाएगा, जबकि JavaScript मीडिया क्वेरी का इस्तेमाल एचटीएमएल में बदलाव को रोकने के लिए किया जाएगा.

सीएसएस को शर्तों के साथ तैयार करना

मैंने मीडिया क्वेरी लेवल 5 के सिंटैक्स को चालू करने के लिए PostCSS का इस्तेमाल किया है, जहां मीडिया क्वेरी बूलियन को वैरिएबल में स्टोर किया जा सकता है:

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

JS कंडीशनल तैयार किया जा रहा है

JavaScript में, ब्राउज़र मीडिया क्वेरी की जांच करने का तरीका बताता है. मैंने मीडिया क्वेरी जांच से बूलियन नतीजे को एक्सट्रैक्ट करने और उसका नाम बदलने के लिए deस्ट्रक्चर का इस्तेमाल किया था:

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

इसके बाद, मैं motionOK की जांच कर सकता हूं और दस्तावेज़ को सिर्फ़ तब बदल सकता हूं, जब उपयोगकर्ता ने मोशन कम करने का अनुरोध न किया हो.

if (motionOK) {
  // document split manipulations
}

Nesting Draft 1 से @nest सिंटैक्स चालू करने के लिए, PostCSS का इस्तेमाल करके, मैं उसी वैल्यू की जांच कर सकता हूं. इससे मुझे ऐनिमेशन के सभी लॉजिक, माता-पिता और बच्चों के लिए इसकी स्टाइल से जुड़ी ज़रूरी शर्तों को एक ही जगह पर स्टोर करने में मदद मिलती है:

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

PostCSS कस्टम प्रॉपर्टी और JavaScript बूलियन की मदद से, हम इस इफ़ेक्ट को बेहतर बनाने के लिए तैयार हैं. यह हमें अगले सेक्शन में ले जाता है, जहां स्ट्रिंग को एलिमेंट में बदलने के लिए JavaScript को बांटा जाता है.

टेक्स्ट को बांटा जा रहा है

टेक्स्ट के अक्षर, शब्द, लाइन वगैरह को CSS या JS के साथ अलग-अलग ऐनिमेट नहीं किया जा सकता. इफ़ेक्ट हासिल करने के लिए, हमें बॉक्स की ज़रूरत है. अगर हमें हर अक्षर को ऐनिमेट करना है, तो हर अक्षर को एक एलिमेंट होना चाहिए. अगर हमें हर शब्द को ऐनिमेट करना है, तो हर शब्द का एक एलिमेंट होना चाहिए.

  1. स्ट्रिंग को एलिमेंट में बांटने के लिए, JavaScript यूटिलिटी फ़ंक्शन बनाएं
  2. इन सुविधाओं का इस्तेमाल करने के तरीके तैयार करें

अक्षरों को स्प्लिट करने वाला यूटिलिटी फ़ंक्शन

शुरुआत करने के लिए सबसे मज़ेदार बात यह है कि इसमें एक ऐसा फ़ंक्शन दिया गया है जो एक स्ट्रिंग लेता है और हर अक्षर को एक कलेक्शन में दिखाता है.

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

ES6 के spread सिंटैक्स से, यह काम आसानी से हो गया.

शब्दों को विभाजित करने वाला फ़ंक्शन

अक्षरों को बांटने की तरह ही, यह फ़ंक्शन एक स्ट्रिंग लेता है और हर शब्द को एक कलेक्शन में दिखाता है.

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

JavaScript स्ट्रिंग पर split() तरीके से, हम यह तय कर पाते हैं कि किन वर्णों को स्लाइस किया जाए. मैंने एक खाली जगह पास की है, जो शब्दों के बीच विभाजन को दिखाती है.

बॉक्स यूटिलिटी फ़ंक्शन बनाना

इस इफ़ेक्ट में हर अक्षर के लिए बॉक्स होते हैं और उन फ़ंक्शन में हमें पता चलता है कि map() को span() फ़ंक्शन के साथ कॉल किया जा रहा है. यहां span() फ़ंक्शन दिया गया है.

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

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

  return node
}

ध्यान रखें कि अरे की पोज़िशन के साथ, --index नाम की कस्टम प्रॉपर्टी को सेट किया जा रहा है. अक्षर वाले ऐनिमेशन के लिए बॉक्स का होना बहुत अच्छी बात है, लेकिन सीएसएस में इस्तेमाल करने के लिए इंडेक्स होने का असर बहुत मामूली दिखता है. इस बड़े असर में सबसे ज़्यादा खास बात चौंका देने वाली है. हम --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. उन्हें अलग-अलग करना और टेक्स्ट को एचटीएमएल से बदलना

इसके बाद, सीएसएस के मालिकाना हक से जुड़ी चीज़ें और एलिमेंट / बॉक्स को ऐनिमेट कर दिया जाएगा.

एलिमेंट ढूंढना

मैंने मनचाहे ऐनिमेशन और टेक्स्ट को बांटने के तरीके के बारे में जानकारी स्टोर करने के लिए, एट्रिब्यूट और वैल्यू का इस्तेमाल करने का विकल्प चुना है. मुझे जानकारी देने वाले इन विकल्पों को एचटीएमएल में रखना अच्छा लगा. split-by एट्रिब्यूट का इस्तेमाल JavaScript से किया जाता है. इसका इस्तेमाल एलिमेंट ढूंढने और अक्षरों या शब्दों के लिए बॉक्स बनाने के लिए किया जाता है. सीएसएस में letter-animation या word-animation एट्रिब्यूट का इस्तेमाल, एलिमेंट में बच्चों को टारगेट करने और ट्रांसफ़ॉर्म और ऐनिमेशन को लागू करने के लिए किया जाता है.

यहां एचटीएमएल का एक सैंपल दिया गया है, जो दो एट्रिब्यूट दिखाता है:

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

JavaScript से एलिमेंट ढूंढना

मैंने एट्रिब्यूट की मौजूदगी के लिए सीएसएस सिलेक्टर सिंटैक्स का इस्तेमाल किया है, ताकि उन एलिमेंट की सूची इकट्ठा की जा सके जिन्हें टेक्स्ट को बांटना है:

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

सीएसएस से एलिमेंट ढूंढना

सभी अक्षर वाले ऐनिमेशन को एक ही बेस स्टाइल देने के लिए, मैंने सीएसएस में एट्रिब्यूट मौजूदगी चुनने वाला टूल भी इस्तेमाल किया है. बाद में, हम एट्रिब्यूट वैल्यू का इस्तेमाल करके ज़्यादा खास स्टाइल जोड़ेंगे.

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. टेक्स्ट को एलिमेंट से बदलें.

ऐनिमेशन और ट्रांज़िशन को बांटना

ऊपर दिए गए दस्तावेज़ों में हेर-फेर करने से, कई संभावित ऐनिमेशन और इफ़ेक्ट अनलॉक हो गए हैं. ये सीएसएस या JavaScript इस्तेमाल किए जा सकते हैं. इस लेख के सबसे नीचे कुछ लिंक दिए गए हैं. इनकी मदद से, आपको कॉन्टेंट को अलग-अलग हिस्सों में बांटने की सुविधा मिलेगी.

दर्शकों को दिखाएं कि आप उनकी मदद से क्या कर सकते हैं! मैं आपको सीएसएस से चलने वाले चार ऐनिमेशन और ट्रांज़िशन शेयर करूँगी. 🤓

अक्षर को छोटे-छोटे अक्षरों में बांटें

स्प्लिट लेटर वाले इफ़ेक्ट का इस्तेमाल शुरू करने के लिए, मुझे यह सीएसएस काफ़ी मददगार लगी. मैं सभी ट्रांज़िशन और ऐनिमेशन को मोशन मीडिया क्वेरी के पीछे डाल देता हूं और फिर हर नए चाइल्ड लेटर span को एक डिसप्ले प्रॉपर्टी के साथ-साथ व्हाइट स्पेस के साथ क्या करना है, इसका स्टाइल भी देता हूं:

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

व्हाइट स्पेस की स्टाइल ज़रूरी है, ताकि लेआउट इंजन, उन स्पैन को छोटा न कर सके जो सिर्फ़ एक स्पेस हैं. अब चलते हैं राज्य के मज़ेदार पलों की.

अलग-अलग अक्षरों वाले ट्रांज़िशन का उदाहरण

इस उदाहरण में, स्प्लिट टेक्स्ट इफ़ेक्ट के लिए सीएसएस ट्रांज़िशन का इस्तेमाल किया गया है. ट्रांज़िशन के दौरान, हमें इंजन के लिए इन स्टेट की ज़रूरत होती है, ताकि वह ऐनिमेशन के बीच में आ सके. इस दौरान, मैंने तीन स्थितियां चुनीं: नहीं, घुमाएं वाक्य पर कर्सर घुमाएं, किसी अक्षर पर कर्सर घुमाएं.

जब उपयोगकर्ता किसी वाक्य (यानी कंटेनर) पर कर्सर घुमाता है, तो मैंने बच्चों के सभी बच्चों को वापस स्केल कर लिया है, जैसे कि उपयोगकर्ता ने उन्हें और दूर कर दिया हो. फिर, जैसे ही उपयोगकर्ता किसी अक्षर पर कर्सर घुमाता है, मैं उसे आगे की ओर ले जाता हूं.

@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 DevTools

स्प्लिट किए गए शब्दों का उदाहरण

इस ट्रांज़िशन के इस उदाहरण में, मैंने फिर से कर्सर घुमाने की सुविधा का इस्तेमाल किया है. शुरुआत में यह इफ़ेक्ट, कॉन्टेंट को होवर करने तक छिपा देता है.

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

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

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

ऐनिमेशन के तौर पर, छोटे-छोटे शब्दों का उदाहरण

ऐनिमेशन के इस उदाहरण में, मैंने टेक्स्ट के किसी सामान्य पैराग्राफ़ पर एक स्टैक्ड इनफ़ाइनाइट ऐनिमेशन बनाने के लिए, फिर से सीएसएस @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;
  }
}

नतीजा

अब आपको पता चल गया है कि मैंने इसे कैसे किया, तो आपको कैसा लगा?! 🙂

चलिए, इसे अलग-अलग तरीके से समझें और वेब पर सभी के काम करने के तरीके सीखें. एक कोडिंग बनाएं या अपना डेमो होस्ट करें और मुझे इसके साथ ट्वीट करें. इसके बाद, मैं इसे नीचे दिए गए कम्यूनिटी रीमिक्स सेक्शन में जोड़ दूँगी.

सोर्स

ज़्यादा डेमो और प्रेरणा

कम्यूनिटी रीमिक्स

  • CodeSandbox पर gnhcwu का <text-hover> वेब कॉम्पोनेंट