Kiedy przycisk nie jest przyciskiem?

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ Nie wszystko, co okrągłe i wyróżnia się, uważane jest za przycisk. W tym artykule Vadim wyjaśnia, jak stworzyć odpowiedni interaktywny przycisk dla swoich użytkowników — taki, którego nie należy mylić z niczym innym.

Załóżmy, że masz część interfejsu, którą użytkownik klika i coś się dzieje. Brzmi jak przycisk dla mnie, ale na razie nazwijmy to „klikającą rzeczą”. Wiem, masz pewność, że to też przycisk: jest zaokrąglony i wyróżnia się ładnym pomidorowym kolorem, prosząc o interakcję. Ale zastanówmy się przez chwilę. Obiecuję, że na dłuższą metę zaoszczędzi to czas.

Pomidorowa rzecz przypominająca guzik z napisem „Coś”.
Zaprojektuj dla swojej „klikającej rzeczy” (duży podgląd)

Co by było, gdyby tekst w tej klikającej rzeczy brzmiał „Czytaj więcej”, a kliknięcie go doprowadziło użytkownika do artykułu na innej stronie? Hmm. A co by było, gdyby pojawiło się podkreślone na niebiesko słowo „Zamknij”, które zamyka wyskakujące okno dialogowe? Czy jest to link tylko dlatego, że jest niebieski i podkreślony? Oczywiście nie.

Link podobny do przycisku i przycisk podobny do linku
Dylemat linku lub przycisku (duży podgląd)
Więcej po skoku! Kontynuuj czytanie poniżej ↓

Łał! Wygląda na to, że po prostu nie da się stwierdzić, czy jest to link, czy przycisk. To szalone! Zanim wybierzesz odpowiedni element, musimy zrozumieć, co robi ta rzecz. Ale co, jeśli jeszcze nie wiemy, co robi lub po prostu jesteśmy zdezorientowani? Cóż, jest dla nas przydatny schemat blokowy:

Schemat blokowy: to przycisk. Jeśli nie, to jest to link. Otóż ​​to.
Naukowy schemat blokowy do wyboru odpowiedniego elementu (duży podgląd)
  1. To przycisk.
  2. Jeśli nie, to jest to link.
  3. Otóż ​​to.

Czy więc wszystko jest przyciskiem? Nie, ale zawsze możesz zacząć od przycisku dla prawie każdego elementu, który można kliknąć lub wejść w interakcję w podobny sposób. A jeśli czegoś brakuje, na przykład nawigacja do innej strony, użyj zamiast tego linku. I nie, wskaźnik nie jest powodem, aby go <a href> . Mamy cursor: pointer do tego.

Skoncentrowany przycisk pomidora z napisem „Coś”
Nie zapomnij podać stylów skupienia. (duży podgląd)

W porządku, to <button> — zgadzamy się z tym. Umieśćmy to w naszym szablonie i stylizujmy zgodnie z projektem: trochę dopełnienia, zaokrąglenia, wypełnienie pomidorowe, biały tekst, a nawet niektóre style ostrości. Och, to takie miłe z twojej strony.

 <button type="button" class="button"> Something </button> <style> .button { display: inline-block; padding: 10px 20px; border-radius: 20px; background-color: tomato; color: white; } .button:focus { outline: none; box-shadow: 0 0 0 5px #006AE3; } </style>

To nie trwało długo. Chciałeś go szybko zbudować i zjeść lunch, bo jesteś głodny. Ok, zobaczmy jak to wygląda i ruszajmy.

Brzydko wyglądający przycisk pomidora, renderowany w przeglądarce
Czasami przeglądarka nie jest twoim najlepszym przyjacielem. (duży podgląd)

O mój Boże! Coś jest nie tak z przeglądarką. Dlaczego ten przycisk jest taki brzydki? Tekst jest mały, mimo że wyraźnie ustawiliśmy body na 16px , a nawet font-family jest błędna. Zaokrąglona lamówka z głupim pseudocieniem jest tak retro, że to jeszcze nie trend.

Ach, to domyślny styl przeglądarki. Musisz to ostrożnie cofnąć, a nawet dodać Normalize.css lub Reset.css… lub możesz po prostu użyć <div> i zapomnieć o tym. Czy szybkie rozwiązywanie problemów nie jest tym, za co ci płacą? Jesteś głodny, a to wcale nie pomaga. Ale jesteś profesjonalistą: weź się w garść i pomyśl.

Jaka jest różnica między <button> a <div> ? Wbudowany <button> jest elementem interaktywnym, co oznacza, że ​​można z nim wchodzić w interakcje. To głębokie. Możesz go kliknąć, możesz się na nim skoncentrować za pomocą klawiatury, a także przekazuje czytnikom ekranu dostępną rolę button , umożliwiając użytkownikom zrozumienie, że jest to przycisk.

Robi wrażenie! Wiesz nie tylko o elemencie <button> HTML, ale także wiesz co nieco o ARIA i obsłudze czytników ekranu. Być może próbowałeś nawet VoiceOver lub NVDA, aby sprawdzić, jak dostępne są twoje interfejsy.

Więc zdecydowałeś się zrobić sztuczkę. Nie będziesz zadzierać ze stylami przeglądarki i sprawisz, że element będzie wyglądał jak odpowiedni interaktywny przycisk dla użytkowników, którzy mogą go potrzebować. To sprytne!

 <div class="button" tabindex="0" role="button"> Something </div>

Teraz nie tylko wygląda dobrze, ale można na nim skupić się za pomocą klawiatury dzięki atrybutowi tabindex="0" , a czytniki ekranu potraktują go jako właściwy przycisk, ponieważ mądrze dodałeś do niego role="button" . Zatwierdź Git && w takim razie! Do tego jest kilka dodatkowych zadań, ale ze stylizacją mamy już za sobą. Co może pójść nie tak? Czas na lunch. Świetnie, chodźmy!

Godzinę później…

To był fajny lunch! Wróćmy do naszej klikającej rzeczy. Zanim przejdziemy dalej, musimy wykonać kilka zadań. Zobaczmy… Musimy wywołać funkcję doSomething po kliknięciu przycisku i powinien istnieć sposób na wyłączenie przycisku, aby nie można go było kliknąć. Brzmi łatwo. Dodajmy detektor zdarzeń do tego przycisku:

 <script> const buttons = document.querySelectorAll('.button'); [...buttons].forEach(button => { button.addEventListener('click', doSomething); }); function doSomething() { console.log('Something!'); } </script>

Gotowy. Użytkownik może teraz kliknąć go myszą na pulpicie i dotknąć palcem na ekranie dotykowym. Zdarzenie kliknięcia uruchomi się niezawodnie, a zobaczysz dużo Coś! w Twojej konsoli. Jakie jest następne zadanie?

Trzymać się! Musimy upewnić się, że działa to tak samo dla użytkowników klawiatury. Ponieważ mamy ten tabindex="0" na przycisku, można na nim skoncentrować się, a kiedy jest już skoncentrowany, użytkownicy powinni być w stanie nacisnąć spację lub klawisz „Enter”, aby wywołać to, co dołączyliśmy.

Musimy więc dołączyć inny detektor zdarzeń, aby wyłapać wszystkie klawisze, i uruchomimy naszą funkcję tylko dla niektórych klawiszy. Dzięki Bogu, że urządzenia dotykowe są wystarczająco inteligentne, aby przekształcić wszystkie stuknięcia w kliknięcia; w przeciwnym razie musielibyśmy również dołączyć kilka zdarzeń dotykowych.

 <script> const buttons = document.querySelectorAll('.button'); [...buttons].forEach(button => { button.addEventListener('click', doSomething); button.addEventListener('keyup', (event) => { if (event.key == 'Enter' || event.key == ' ') { doSomething(); } }); }); function doSomething() { console.log('Something!'); } </script>

Uff! Teraz nasza klikalna rzecz jest w pełni dostępna z klawiatury. Jestem z ciebie taki dumny! A JavaScript jest naprawdę magiczny — co byśmy bez niego zrobili?

W porządku, jakie jest ostatnie zadanie: „Przycisk powinien mieć stan nieaktywny, który zmienia jego wygląd i zachowanie na coś odrętwiałego”. Zdrętwiały? Myślę, że oznacza to coś szarego i nie reagującego na interakcję. OK, dodajmy stan w arkuszu stylów, używając nazewnictwa BEM.

 <div class="button button--disabled" tabindex="0" role="button"> Something </div> <style> .button--disabled { background-color: #9B9B9B; } </style> 
Szary przycisk z zastosowanym stanem wyłączenia
Ten przycisk wygląda wygodnie zdrętwiały. (duży podgląd)

Dla mnie to wygląda na wygodnie odrętwiałe . Za każdym razem, gdy przycisk musi być wyłączony, dodamy modyfikator button--disabled , aby był szary. Ale to nie jest jeszcze wystarczająco odrętwiałe: nadal może być skupione i uruchamiane zarówno przez wskaźnik, jak i klawiaturę.

Cholera, to staje się trudne.

Nie tylko to, ale przycisk nie powinien być dostępny w kolejności tabulacji, co oznacza, że ​​atrybut tabindex nie powinien tam być. I musimy sprawdzić, czy przycisk ma stan wyłączony, a następnie przestać wyzwalać naszą funkcję. Ponadto ten modyfikator może być stosowany dynamicznie. Chociaż dla CSS nie jest problemem dopasowywanie elementów za pomocą selektorów w locie i stosowanie stylów, możemy potrzebować pewnego rodzaju obserwatora mutacji, aby wywołać inne zmiany dla tego przycisku.

Wiem, prawda? Pomyśleliśmy, że będzie to prosty mały przycisk, który uruchamia funkcję i ma wyłączony stan. Staraliśmy się to naprawić dzięki dostępności i tym wszystkim, a teraz jesteśmy głęboko w tej króliczej nory.

Kupmy jedzenie na wynos. Nie wrócimy do domu na obiad, zanim skończymy i odpowiednio to przetestujemy. Cholerne W3C! Dlaczego nie starają się ułatwić nam życie? Jakby im na nas zależało!

W rzeczywistości robią…

Cofnijmy się o kilka kroków, zanim wskoczymy w ten bałagan. Dlaczego nie spróbujemy zrobić tych rzeczy za pomocą elementu <button> ? Ma w zanadrzu kilka przydatnych sztuczek, a nie tylko brzydkie style przeglądarki. Aha, i nie zapomnij type="button" — nie chcesz, aby przycisk „Zamknij” w wyskakującym okienku przypadkowo przesłał formularz, ponieważ type="submit" jest wartością domyślną.

Najwyraźniej, gdy <button> jest skupiony i naciśnięty jest spacja lub klawisz „Enter”, wywoła to zdarzenie click , tak jak robią to urządzenia mobilne, gdy dostaną stuknięcia, klepnięcia, lizania lub cokolwiek innego, co są w stanie odebrać Dziś. Jeden detektor zdarzeń mniej w naszym kodzie! Miły.

 // A click is enough! button.addEventListener('click', doSomething);

Jeśli chodzi o stan wyłączony, atrybut disabled jest dostępny dla elementu <button> , jak również dla wszystkich elementów formularza, w tym <fieldset> . Bez żartów. Czy wiesz, że możesz wyłączyć całą grupę danych wejściowych zgrupowanych razem, po prostu stosując pojedynczy atrybut do nadrzędnego <fieldset> ?

Grupa nieaktywnych wejść i przycisk
Kilka danych wejściowych wyłączonych za pomocą jednego atrybutu (duży podgląd)
 <fieldset disabled> <legend>A bunch of numb inputs</legend> <p> <label> <input type="radio" name="option"> Of course it's a link </label> </p> <p> <label> <input type="radio" name="option"> Obviously, it's a button </label> </p> <p> <label> <input type="radio" name="option"> I just wanna go home </label> </p> <button type="button">Button</button> </fieldset>

Teraz wiesz! Ten atrybut nie tylko wyłącza wszystkie zdarzenia w elementach formularza, ale także usuwa je z kolejności tabulacji. Problem rozwiązany!

 <button disabled type="button" class="button"> Something </button>

Ale czekaj, jest więcej! Wyzwala również pseudoklasę :disabled w CSS, co oznacza, że ​​możemy pozbyć się modyfikatora BEM do deklarowania stylów i zamiast tego użyć wbudowanego modyfikatora dynamicznego.

 .button:disabled { background-color: #9B9B9B; }

Jeśli chodzi o brzydkie style przeglądarki, nie musimy używać całego Normalize.css, aby naprawić pojedynczy przycisk. Użyj go jako źródła mądrości: trzy dodatkowe wiersze poniżej naprawią większość irytujących różnic w stosunku do <div> . Jeśli kiedykolwiek będziesz potrzebować więcej, możesz skopiować z niego odpowiednie części.

 .button { font-size: 100%; font-family: inherit; border: none; }

Gotowy. W końcu HTML nie jest taki zły!

Ale jeśli od czasu do czasu Cię zaskoczy, sprawdź specyfikację HTML, aby uzyskać odpowiedzi. Z biegiem lat stał się znacznie bardziej przyjazny i zawiera wiele dobrych przykładów użycia i ułatwień dostępu. I oczywiście stary dobry Doktor HTML5 jest nadal niezawodnym miejscem, w którym można znaleźć różnicę między elementami <section> i <article> oraz sprawdzić, czy zarys dokumentu jest już czymś (nie do końca). Jest duża szansa, że ​​przeczytasz również dokumentację HTML Mozilli i też tego nie pożałujesz.

To zadanie jest już wykonane! Co dalej? Rozwijany kalendarz karuzeli z polem wyszukiwania? O mój! Powodzenia z tym. Ale pamiętaj: <button> to Twój przyjaciel!

Dalsze czytanie na SmashingMag:

  • Jak zaprojektować lepsze przyciski
  • Budowanie włączające przyciski przełączania
  • Projekt przycisku ducha: czy to naprawdę wciąż coś (i dlaczego)?
  • Wzorce projektowe: łamanie zasad jest w porządku