कंटेंट पर जाएँ
charmotion

ऐप या वेबसाइट में लोडिंग एनिमेशन कैसे जोड़ें

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

गाइड का कवर इलस्ट्रेशन: ऐप या वेबसाइट में loading एनिमेशन कैसे जोड़ें, Charmotion के डेमो कैरेक्टर के साथ

लोडिंग एनिमेशन जोड़ने से पहले तय करें कि इंतज़ार कितना लंबा है: लगभग एक सेकंड से कम हो तो कुछ न दिखाएँ, करीब 2-10 सेकंड के लिए लूप होने वाला spinner या कैरेक्टर, और उससे ज़्यादा के लिए प्रतिशत दिखाने वाला बार। फिर इसे सिर्फ़ तभी रेंडर करें जब काम बाकी हो, role="status" से इसकी सूचना दें और मोशन कम करें सेटिंग का ध्यान रखें।

मुख्य बातें

  • इंडिकेटर को इंतज़ार के हिसाब से चुनें: लगभग 1 सेकंड से कम पर कुछ नहीं, 2-10 सेकंड के लिए लूप, 10 सेकंड या ज़्यादा के लिए progress bar।
  • लोडर को थोड़ी देर से दिखाएँ, ताकि तेज़ रिस्पॉन्स पर spinner झलक कर न जाए।
  • सिर्फ़ transform और opacity को एनिमेट करें, ताकि main thread व्यस्त होने पर भी लोडर स्मूद चले।
  • विज़ुअल के साथ role="status" टेक्स्ट और aria-busy जोड़ें, ताकि screen reader इस्तेमाल करने वालों को पता चले कि कुछ हो रहा है।
  • ब्रांडेड कैरेक्टर लूप होने वाले इंडिकेटर के रूप में अच्छा काम करता है; लंबे कामों में यह progress bar की जगह नहीं ले सकता।
  • लोगो लोडर के लिए लोगो को घूमती रिंग के अंदर स्थिर रखें, या उसे एक हल्की, सीमलेस पल्स दें; मोशन कम करें चालू होने पर यह अतिरिक्त मोशन बंद कर दें।

पहले से कोई कैरेक्टर या लोगो है? अपने कैरेक्टर को असली ऐप स्क्रीन में देखें: स्प्लैश, ऑनबोर्डिंग, लोडिंग और एम्प्टी स्टेट स्क्रीन। यह फ़्री है, आपके ब्राउज़र में चलता है और कुछ भी अपलोड नहीं होता।

Spinner, skeleton, progress bar या ब्रांडेड लोडर: कौन सा चुनें?

इंडिकेटर पहले अनुमानित इंतज़ार के हिसाब से चुनें, फिर संदर्भ के हिसाब से। Nielsen Norman Group की गाइडेंस समय की सीमाएँ बताती है: लगभग एक सेकंड से कम के एक्शन के लिए कोई इंडिकेटर नहीं, करीब 2-10 सेकंड के इंतज़ार के लिए spinner जैसा लूप होने वाला इंडिकेटर, और 10 सेकंड या उससे ज़्यादा लगने वाली किसी भी चीज़ के लिए प्रतिशत दिखाने वाला इंडिकेटर (NN/g)। ये सीमाएँ Nielsen की response-time सीमाओं पर आधारित हैं: 0.1 सेकंड तुरंत लगता है, 1 सेकंड तक यूज़र के सोचने का सिलसिला बना रहता है, और 10 सेकंड लगभग ध्यान टिकने की सीमा है।

स्थितिइस्तेमाल
~1 सेकंड से कमकोई लोडर नहीं। कंट्रोल पर तुरंत फ़ीडबैक दें (pressed स्टेट, disabled बटन)।
पेज या लिस्ट जिसका लेआउट आपको पहले से पता हैSkeleton: कंटेंट के आकार के ग्रे प्लेसहोल्डर, जो उसी जगह असली कंटेंट से बदल जाते हैं।
2-10 सेकंड, प्रोग्रेस का पता नहींलूप होने वाला spinner या लूप होने वाला कैरेक्टर।
10+ सेकंड, या मापा जा सकने वाला काम (अपलोड, एक्सपोर्ट)काम कितना पूरा हुआ, यह प्रतिशत में दिखाने वाला progress bar, चाहें तो साथ में एक कैरेक्टर भी।

Skeleton और spinner एक-दूसरे के प्रतिद्वंद्वी नहीं हैं। Skeleton बताता है कि कंटेंट कहाँ दिखेगा; spinner या कैरेक्टर बताता है कि काम चल रहा है। कई स्क्रीन पहली बार पेज लोड होने पर skeleton और बाद के एक्शन, जैसे "load more", के लिए छोटा spinner इस्तेमाल करती हैं। इन समय-सीमाओं की पूरी जानकारी के लिए एनिमेशन की अवधि और लोडिंग UX देखें।

सिर्फ़ CSS से loader कैसे बनाएँ?

CSS spinner के लिए एक element, एक keyframe rule चाहिए, JavaScript की कोई ज़रूरत नहीं। इसे transform से घुमाएँ: web.dev सलाह देता है कि एनिमेशन को transform और opacity तक सीमित रखें, क्योंकि ये compositing stage पर ही रहते हैं, इसलिए scripts चलते समय भी spinner घूमता रहता है (web.dev)।

<div class="loader" role="status">
  <span class="spinner" aria-hidden="true"></span>
  <span class="visually-hidden">Loading results…</span>
</div>

<style>
.spinner {
  display: inline-block;
  width: 32px;
  height: 32px;
  border: 3px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
</style>

Spinner को fixed width और height दें, ताकि दिखते समय वह layout को न खिसकाए। currentColor इस्तेमाल करें, ताकि light और dark दोनों themes में वह text का रंग ले ले।

Skeleton भी उतना ही आसान है: fixed size और background color वाले blocks, चाहें तो transform से हिलाए गए animated gradient से बनी shimmer के साथ। Shimmer हल्की रखें, और मोशन कम करें सेटिंग चालू होने पर उसे हटा दें।

अपने लोगो के साथ loading एनिमेशन कैसे बनाएँ?

लोगो loading एनिमेशन, यानी आपके लोगो वाला loading spinner, तब सबसे अच्छा काम करता है जब लोगो पढ़ने लायक बना रहे। ज़्यादातर ब्रांड के लिए तीन pattern काफ़ी हैं:

  • घूमती रिंग के अंदर लोगो। लोगो स्थिर रहता है और उसके चारों ओर एक रिंग घूमती है। यह सबसे साफ़ पढ़ा जाने वाला विकल्प है और किसी भी आकार के लोगो के लिए काम करता है।
  • हल्की pulse। लोगो कुछ प्रतिशत छोटा होकर वापस आता है, साथ में opacity में हल्का बदलाव। छोटे symbols और ऐप आइकन के लिए अच्छा है।
  • लोगो खुद घूमता है। सिर्फ़ गोल, symmetrical लोगो के लिए; wordmark या asymmetric आइकन पढ़ना मुश्किल हो जाता है और चक्कर जैसा महसूस हो सकता है।
<div class="logo-loader" role="status">
  <img src="/logo-mark.svg" alt="" width="40" height="40">
  <span class="visually-hidden">Loading…</span>
</div>

<style>
.logo-loader {
  position: relative; display: grid; place-items: center;
  width: 64px; height: 64px;
}
.logo-loader::after {
  content: ""; position: absolute; inset: 0;
  border: 3px solid currentColor; border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
.logo-loader img { animation: breathe 1.8s ease-in-out infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes breathe { 50% { transform: scale(0.92); opacity: 0.8; } }

@media (prefers-reduced-motion: reduce) {
  .logo-loader::after { animation-duration: 2.7s; }
  .logo-loader img { animation: none; }
}
</style>

दोनों एनिमेशन सिर्फ़ transform और opacity इस्तेमाल करते हैं, और fixed size जगह पहले से रिज़र्व कर देता है, इसलिए कुछ नहीं खिसकता। खाली alt की वजह से screen reader लोगो पढ़ने के बजाय "Loading…" text पढ़ते हैं।

लूप कितना लंबा हो? कोई guideline लूप की लंबाई तय नहीं करती। ज़रूरी यह है कि वह seamless हो (आखिरी फ़्रेम पहले फ़्रेम में सहज रूप से जुड़े), रफ़्तार तेज़-धीमी होने के बजाय एक जैसी रहे, और इतना छोटा हो कि आम 2 से 10 सेकंड के इंतज़ार में कुछ बार दोहराया जा सके। Pulse को कभी flashing न बनने दें: WCAG 2.3.1 किसी भी एक सेकंड में अधिकतम तीन flash की सीमा तय करता है (W3C)।

मोशन कम करें: indicator रखें, अतिरिक्त मोशन हटाएँ। उदाहरण में रिंग धीमी हो जाती है और लोगो की pulse रुक जाती है, जबकि status text अब भी इंतज़ार की सूचना देता है। ऐप शुरू होते समय full-screen loader के नियम अलग हैं; अपने ऐप आइकन को लॉन्च इंट्रो में बदलना देखें।

Loading के दौरान ब्रांडेड कैरेक्टर कैसे दिखाएँ?

कैरेक्टर personality वाला लूपिंग इंडिकेटर है, इसलिए वह spinner की तरह 2 से 10 सेकंड के दायरे में आता है। यह उन जगहों पर सबसे अच्छा काम करता है जहाँ यूज़र पहले से रुकते हैं: इमेज जनरेट होते समय, मैसेज भेजते समय, लाइब्रेरी सिंक होते समय।

loading: mood 5, काम चलने तक लूप होता है।

Rive file में loader अलग asset नहीं, बल्कि स्टेट मशीन की एक स्टेट होता है। काम चलते समय आप एक नंबर को loading मूड पर सेट करते हैं और काम खत्म होने पर success या error ट्रिगर फ़ायर करते हैं, इसलिए वही कैरेक्टर नतीजा भी दिखा देता है। वेब पर:

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

const r = new Rive({
  src: "/character.riv",
  canvas: document.querySelector("#mascot"),
  stateMachine: "CharacterStateMachine",
  autoplay: true,
  onLoad: () => {
    r.resizeDrawingSurfaceToCanvas();
    runWithMascot();  // inputs are available once the file has loaded
  },
});

function setMood(n) {
  const mood = r.stateMachineInputs("CharacterStateMachine").find((i) => i.name === "mood");
  if (mood) mood.value = n;
}
function fire(name) {
  r.stateMachineInputs("CharacterStateMachine").find((i) => i.name === name)?.fire();
}

async function runWithMascot() {
  setMood(5);                                    // loading loop
  await doWork().then(() => fire("success"), () => fire("error"));
  setMood(0);                                    // back to idle
}

Charmotion files ठीक इसी के लिए बनी हैं: आपके अपने मैस्कॉट से बने सेट में मूड 5 loading लूप है (1.2 सेकंड, seamless) और मूड 3 thinking है (2.4 सेकंड), साथ में success और error ट्रिगर जो मौजूदा मूड पर लौट आते हैं। 3D या gradient लोगो को फिर से बनाए बिना जैसे के तैसे एनिमेट किया जाता है, इसलिए यही तरीका लोगो loader के लिए भी काम करता है। यही स्टेट Data Binding के लिए Character व्यू मॉडल के ज़रिए भी उपलब्ध हैं। अगर काम लंबा है और मापा जा सकता है, तो कैरेक्टर के साथ असली progress bar भी रखें।

Loader सिर्फ़ तभी कैसे दिखाएँ जब काम चल रहा हो?

Loader को timer से नहीं, request से जोड़ें, और उसे दिखाने से पहले थोड़ी देर रुकें। क्योंकि लगभग एक सेकंड से कम के actions के लिए users को किसी indicator की ज़रूरत नहीं होती, कुछ सौ milliseconds से एक सेकंड तक की देरी तेज़ responses पर loader को छिपा देती है और ध्यान भटकाने वाली झलक से बचाती है।

async function withLoader(region, task, delay = 600) {
  region.setAttribute("aria-busy", "true");
  const timer = setTimeout(() => region.classList.add("is-loading"), delay);
  try {
    return await task();
  } finally {
    clearTimeout(timer);
    region.classList.remove("is-loading");
    region.setAttribute("aria-busy", "false");
  }
}

finally block ज़रूरी है: errors और cancellations पर भी loader हटना चाहिए, वरना स्क्रीन हमेशा घूमती रहेगी। React में यही तरीका एक pending state है, जो request से पहले set होती है और finally में clear होती है, और loader शर्त के आधार पर render होता है।

Native platforms पर built-in components ही default विकल्प हैं। SwiftUI में indeterminate spinner के लिए ProgressView() और determinate bar के लिए ProgressView(value:) है; Jetpack Compose में progress value के साथ या उसके बिना CircularProgressIndicator और LinearProgressIndicator हैं। कैरेक्टर view सिर्फ़ वहीं लगाएँ जहाँ ब्रांड का पल इसके लायक हो, और उसे दिखाने-छिपाने के लिए वही pending flag इस्तेमाल करें।

Loader को accessible कैसे बनाएँ?

तीन बातें loader को हर किसी के लिए काम का बनाती हैं:

  • इसकी सूचना दें। "Loading results…" जैसा छोटा text role="status" वाले element में रखें। यह एक live region है, जिसे screen reader focus हटाए बिना, बीच में टोके बगैर पढ़ते हैं (MDN)। सजावटी spinner या कैरेक्टर को aria-hidden="true" से छिपाएँ।
  • Region को busy चिह्नित करें। अपडेट हो रहे container पर aria-busy="true" सेट करें और काम पूरा होने पर वापस false करें, ताकि assistive technology अंतिम content का इंतज़ार कर सके।
  • मोशन कम करें सेटिंग का सम्मान करें। prefers-reduced-motion: reduce media query operating system की reduce-motion सेटिंग को दर्शाती है (MDN)। Spinner धीमा करें, उछलते कैरेक्टर की जगह स्थिर pose और text दिखाएँ, या सादा progress bar दिखाएँ। SwiftUI में @Environment(\.accessibilityReduceMotion) पढ़ें।

WCAG 2.2 SC 2.2.2 (Pause, Stop, Hide) आमतौर पर माँग करता है कि दूसरे content के साथ पाँच सेकंड से ज़्यादा चलने वाले मोशन को रोकने का तरीका हो। इसमें बताया गया है कि preload phase के दौरान का एनिमेशन तब essential माना जा सकता है जब उस समय कोई interaction संभव न हो (W3C)। ऐसे content के पास वाला loader, जिसे user अब भी इस्तेमाल कर सकता है, इस छूट में नहीं आता, इसलिए काम खत्म होते ही उसे रोक दें। ज़्यादा जानकारी accessible एनिमेशन और मोशन कम करें में है।

Loading एनिमेशन की सबसे आम गलतियाँ क्या हैं?

  • तुरंत होने वाले actions के लिए loader। 150 ms के लिए दिखने वाला spinner glitch जैसा लगता है। उसे देर से दिखाएँ।
  • दो मिनट के एक्सपोर्ट पर spinner। लगभग 10 सेकंड के बाद users जानना चाहते हैं कि कितना बाकी है। प्रतिशत वाला bar या स्टेप की गिनती दिखाएँ।
  • आंशिक updates के लिए full-screen blocker। अगर सिर्फ़ एक list refresh हो रही है, तो indicator उसी list में रखें और बाकी स्क्रीन इस्तेमाल के लायक रहने दें।
  • लेआउट शिफ़्ट। जो loader दिखते समय content को नीचे धकेले और फिर वापस खींचे, वह loader न होने से भी बुरा है। उसकी जगह रिज़र्व करें या उसे overlay करें।
  • भारी loader assets। बड़ा GIF या video loader डाउनलोड होने में उस काम से ज़्यादा समय ले सकता है जिसके दौरान वह दिखता है। CSS spinner कुछ lines का होता है; छोटी Rive file आमतौर पर कुछ दर्जन kilobytes की होती है।
  • अटकी हुई स्टेट। Errors और timeouts पर loader हमेशा हटाएँ, और उसकी जगह साफ़ message और दोबारा कोशिश करने का विकल्प दें।

अगर कैरेक्टर success और error स्टेट भी दिखाता है, तो events को रिएक्शन से जोड़ने के लिए मैस्कॉट एनिमेशन स्टेट देखें।

Loading एनिमेशन कैसे जोड़ें

  1. इंतज़ार का अनुमान लगाएँ. आम अवधि मापें। लगभग 1 सेकंड से कम के लिए loader की ज़रूरत नहीं, 2 से 10 सेकंड के लिए looping indicator, 10 सेकंड या ज़्यादा के लिए प्रतिशत वाला bar।
  2. Indicator चुनें. जहाँ layout पता हो वहाँ skeleton, अनजाने छोटे इंतज़ार के लिए spinner या कैरेक्टर लूप, और मापे जा सकने वाले काम के लिए progress bar इस्तेमाल करें।
  3. हल्की properties से बनाएँ. CSS में सिर्फ़ transform और opacity एनिमेट करें, या कैरेक्टर के लिए loading मूड वाली छोटी Rive file इस्तेमाल करें।
  4. इसे request से जोड़ें. Request pending रहने तक थोड़ी देरी के बाद loader दिखाएँ, और उसे finally block में हटाएँ ताकि errors पर भी वह हट जाए।
  5. इसे accessible बनाएँ. role="status" text जोड़ें, aria-busy toggle करें, सजावटी मोशन को screen readers से छिपाएँ, और मोशन कम करें सेटिंग में उसे धीमा करें या बदलें।

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

Loading spinner दिखाने से पहले कितना इंतज़ार करना चाहिए?

इतनी देर रुकें कि तेज़ जवाबों में यह कभी न दिखे। Nielsen Norman Group की सलाह है कि लगभग एक सेकंड से कम समय लेने वाले कामों के लिए कोई indicator न दिखाएँ, इसलिए कुछ सौ मिलीसेकंड से एक सेकंड तक की देरी अच्छा काम करती है। अगर request पहले पूरी हो जाए, तो देरी को हमेशा रद्द करें।

क्या skeleton screen, spinner से बेहतर है?

कोई भी हर जगह बेहतर नहीं है। Skeleton उस कंटेंट के लिए सही है जिसका layout आपको पहले से पता हो, जैसे feed या product grid, क्योंकि पेज अपनी जगह पर भरता हुआ दिखता है। Spinner उन कामों के लिए सही है जिनका layout पहले से तय न हो। कई ऐप पहली बार loading पर skeleton और उसके बाद spinner इस्तेमाल करते हैं।

क्या मैस्कॉट, progress bar की जगह ले सकता है?

लंबे कामों के लिए नहीं। लूप होता मैस्कॉट बताता है कि काम चल रहा है, पर यह नहीं कि कितना बाकी है। इसे लगभग 2 से 10 सेकंड के इंतज़ार के लिए इस्तेमाल करें, और 10 सेकंड या उससे ज़्यादा के लिए प्रतिशत दिखाने वाला progress bar दिखाएँ, चाहें तो उसके पास मैस्कॉट भी रखें।

अपने लोगो के साथ loading spinner कैसे बनाएँ?

लोगो को स्थिर रखकर एक CSS रिंग के बीच में रखें जो transform से घूमती हो, या लोगो को ही हल्का scale और opacity वाला pulse दें। पूरे लोगो को तभी घुमाएँ जब वह गोल और symmetrical हो। role="status" वाला टेक्स्ट जोड़ें, इमेज को screen readers से छिपाएँ, और मोशन कम करें सेटिंग चालू होने पर मोशन को धीमा करें या रोक दें।

क्या मोशन कम करें सेटिंग में loader रुक जाना चाहिए?

उसे गायब होने की बजाय शांत हो जाना चाहिए, क्योंकि यूज़र्स को अब भी पता होना चाहिए कि काम चल रहा है। रोटेशन धीमा करें, उछलते कैरेक्टर को स्थिर pose में बदलें, या progress bar दिखाएँ, और role="status" वाला टेक्स्ट बनाए रखें ताकि स्टेट की जानकारी अब भी announce होती रहे।

इस गाइड से झटपट जवाब

स्रोत

संबंधित गाइड