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

अलग-अलग अक्षरों और शब्दों के ऐनिमेशन बनाने के तरीके की बुनियादी जानकारी.

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

डेमो

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

खास जानकारी

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

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

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

यहां उन शर्तों के हिसाब से मिलने वाले नतीजों की झलक दी गई है जिनके लिए हमने यह सेटअप किया है:

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

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

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

मोशन की शर्तें तैयार करना

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

सीएसएस कंडीशनल तैयार करना

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

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

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

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

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

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

if (motionOK) {
  // document split manipulations
}

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

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

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

टेक्स्ट को बांटना

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

  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;
  }
}

शब्दों को अलग-अलग करना

इन उदाहरणों में, फ़्लेक्सबॉक्स ने मेरे लिए कंटेनर टाइप के तौर पर काम किया. साथ ही, ch यूनिट को सही गैप की लंबाई के तौर पर बेहतर तरीके से इस्तेमाल किया.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
फ़्लेक्सबॉक्स डेवलपर टूल, जो शब्दों के बीच के अंतर को दिखाता है

ट्रांज़िशन के लिए अलग-अलग शब्दों का इस्तेमाल करने का उदाहरण

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

@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;
  }
}

नतीजा

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

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

स्रोत

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

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