Powrót do strony głównej

CSS dla dużych rozwijanych menu w formularzach

Artykuł omawia problem ograniczonych rozwijanych menu w formularzach i proponuje rozwiązania CSS do ich rozszerzenia. Podane są przykłady kodu w CSS i React dla middle/senior deweloperów. Zwrócono uwagę na accessibility i wydajność.

Rozszerz dropdown: CSS-hak dla deweloperów FE
Advertisement 728x90

Optymalizacja menu rozwijanych w formularzach: problemy i rozwiązania CSS

Frontendowi często napotykają się na elementy select, gdzie wysokość listy rozwijanej jest sztywno ograniczona do 4–5 pozycji. To tworzy barierę dla użytkowników: pełna lista z ponad 100 opcjami nie da się obejrzeć bez męczącego przewijania przez wąską szczelinę. W rezultacie spada użyteczność — użytkownik nie może szybko ocenić dostępnych rozwiązań i wybrać odpowiednie.

Typowy scenariusz: formularz publikacji artykułu z polami "Celem jest" i "Haby". Wyszukiwanie pomaga wpisać dokładny żądanie, ale bez wcześniejszego zapoznania się ze spiskiem jest bezużyteczne. Przewijanie wymaga 20–50 iteracji kółkiem myszy, co irytuje i zużywa czas.

Rozwiązanie CSS do rozszerzenia listy

Problem można rozwiązać prostymi regułami CSS, które stosuje się przez narzędzia deweloperskie lub w stylach komponentu. Zwiększenie wysokości do rozsądnego limitu (max-height: 80vh lub stałe 400–500px) pozwala wyświetlić od razu 20–30 elementów, minimalizując potrzebę przewijania.

Google AdInline article slot

Przykład stylów dla niestandardowego selecta lub elementu natywnego:

.select-container {
  position: relative;
}

.select-dropdown {
  max-height: 80vh !important;
  overflow-y: auto;
  position: absolute;
  z-index: 1000;
  width: 100%;
  background: white;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.select-option {
  padding: 12px 16px;
  cursor: pointer;
}

.select-option:hover {
  background: #f5f5f5;
}

To rozwiązanie wykorzystuje dostępne miejsce na ekranie, nie naruszając układu. Dla dużych monitorów efekt jest szczególnie widoczny — użytkownik widzi kontekst całościowo.

Antypattern: ignorowanie rzeczywistego rozmiaru danych

Ograniczone listy rozwijane to klasyczny antypattern UX. Projektanci rysują prototypy dla 3–5 elementów, a frontend realizuje je dokładnie, nie uwzględniając przypadków skrajnych. Wynik: interfejs, który nie skaluje się pod rzeczywiste dane.

Google AdInline article slot

Główne cechy antypatternu:

  • Stała wysokość listy rozwijanej < 200px przy liście > 20 pozycji.
  • Brak wirtualnego przewijania lub paginacji dla długich list.
  • Brak opcji "przejrzyj wszystkie" lub trybu pełnoekranowego.
  • Wyszukiwanie aktywuje się tylko po uzyskaniu fokusu, bez podglądu.

Zamiast tego implementuj:

  • Dynamiczną wysokość: min(80vh, 50% listy).
  • Wirtualizację dla list > 100 elementów (react-window, react-virtualized).
  • Nawigację klawiaturą z wyszukiwaniem luźnym.
  • Ładowanie opóźnione opcji podczas przewijania.

Najlepsze praktyki dla frontendów

Elementy interaktywne powinny dopasowywać się do viewportu. Statyczny content nie współdziała z użytkownikiem — można go zwijać lub ukrywać.

Google AdInline article slot
  • Dostosowanie do urządzenia: Użyj max-height: calc(100vh - 200px) zarówno na mobilnych, jak i desktopowych.
  • Dostępność (A11y): Dodaj atrybuty ARIA (role="listbox", aria-activedescendant).
  • Wydajność: W React/Vue stosuj portale, by rozwiązać konflikty z z-index.
  • Testowanie: Sprawdź działanie na listach 10, 50, 200 elementów.

Przykład komponentu React z dynamiczną listą rozwijaną:

import React, { useState, useRef } from 'react';

const AdaptiveSelect = ({ options, onChange }) => {
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState('');
  const dropdownRef = useRef();

  const toggle = () => setIsOpen(!isOpen);

  const handleSelect = (value) => {
    setSelected(value);
    onChange(value);
    setIsOpen(false);
  };

  return (
    <div className="select-container">
      <div className="select-trigger" onClick={toggle}>
        {selected || 'Wybierz opcję'}
      </div>
      {isOpen && (
        <div className="select-dropdown" ref={dropdownRef}>
          {options.map(opt => (
            <div key={opt} className="select-option" onClick={() => handleSelect(opt)}>
              {opt}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

export default AdaptiveSelect;

Komponent automatycznie dostosowuje się do rozmiaru listy i ekranu.

Co warto pamiętać

  • Skalowalność: Menu rozwijane z >20 opcjami wymagają max-height 80vh dla wygody.
  • Doświadczenie użytkownika: Pełne przeglądanie listy bez przewijania zmniejsza czas wybierania 5–10 razy.
  • Realizacja: 5–10 linii CSS rozwiązuje 90% przypadków; dla skomplikowanych — wirtualizacja.
  • Testowanie: Sprawdzaj na rzeczywistych danych, a nie prototypach z 4 elementami.
  • Dostępność: Zapewnij nawigację klawiaturą i wsparcie dla czytników ekranu.

— Editorial Team

Advertisement 728x90

Czytaj dalej