Svi članci
How to11. pro 2024. · 7 min čitanja

Kako napraviti gumb koji ne mijenja veličinu tijekom loading-a?

Naučite kako spriječiti pomake u izgledu gumba tijekom loading state-a koristeći grid-stacking ili apsolutno pozicioniranje uz stručne uvide AS Agency-a.

Antonio ŠumakOsnivač, AS Agency
Kako napraviti gumb koji ne mijenja veličinu tijekom loading-a?

Problem 💡

Jeste li se ikada susreli sa situacijom gdje trebate implementirati loading state za gumb, ali nakon klika gumb mijenja veličinu?

Gumb koji mijenja velicinu u loading state-u
Gumb koji mijenja velicinu u loading state-u

Ovo ponašanje može izgledati nespretno, neprofesionalno i neprijateljski prema korisniku. Također uvodi pomake u izgledu, što negativno utječe na korisničko iskustvo vaše web stranice i SEO izvedbu. Kako to spriječiti? Kako pristupiti ovom problemu?

Postoje dva glavna pristupa za rješavanje ovog problema, ali jedan se ističe kao bolji. Istražimo oba.

  1. Absolute positioning pristup
  2. Grid stacking pristup

Početni pristup

U početku biste mogli pomisliti prikazati tekst prema zadanim postavkama i, kada je loading state aktivan, zamijeniti tekst spinnerom. Evo kako možete kreirati osnovnu komponentu gumba:

TypeScript
import Spinner from './spinner';

type TProps = {
  text: string;
  isLoading?: boolean;
  onClick: () => void;
};
const Button = ({ text, isLoading, onClick }: TProps) => {
  return (
    <button
      onClick={onClick}
      className='px-4 py-2 bg-purple-500 text-white flex justify-between items-center'
    >
      {!isLoading ? <span>{text}</span> : <Spinner />}
    </button>
  );
};

export default Button;

Kao što vidite, ovo je jednostavna komponenta gumba s isLoading svojstvom koje određuje hoće li biti prikazan tekst ili spinner.

TypeScript
'use client';

import Button from './components/button';
import { useState } from 'react';

export default function Home() {
  const [isLoading, setIsLoading] = useState(false);
  
  const handleLoading = () => {
    setIsLoading(true);
    setTimeout(() => {
      setIsLoading(false);
    }, 3000);
  };
  
  return (
    <main className='grid place-items-center h-screen'>
      <Button
        text='Submit this form'
        onClick={() => handleLoading()}
        isLoading={isLoading}
      />
    </main>
  );
}

Evo kako biste prikazali komponentu gumba.

Međutim, ovaj pristup dovodi do problema s promjenom veličine: kada se prikazuje tekst, gumb ima veću veličinu, a kada se aktivira loading state, gumb postaje uži. Ovdje trebamo ponovno razmotriti rješenje.

1. Absolute Positioning pristup 📊

Kako biste riješili problem promjene veličine, možete koristiti apsolutno pozicioniranje. Ovo zahtijeva nekoliko prilagodbi unutar komponenti gumba i spinnera.

TypeScript
import Spinner from './spinner';

type TProps = {
  text: string;
  isLoading?: boolean;
  onClick: () => void;
};
const Button = ({ text, isLoading, onClick }: TProps) => {
  return (
    <button
      onClick={onClick}
      className='px-4 py-2 bg-purple-500 text-white flex justify-between items-center relative'
    >
      <span className={`${isLoading ? 'invisible' : 'visible'}`}>{text}</span>
      {isLoading && (
        <div className='absolute inset-0 w-full flex items-center justify-center'>
          <Spinner />
        </div>
      )}
    </button>
  );
};

export default Button;

Promjene uključuju dodavanje klase relative gumbu, izmjenu načina prikazivanja teksta gumba tijekom loading state i omatanje komponente Spinner dodatnim spremnikom.

Ali u čemu je nedostatak ovog pristupa? Iako rješava problem promjene veličine, uvodi novi problem - preljev teksta.

Problem sa absolute pristupom
Problem sa absolute pristupom

Kao što je ovdje prikazano, ako je poruka loading state dulja od početnog teksta gumba, dolazi do prelijevanja teksta. Za rješavanje ovog problema potrebno je bolje rješenje.

2. Grid Stacking pristup 🌐

Grid stacking pruža elegantan i robustan način rješavanja ovog problema. Kod ovog pristupa sve promjene potrebne su unutar same komponente gumba.

TypeScript
import Spinner from './spinner';

type TProps = {
  text: string;
  isLoading?: boolean;
  onClick: () => void;
};
const Button = ({ text, isLoading, onClick }: TProps) => {
  return (
    <button
      onClick={onClick}
      className={`px-4 py-2 bg-purple-500 text-white grid [grid-template-areas:stack]`}
    >
      <span
        className={`[grid-area:stack] ${!isLoading ? 'visible' : 'invisible'}`}
      >
        {text}
      </span>
      <Spinner
        className={`[grid-area:stack] place-self-center ${
          isLoading ? 'visible' : 'invisible'
        }`}
      />
    </button>
  );
};

export default Button;

Prvo, trebate dodati grid kao className gumbu, čime omogućavate CSS Grid izgled. Ključni className ovdje je [grid-template-areas:stack], koji definira jedno grid područje nazvano stack. Ovo osigurava da se svi child elementi slažu jedan na drugi.

Kako bi grid-područja radila, primijenite [grid-area:stack] na tekst gumba i komponentu Spinner. Dodatno, koristite className poput visible i invisible za upravljanje vidljivošću elemenata prema potrebi.

Grid stacking pristup output
Grid stacking pristup output

Izlaz spinnera ostaje identičan pristupu s apsolutnim pozicioniranjem. Međutim, grid stacking nudi značajnu prednost.

Grid stacking approach sa dužom loading porukom
Grid stacking approach sa dužom loading porukom

Kao što je prikazano, grid pristup uzima u obzir najveći child element prilikom određivanja veličine gumba. To znači da početna veličina gumba već uključuje dulju poruku loading state, sprječavajući pomake u izgledu.

Zaključak 🔧

Ovaj blog post detaljno opisuje dva pristupa za rješavanje problema promjene veličine gumba tijekom loading state: apsolutno pozicioniranje i grid stacking. Iako apsolutno pozicioniranje nudi brzo rješenje, grid stacking se pokazuje kao superiornije rješenje jer izbjegava preljev teksta i pomake u izgledu, čime poboljšava korisničko iskustvo i održava SEO izvedbu.

U AS Agency, mi pažljivo pristupamo ovim nijansama kako bismo osigurali da web stranice naših klijenata budu dotjerane, prilagođene korisnicima i optimizirane za najbolju izvedbu. Ako tražite tim koji prioritet daje svakom detalju kako bi isporučio izvanredne rezultate, ne tražite dalje. Stvorimo nešto nevjerojatno zajedno! ✨

Napisao Antonio Šumak

Osnivač AS Agency. Dizajniram i izrađujem brze web stranice za male tvrtke — i zapisujem ono što naučim usput.

Podijeli

Rezervacije za list. / stu. 2026. · 2 slobodna mjesta

Spremni pokazati svijetusvoj posao?

Razgovarajmo o vašoj ideji na besplatnom, opuštenom pozivu od 30 minuta. Otići ćete s jasnim planom i poštenom ponudom.

Zagreb--:--New York--:--