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

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

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

डेमो

अगर आपको वीडियो देखना है, तो इस पोस्ट का 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 को अलग-अलग हिस्सों में बांटा है.

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

टेक्स्ट के अक्षरों, शब्दों, लाइनों वगैरह को 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. टेक्स्ट को एलिमेंट से बदलें.

ऐनिमेशन और ट्रांज़िशन को अलग-अलग करना

दस्तावेज़ को अलग-अलग बांटने के ऊपर किए गए बदलाव ने अभी-अभी CSS या 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;
}
फ़्लेक्सबॉक्स डेवलपर टूल, जो शब्दों के बीच के अंतर को दिखाता है

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

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

@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 बनाएं या अपना डेमो होस्ट करें. इसके बाद, मुझे ट्वीट करें. हम इसे नीचे दिए गए कम्यूनिटी रीमिक्स सेक्शन में जोड़ देंगे.

स्रोत

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

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

  • CodeSandbox पर gnehcwu के ज़रिए <text-hover> वेब कॉम्पोनेंट