Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Responsive Design Patterns w React - Adaptacja do Kazdej Przestrzeni

Pilotze, Twoj statek kosmiczny musi dzialac rownie dobrze na malym ekranie nadrecznego terminala, co na wielkim monitorze centrum dowodzenia. W swiecie React responsive design oznacza tworzenie komponentow, ktore elegancko dostosowuja sie do kazdego rozmiaru ekranu -- od mobilnego urządzenia po ultraszeroki monitor.

Hook useMediaQuery -- responsywnosc w JavaScript

Czasem potrzebujesz zmienic nie tylko style, ale cala strukture komponentu w zaleznosci od rozmiaru ekranu. Wtedy przydaje sie custom hook

useMediaQuery
:

1function useMediaQuery(query) {
2  const [matches, setMatches] = useState(
3    () => window.matchMedia(query).matches
4  );
5
6  useEffect(() => {
7    const mediaQuery = window.matchMedia(query);
8    const handler = (e) => setMatches(e.matches);
9
10    mediaQuery.addEventListener('change', handler);
11    return () => mediaQuery.removeEventListener('change', handler);
12  }, [query]);
13
14  return matches;
15}

Uzycie w komponencie:

1function MissionDashboard() {
2  const isMobile = useMediaQuery('(max-width: 767px)');
3  const isTablet = useMediaQuery('(min-width: 768px) and (max-width: 1023px)');
4
5  if (isMobile) return <MobileDashboard />;
6  if (isTablet) return <TabletDashboard />;
7  return <DesktopDashboard />;
8}

Hook slucha na zmiany rozmiaru okna i zwraca

true
/
false
-- React automatycznie przerenderuje komponent gdy wartosc sie zmieni.

Mobile-first CSS w React

Podejscie mobile-first oznacza: zaczynamy od stylow dla najmalszych ekranow, a potem rozszerzamy dla wiekszych. Tak jak projektowanie kokpitu od najprostszego terminala w gore:

1/* Bazowe style -- mobile */
2.grid {
3  display: grid;
4  grid-template-columns: 1fr;
5  gap: 16px;
6}
7
8/* Tablet -- rozszerzamy */
9@media (min-width: 768px) {
10  .grid {
11    grid-template-columns: repeat(2, 1fr);
12  }
13}
14
15/* Desktop -- jeszcze szerzej */
16@media (min-width: 1024px) {
17  .grid {
18    grid-template-columns: repeat(3, 1fr);
19  }
20}

Responsywna kompozycja komponentow

Zamiast jednego ogromnego komponentu z wieloma warunkami, warto dzielic UI na mniejsze czesci, ktore mozna roznie komponowac:

1function Sidebar({ items }) {
2  return (
3    <nav className="sidebar">
4      {items.map(item => (
5        <a key={item.id} href={item.href}>{item.label}</a>
6      ))}
7    </nav>
8  );
9}
10
11function BottomNav({ items }) {
12  return (
13    <nav className="bottom-nav">
14      {items.map(item => (
15        <a key={item.id} href={item.href}>{item.icon}</a>
16      ))}
17    </nav>
18  );
19}
20
21function Navigation({ items }) {
22  const isMobile = useMediaQuery('(max-width: 767px)');
23  return isMobile ? <BottomNav items={items} /> : <Sidebar items={items} />;
24}

Na mobilce nawigacja jest na dole ekranu (jak w aplikacji), a na desktopie -- z boku jako sidebar. Ten sam zestaw danych, rozna prezentacja.

Container Queries w React

Container queries to nowa, potezna funkcja CSS. Pozwalaja stylowac element na podstawie rozmiaru jego rodzica, a nie calego okna przegladarki:

1.card-container {
2  container-type: inline-size;
3}
4
5@container (min-width: 400px) {
6  .card {
7    display: flex;
8    gap: 16px;
9  }
10}
11
12@container (min-width: 600px) {
13  .card {
14    grid-template-columns: 1fr 2fr;
15  }
16}

W React ustawiamy

container-type
na rodzicu:

1function CardGrid({ children }) {
2  return (
3    <div style={{ containerType: 'inline-size' }}>
4      {children}
5    </div>
6  );
7}

Container queries sa swietne dla komponentow reuzywanych -- karta misji moze wygladac inaczej w waskim sidebarze i szerokim main content, bez wiedzy o rozmiarze okna.

Fluid Typography -- plynna typografia

Zamiast skokowo zmieniać rozmiar czcionki miedzy breakpointami, mozna uzyc

clamp()
dla plynnego skalowania:

1.heading {
2  /* Minimalnie 18px, optymalnie 4vw, maksymalnie 36px */
3  font-size: clamp(18px, 4vw, 36px);
4}
5
6.body-text {
7  font-size: clamp(14px, 2vw, 18px);
8  line-height: clamp(20px, 3vw, 28px);
9}

W React mozna to zaimplementowac jako system:

1const fluidType = {
2  heading: 'clamp(18px, 4vw, 36px)',
3  subheading: 'clamp(16px, 3vw, 24px)',
4  body: 'clamp(14px, 2vw, 18px)',
5  caption: 'clamp(11px, 1.5vw, 14px)',
6};
7
8function Heading({ children }) {
9  return <h1 style={{ fontSize: fluidType.heading }}>{children}</h1>;
10}

Responsive Images w React

Obrazy to czesto najciezsze zasoby na stronie. React pozwala implementowac responsywne obrazy:

1function ResponsiveImage({ src, alt, sizes }) {
2  return (
3    <img
4      src={src}
5      alt={alt}
6      srcSet={`${src}?w=400 400w, ${src}?w=800 800w, ${src}?w=1200 1200w`}
7      sizes={sizes || '(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw'}
8      loading="lazy"
9      style={{ width: '100%', height: 'auto' }}
10    />
11  );
12}

Atrybut

srcSet
mowi przegladarce o dostepnych rozmiarach, a
sizes
-- ktory rozmiar uzyc przy danym rozmiarze okna.

Kiedy CSS, kiedy JavaScript?

  • Media queries w CSS -- gdy zmieniasz tylko style (kolory, rozmiary, uklad)
  • useMediaQuery w JS -- gdy zmieniasz strukture komponentu (inne komponenty, inna logika)
  • Container queries -- gdy komponent musi reagowac na rozmiar swojego kontenera
  • clamp() -- dla plynnego skalowania wartosci miedzy minimum a maksimum
Vai a CodeWorlds