कंटेंट पर जाएँ
सीमित समयStarter अब $20 की जगह $9 प्रति माह है।प्लान देखें
charmotion

स्क्रॉल से चलने वाला लोगो और मैस्कॉट एनिमेशन: CSS, Rive और वीडियो

Charmotion टीम द्वारा · अपडेट:

गाइड का कवर इलस्ट्रेशन: Scroll-Driven लोगो और मैस्कॉट एनिमेशन: CSS, Rive और वीडियो, Charmotion डेमो कैरेक्टर्स के साथ

Scroll के साथ चलने वाले लोगो के लिए CSS scroll-driven animations इस्तेमाल करें: scroll() या view() के साथ animation-timeline, और transform व opacity को एनिमेट करें। नवंबर 2026 तक ये मौजूदा Chrome, Edge, Firefox और Safari में काम करते हैं, इसलिए इन्हें @supports में रखें और पुराने ब्राउज़र को resting लोगो दिखाने दें। Rive मैस्कॉट के लिए scroll progress को एक data-bound number से जोड़ें।

मुख्य बातें

  • CSS scroll-driven animations अक्टूबर 2026 में Baseline (newly available) बने: Chrome और Edge 115, Firefox 159 और Safari 26 animation-timeline को सपोर्ट करते हैं।
  • किसी एलिमेंट को viewport पार करते समय एनिमेट करने के लिए view() और पेज कितना scroll हुआ उससे मोशन जोड़ने के लिए scroll() इस्तेमाल करें। animation-timeline को animation shorthand के बाद declare करें।
  • एक बार चलने वाले reveals के लिए, एक Intersection Observer जो वीडियो शुरू करे या Rive trigger fire करे, ज़्यादा आसान है और पुराने ब्राउज़र में भी काम करता है।
  • Rive ने runtime v2.41.0 में scrub() को deprecated कर दिया। इसके बजाय data-bound number से 1D blend state चलाएँ।
  • हर scroll एनिमेशन को prefers-reduced-motion: no-preference के पीछे रखें, और static स्टेट को पूरा, resting लोगो बनाएँ।

पहले से कोई कैरेक्टर या लोगो है? असली ऐप स्क्रीन में उदाहरण देखें: स्प्लैश, ऑनबोर्डिंग, लोडिंग और एम्प्टी स्टेट स्क्रीन, और हर एक में चलने वाला एनिमेशन।

लोगो या मैस्कॉट के लिए कौन सी scroll animation तकनीक सही है?

दो अलग-अलग इफ़ेक्ट हैं जिन्हें लोग "scroll animation" कहते हैं, और दोनों के लिए अलग टूल चाहिए:

  • Scroll-linked (scrubbed): एनिमेशन की progress scroll position के साथ चलती है। ऊपर scroll करें तो वह उल्टा चलता है। Scroll करने पर छोटा होने वाला header लोगो scroll-linked है।
  • Scroll-triggered: कुछ view में scroll होकर आते ही एनिमेशन अपनी घड़ी पर चलता है। अपना सेक्शन आने पर हाथ हिलाने वाला मैस्कॉट scroll-triggered है।
तकनीकप्रकारकिसके लिए बेस्टखर्च
CSS animation-timeline: view() या scroll()Scroll-linkedSVG या image लोगो: reveal, shrink, rotate, fadeकोई JavaScript नहीं; smoothness के लिए सिर्फ़ transform और opacity
Intersection Observer + वीडियो या Rive triggerScroll-triggeredएक बार रिएक्ट करने वाला मैस्कॉट, सेक्शन आने पर लोगो introJavaScript की कुछ लाइनें; हर जगह काम करता है
Blend state चलाता Rive data-bound numberScroll-linkedScroll के साथ चलने वाले कैरेक्टर pose: नीचे देखना, मुड़ना, progress मैस्कॉटRive runtime और एक scroll handler
वीडियो currentTime scrubbingScroll-linkedपहले से render किए गए 3D लोगो turns और product spinsबड़ी फ़ाइलें; seeking का खर्च encoding और डिवाइस के हिसाब से बदलता है

ज़्यादातर लोगो के लिए CSS काफ़ी है। जब चलने वाली चीज़ का चेहरा हो और उसे असली pose चाहिए, तब Rive लें, और वीडियो तब जब मोशन एक rendered 3D शॉट हो जिसे कोई runtime live नहीं बना सकता।

CSS scroll-driven animations कैसे काम करते हैं?

MDN इन्हें "animate property values along a scroll-based timeline rather than the default time-based document timeline" का तरीका बताता है। आप सामान्य @keyframes लिखते हैं, फिर उन्हें animation-timeline से एक timeline से जोड़ते हैं:

  • scroll() "the root element, nearest scroller, or self" के लिए एक scroll progress timeline बनाता है। 0% ऊपर है, 100% scroll range का अंत है।
  • view() एक view progress timeline बनाता है जो "progresses based on changes in the visibility of a subject element inside its nearest scroll container." डिफ़ॉल्ट रूप से यह उस पल से चलता है जब एलिमेंट एक किनारे पर पहली बार दिखता है, उस पल तक जब वह दूसरे किनारे से निकल जाता है।
  • animation-range timeline के उस हिस्से को सीमित करता है जिसे एनिमेशन इस्तेमाल करता है, जैसे entry 0% entry 100% ताकि एनिमेशन ठीक तब खत्म हो जब एलिमेंट पूरी तरह अंदर आ जाए।

एक लोगो जो उसके सेक्शन के scroll होकर आने पर ऊपर उठकर टिक जाता है:

@keyframes logo-in {
  from { opacity: 0; transform: translateY(32px) scale(0.85) rotate(-6deg); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .section-logo {
      animation: logo-in 1ms linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 40%;
    }
  }
}

एक header लोगो जो पेज scroll के पहले 200 पिक्सेल में छोटा होता है:

@keyframes logo-shrink {
  to { transform: scale(0.7); }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll()) {
    .site-logo {
      transform-origin: left center;
      animation: logo-shrink 1ms linear both;
      animation-timeline: scroll(root);
      animation-range: 0px 200px;
    }
  }
}

एक जाल में लगभग हर कोई फँसता है: animation-timeline को animation shorthand reset कर देता है। MDN कहता है कि आपको "need to declare animation-timeline after declaring any animation shorthand for it to take effect", और Chrome की गाइड भी यही चेतावनी देती है। 1ms duration जान-बूझकर है: scroll timeline पर एनिमेशन वैसे भी scroll range में फैल जाता है, लेकिन MDN बताता है कि Firefox में एनिमेशन लागू होने के लिए duration सेट होना चाहिए, और 1ms की सलाह देता है। Timeline पर linear easing रखें ताकि लोगो scrollbar के साथ बराबर चले; कैरेक्टर keyframes में डालें।

नवंबर 2026 तक कौन से ब्राउज़र animation-timeline को सपोर्ट करते हैं?

सभी मौजूदा बड़े engines। नवंबर 2026 तक MDN animation-timeline, view() और animation-range को "Baseline 2026, newly available" बताता है, जो नए ब्राउज़र में "since October 2026" काम करते हैं।

ब्राउज़रanimation-timeline वाला पहला वर्ज़न
Chrome और Edge115
Firefox159
Safari (macOS और iOS)26
Samsung Internet23

Can I use के अनुसार नवंबर 2026 में global support लगभग 89% यूज़र्स तक है। "Newly available" का मतलब है कि पुराने डिवाइस में यह अब भी नहीं है: Safari 18 या पुराने Firefox वाले सभी। इसीलिए ऊपर का हर sample @supports के अंदर है।

Fallback पूरी हो चुकी स्टेट होनी चाहिए, छिपा हुआ लोगो नहीं। एलिमेंट की सामान्य styles को resting लोगो के रूप में लिखें, और मोशन सिर्फ़ @supports block के अंदर जोड़ें। तब बिना सपोर्ट वाले ब्राउज़र एक static, सही लोगो दिखाते हैं, और reduced-motion यूज़र्स को भी यही मिलता है। अगर पुराने ब्राउज़र के लिए भी मोशन ज़रूरी है, तो नीचे वाला Intersection Observer तरीका play-once fallback के रूप में इस्तेमाल करें; सिर्फ़ एक लोगो के लिए scroll-event polyfill ship न करें।

लोगो या मैस्कॉट एनिमेशन view में scroll होकर आने पर कैसे चलाएँ?

Intersection Observer इस्तेमाल करें। MDN इसके मुख्य उपयोगों में "deciding whether or not to perform tasks or animation processes based on whether or not the user will see the result" गिनाता है, और यह Baseline widely available है (मार्च 2019 से)। यह वर्ज़न muted वीडियो को तब चलाता है जब वे कम से कम आधे दिख रहे हों, वरना pause कर देता है:

<video data-play-on-view muted playsinline loop preload="none"
       width="720" height="720" poster="/mascot-wave.webp">
  <source src="/mascot-wave.webm" type="video/webm">
  <source src="/mascot-wave.mp4" type="video/mp4">
</video>
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)");

const observer = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    const video = entry.target;
    if (entry.isIntersecting && !reduce.matches) {
      video.play().catch(() => {});
    } else {
      video.pause();
    }
  }
}, { threshold: 0.5 });

document.querySelectorAll("video[data-play-on-view]").forEach((v) => observer.observe(v));

muted attribute ज़रूरी है: MDN की autoplay गाइड कहती है कि autoplay blocking तब लागू नहीं होती जब "the audio track is muted", इसलिए user gesture के बिना play() सिर्फ़ बिना आवाज़ वाले वीडियो पर काम करता है। .catch() blocked play को error log करने से रोकता है।

एक बार वाले रिएक्शन के लिए, जैसे लोगो intro या मैस्कॉट का हाथ हिलाना, पहली बार चलने के बाद observer.unobserve(entry.target) call करें ताकि विज़िटर के हर बार scroll करने पर यह फिर से शुरू न हो। Rive फ़ाइल के लिए वही observer play() call करने के बजाय एक trigger fire कर सकता है (अगला सेक्शन देखें), और viewport से बाहर जाने पर Rive instance को r.pause() से pause कर सकता है।

Scroll के साथ Rive एनिमेशन को scrub कैसे करें?

State machine से, timeline से नहीं। Rive के web runtime में scrub() अब भी है, लेकिन उसके docs इसे "Deprecated in v2.41.0, use a state machine to control playback instead" बताते हैं। सपोर्टेड तरीका है 1D blend state: Rive के docs कहते हैं कि यह timelines को "with a single numerical view model property" मिलाता है, और इसके उपयोगों में "scrolling interactions" गिनाते हैं। Editor में शुरुआती pose को एक timeline में और आखिरी pose को दूसरी में key करें, एक number property (जैसे scrollProgress, range 0 से 100) से चलने वाला 1D blend state जोड़ें, और export करें।

Runtime पर उस number को data binding से scroll progress के हिसाब से सेट करें:

import { Rive } from "@rive-app/canvas";

const section = document.querySelector("#story");
const canvas = document.querySelector("#mascot");
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

const r = new Rive({
  src: "/mascot.riv",
  canvas,
  stateMachine: "State Machine 1",
  autoplay: true,
  autoBind: true,
  onLoad: () => {
    r.resizeDrawingSurfaceToCanvas();
    const progress = r.viewModelInstance?.number("scrollProgress");
    if (!progress || reduce) return;

    let queued = false;
    const update = () => {
      queued = false;
      const box = section.getBoundingClientRect();
      const range = box.height - window.innerHeight;
      const p = range > 0 ? Math.min(Math.max(-box.top / range, 0), 1) : 0;
      progress.value = Math.round(p * 100);
    };
    window.addEventListener("scroll", () => {
      if (!queued) {
        queued = true;
        requestAnimationFrame(update);
      }
    }, { passive: true });
    update();
  },
});

इसे ऐसे क्यों लिखा गया है: scroll listener passive है और requestAnimationFrame में हर फ़्रेम में ज़्यादा से ज़्यादा एक बार काम करता है, इसलिए scrolling को कभी उसका इंतज़ार नहीं करना पड़ता। पूरे steps में round करने से state machine तभी आगे बढ़ती है जब value बदलती है, और Rive बताता है कि जिस state machine के पास करने को कुछ न हो, वह "settles" होकर आगे बढ़ना बंद कर देती है। View model के बजाय state machine inputs इस्तेमाल करने वाली पुरानी फ़ाइलें r.stateMachineInputs() से अब भी काम करती हैं, लेकिन Rive अब inputs को सीधे सेट करने को deprecated कहता है और data binding की सलाह देता है।

हर scroll पल को scrubbing की ज़रूरत नहीं होती। अक्सर मूड बदलना काफ़ी होता है: पेज के ऊपर मैस्कॉट उत्सुक दिखता है और pricing table पर खुश। Charmotion कैरेक्टर सेट की Rive फ़ाइल पहले से Data Binding के ज़रिए एक mood number देती है जो उसके looping मूड बदलता है, और हर one-shot रिएक्शन के लिए एक trigger, जैसे success। Intersection Observer से mood सेट करने पर blend state बनाए बिना scroll को समझने वाला मैस्कॉट मिल जाता है। हर सेट की README में values की लिस्ट है। देखें यह कैसे काम करता है।

क्या scroll के साथ वीडियो scrub किया जा सकता है?

हाँ। currentTime सेट करने से seek होता है: MDN कहता है "changing the value of currentTime seeks the media to the new time", और ब्राउज़र position को ऐसी जगह पर adjust कर सकता है जिसे media सपोर्ट करता हो। requestAnimationFrame के अंदर scroll progress को time से जोड़ें:

const video = document.querySelector("#logo-turn");
const track = document.querySelector("#logo-turn-track");
let queued = false;

function update() {
  queued = false;
  if (!video.duration) return;
  const box = track.getBoundingClientRect();
  const range = box.height - window.innerHeight;
  const p = range > 0 ? Math.min(Math.max(-box.top / range, 0), 1) : 0;
  video.currentTime = p * video.duration;
}

window.addEventListener("scroll", () => {
  if (!queued) {
    queued = true;
    requestAnimationFrame(update);
  }
}, { passive: true });

यह छोटे, पहले से render किए गए शॉट्स के लिए सबसे अच्छा काम करता है, जैसे 90 डिग्री घूमता 3D लोगो, और इसके असली खर्च हैं:

  • Seeking का मतलब decode का काम है। Seek कितना smooth है, यह वीडियो की encoding और डिवाइस पर निर्भर करता है। ज़्यादा बार keyframes के साथ encode करने से आम तौर पर मदद मिलती है, लेकिन फ़ाइल बड़ी होती है। Mid-range फ़ोन पर टेस्ट करें।
  • पूरी फ़ाइल उपलब्ध होनी चाहिए। Scrubbing को preload="none" के साथ न मिलाएँ; सेक्शन पास आने पर उसे preload करें।
  • इसे छोटा और हल्का रखें। कुछ सेकंड, उसी साइज़ में जिसमें वह दिखता है। जिस लोगो को सिर्फ़ घूमना या scale होना है, उसके लिए SVG या इमेज पर CSS transforms बिना किसी वीडियो के वही काम करते हैं।
  • इसे एक poster दें जो resting फ़्रेम दिखाए, यही reduced-motion और बिना-JavaScript वाली स्टेट भी है।

Scroll एनिमेशन को smooth और आरामदायक कैसे रखें?

पहले smoothness। Chrome की गाइड बताती है कि scroll events एनिमेशन का कमज़ोर आधार क्यों हैं: ब्राउज़र एक अलग process पर scroll करते हैं और scroll events asynchronously भेजते हैं, और "main thread animations are subject to jank." CSS scroll-driven animations इससे बचते हैं और main thread से अलग चल सकते हैं। इन्हें हल्का रखें:

  • transform और opacity को एनिमेट करें। Scroll पर top, left, width या height बदलने से layout का काम होता है और, web.dev के अनुसार, layout shifts होते हैं।
  • हर स्क्रीन पर एक scrubbed एलिमेंट। एक लोगो, एक मैस्कॉट या एक product शॉट, तीनों नहीं।
  • JavaScript से चलने वाली हर चीज़ के लिए passive listeners और हर फ़्रेम में एक अपडेट, जैसा ऊपर के samples में है।
  • जो नहीं दिख रहा उसे pause करें। Scroll होकर दूर चला गया Rive canvas या वीडियो draw करना बंद कर दे।

फिर आराम। Scroll-linked मोशन वह किस्म है जो vestibular disorders वाले लोगों को सबसे ज़्यादा परेशान कर सकती है। SC 2.3.3 (Animation from Interactions, Level AAA) पर W3C की व्याख्या parallax scrolling को अक्सर गैर-ज़रूरी एनिमेशन बताती है और कहती है कि scrolling से शुरू होने वाला मोशन "can trigger vestibular disorders", जिसकी प्रतिक्रियाओं में "distraction, dizziness, headaches and nausea" शामिल हैं। व्यावहारिक नियम:

  • हर scroll एनिमेशन को @media (prefers-reduced-motion: no-preference) के अंदर रखें या JavaScript में matchMedia जाँचें, जैसा यहाँ के सभी samples करते हैं।
  • मूवमेंट छोटा रखें: कुछ दर्जन पिक्सेल, कुछ डिग्री। बड़े zoom और full-screen parallax से ही परेशानी शुरू होती है।
  • कंटेंट को कभी scroll एनिमेशन के पीछे न छिपाएँ। अगर एनिमेशन फ़ेल हो या बंद हो, तब भी लोगो और टेक्स्ट वहीं होने चाहिए।

Reduced-motion सेटिंग पर और जानकारी accessible animation और reduced motion में है।

Fallback के साथ scroll-driven लोगो एनिमेशन कैसे जोड़ें

  1. Resting लोगो को style करें. लोगो की सामान्य CSS को उसकी पूरी, static स्टेट के रूप में लिखें। पुराने ब्राउज़र और reduced-motion यूज़र्स यही देखेंगे।
  2. Keyframes लिखें. शुरुआती pose से resting pose तक सिर्फ़ transform और opacity को एनिमेट करें।
  3. Timeline जोड़ें. @supports (animation-timeline: view()) के अंदर animation shorthand सेट करें, फिर animation-timeline: view() या scroll(), फिर animation-range।
  4. मोशन सेटिंग्स का ध्यान रखें. Block को @media (prefers-reduced-motion: no-preference) में रखें।
  5. ज़रूरत हो तो play-once fallback जोड़ें. पुराने ब्राउज़र के लिए scroll listener के बजाय Intersection Observer से one-shot एनिमेशन शुरू करें।
  6. टेस्ट करें. Mid-range फ़ोन पर धीरे और तेज़ scroll करें, वापस ऊपर scroll करें, और reduced motion चालू करके static स्टेट जाँचें।

अक्सर पूछे जाने वाले सवाल

मेरा animation-timeline कुछ क्यों नहीं कर रहा?

सबसे आम वजह क्रम है: animation shorthand animation-timeline को reset कर देता है, इसलिए animation-timeline को उसके बाद declare करें। यह भी जाँचें कि एलिमेंट के पास सही axis पर scroll container है (अगर वह axis scroll नहीं होता तो view() inactive रहता है) और ब्राउज़र इसे सपोर्ट करता है: Chrome 115, Firefox 159 और Safari 26 या नया।

क्या नवंबर 2026 में भी मुझे scroll-driven animation polyfill चाहिए?

लोगो के लिए आम तौर पर नहीं। नवंबर 2026 तक CSS scroll-driven animations मौजूदा Chrome, Edge, Firefox और Safari में सपोर्टेड हैं। पुराने ब्राउज़र के लिए polyfill लोड करने के बजाय resting लोगो दिखाएँ या Intersection Observer से one-shot एनिमेशन चलाएँ।

क्या Rive एनिमेशन scroll position के साथ चल सकता है?

हाँ। Rive में एक number view model property से चलने वाला 1D blend state बनाएँ, फिर उस number को passive scroll listener में scroll progress से सेट करें, हर फ़्रेम में ज़्यादा से ज़्यादा एक बार। Rive का scrub() method अब भी मौजूद है लेकिन runtime v2.41.0 से deprecated है।

स्रोत

संबंधित गाइड