Când un buton nu este un buton?

Publicat: 2022-03-10
Rezumat rapid ↬ Nu tot ceea ce este rotund și iese în evidență este considerat a fi un buton. În acest articol, Vadim explică cum puteți crea un buton interactiv adecvat pentru utilizatorii dvs. - unul care nu trebuie confundat cu nimic altceva.

Să presupunem că aveți o parte a unei interfețe pe care utilizatorul face clic și se întâmplă ceva. Mi se pare un buton, dar haideți să-l numim „lucru de clic” pentru moment. Știu, sunteți încrezător că este și un buton: este rotunjit și iese în evidență printr-o culoare frumoasă de roșie, cerând să interacționați. Dar să ne gândim o clipă. Va economisi timp pe termen lung, promit.

Lucru asemănător unui buton de roșii, cu textul „Ceva” pe el.
Proiectați pentru „lucru de clic” (previzualizare mare)

Ce se întâmplă dacă textul din acest lucru de clic ar fi „Citește mai mult”, iar făcând clic pe el l-ar duce pe utilizator la un articol pe altă pagină? Hmm. Și dacă ar exista un cuvânt subliniat albastru, „Închidere”, care închide fereastra de dialog pop-up? Este un link doar pentru că este albastru și subliniat? Desigur că nu.

Link asemănător unui buton și buton asemănător linkului
Dilema link-ului sau butonului (previzualizare mare)
Mai multe după săritură! Continuați să citiți mai jos ↓

Vai! Se pare că nu există nicio modalitate de a spune dacă este un link sau un buton doar privindu-l. Asta e o nebunie! Trebuie să înțelegem ce face acest lucru înainte de a alege elementul potrivit. Dar dacă nu știm încă ce face sau suntem pur și simplu confuzi? Ei bine, există o diagramă de flux la îndemână pentru noi:

Diagramă: este un buton. Dacă nu, atunci este un link. Asta e.
O diagramă științifică pentru alegerea elementului potrivit (Previzualizare mare)
  1. Este un buton.
  2. Dacă nu, atunci este un link.
  3. Asta e.

Deci, totul este un buton? Nu, dar puteți începe oricând cu un buton pentru aproape orice element pe care se poate face clic sau cu care se poate interacționa într-un mod similar. Și dacă îi lipsește ceva, cum ar fi navigarea către o altă pagină, folosește în schimb un link. Și nu, un indicator nu este un motiv pentru a-l face <a href> . Avem cursor: pointer pentru asta.

Buton de roșii concentrat cu textul „Ceva” pe el
Nu uitați să oferiți stiluri de focalizare. (Previzualizare mare)

În regulă, este un <button> - suntem de acord cu asta. Să-l punem în șablonul nostru și să-l stilăm în funcție de design: niște umplutură, rotunjire, o umplutură de roșii, text alb și chiar câteva stiluri de focalizare. Oh, ce drăguț din partea ta.

 <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>

Asta nu a durat mult. Ai vrut să-l construiești rapid și să iei niște prânz pentru că ți-e foame. Ok, să vedem cum arată și să mergem.

Buton de roșii cu aspect urât, redat într-un browser
Uneori, browserul nu este cel mai bun prieten al tău. (Previzualizare mare)

Oh, Doamne! Ceva este în neregulă cu browserul. De ce este acest buton atât de urât? Textul este mic, chiar dacă am setat în mod explicit body la 16px și chiar și font-family este greșită. Chenarul rotunjit cu o pseudo-umbră prostească este atât de retro încât nici măcar nu este încă o tendință.

Ahh, este stilul implicit al browserului. Trebuie să o anulați cu atenție sau chiar să adăugați Normalize.css sau Reset.css... sau puteți pur și simplu să utilizați un <div> și să uitați de el. Nu este rezolvarea rapidă a problemelor pentru care te plătesc? Ți-e foame și asta nu ajută deloc. Dar ești un profesionist: împinge-te și gândește-te.

Oricum, care este diferența dintre un <button> și un <div> ? Un <button> încorporat este un element interactiv, ceea ce înseamnă că poate fi interacționat cu acesta. Asta este profundă. Puteți să dați clic pe el, să vă concentrați asupra lui folosind o tastatură și, de asemenea, transmite un rol de button accesibil cititorilor de ecran, făcând posibil ca utilizatorii să înțeleagă că este un buton.

Impresionant! Nu numai că știți despre elementul <button> al HTML, dar știți și câteva lucruri despre ARIA și suportul pentru cititorul de ecran. S-ar putea să fi încercat chiar și VoiceOver sau NVDA pentru a testa cât de accesibile sunt interfețele tale.

Deci, te-ai hotărât să faci un truc. Nu te vei încurca cu stilul browserului și vei face ca elementul să arate ca un buton interactiv adecvat pentru utilizatorii care ar putea avea nevoie de el. E inteligent!

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

Acum nu numai că arată corect, dar poate fi focalizat prin tastatură datorită atributului tabindex="0" , iar cititorii de ecran îl vor trata ca pe un buton adecvat, deoarece i-ați adăugat cu înțelepciune role="button" . Git commit && push atunci! Există câteva sarcini suplimentare pentru acest lucru, dar am terminat cu stilul. Ce ar putea merge prost? Timp pentru prânz. Minunat, hai să mergem!

O oră mai târziu…

A fost un prânz frumos! Să revenim la chestia noastră cu clicuri. Trebuie să îndeplinim câteva sarcini înainte de a merge mai departe. Să vedem... Trebuie să apelăm o funcție doSomething odată ce butonul este apăsat și ar trebui să existe o modalitate de a dezactiva butonul astfel încât să nu poată fi clicat. Sună ușor. Să adăugăm un ascultător de evenimente la acest buton:

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

Terminat. Utilizatorul poate face acum clic pe el cu mouse-ul pe desktop și îl poate atinge cu un deget pe un ecran tactil. Un eveniment de clic se va declanșa în mod fiabil și veți vedea o mulțime de Ceva! în consola ta. Care este următoarea sarcină?

Stai așa! Trebuie să ne asigurăm că funcționează la fel pentru utilizatorii de tastatură. Deoarece avem acest tabindex="0" pe buton, acesta poate fi focalizat, iar odată ce este focalizat, utilizatorii ar trebui să poată apăsa bara de spațiu sau tasta „Enter” pentru a declanșa orice am atașat.

Deci, trebuie să atașăm un alt ascultător de evenimente pentru a prinde toate tastele și vom declanșa funcția noastră numai pentru anumite taste. Slavă Domnului că dispozitivele tactile sunt suficient de inteligente pentru a transforma toate atingerile în clicuri; altfel, ar trebui să atașăm și o grămadă de evenimente tactile.

 <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>

Pf! Acum, lucrul nostru cu clicuri este complet accesibil de la tastatură. Sunt atât de mândru de tine! Și JavaScript este cu adevărat magic - ce ne-am face fără el?

Bine, care este ultima sarcină: „Butonul ar trebui să aibă o stare dezactivată care își schimbă aspectul și comportamentul în ceva amorțit.” Amorțit? Cred că asta înseamnă ceva gri și care nu răspunde la interacțiune. OK, să adăugăm o stare în foaia de stil folosind denumirea BEM.

 <div class="button button--disabled" tabindex="0" role="button"> Something </div> <style> .button--disabled { background-color: #9B9B9B; } </style> 
Buton gri cu starea dezactivată aplicată
Acest buton pare confortabil amorțit. (Previzualizare mare)

Asta mi se pare confortabil amorțit . Ori de câte ori butonul trebuie să fie dezactivat, vom adăuga button--disabled pentru a-l face gri. Dar încă nu este suficient de amorțit: poate fi încă focalizat și declanșat atât de un indicator, cât și de la tastatură.

La naiba, asta devine dificil.

Nu numai că, dar butonul nu ar trebui să fie accesibil în ordinea tabulatorilor, ceea ce înseamnă că atributul tabindex nu ar trebui să fie acolo. Și trebuie să verificăm dacă butonul are starea dezactivată și apoi să oprim declanșarea funcției noastre. De asemenea, acest modificator ar putea fi aplicat dinamic. Deși nu este o problemă pentru CSS să potriviți elementele cu selectoare din mers și să aplicăm stiluri, s-ar putea să avem nevoie de un fel de observator de mutații pentru a declanșa alte modificări pentru acest buton.

Nu-i așa? Ne-am gândit că acesta ar fi un simplu buton mic care declanșează o funcție și are o stare dezactivată. Am încercat să facem totul corect cu accesibilitatea și toate chestiile astea, iar acum ne aflăm adânc în această groapă de iepure.

Să luăm niște mâncare la pachet. Nu vom fi acasă la cină până când vom termina și vom testa corect acest lucru. Sângeros W3C! De ce nu încearcă să ne facă viața mai ușoară? De parcă le pasă de noi!

De fapt, ei fac...

Să facem câțiva pași înapoi înainte de a sări în această mizerie. De ce nu încercăm să facem aceste lucruri folosind elementul <button> ? Are câteva trucuri utile în mânecă, nu doar stilurile urâte ale browserului. Ah, și nu uitați type="button" - nu doriți ca butonul „Închidere” al ferestrei pop-up să trimită accidental formularul, deoarece type="submit" este valoarea implicită.

Aparent, când <button> este focalizat și bara de spațiu sau tasta „Enter” este apăsată, va declanșa evenimentul de click , la fel cum fac dispozitivele mobile când primesc atingeri, bătăi, lisări sau orice altceva sunt capabili să primească azi. Un ascultător de evenimente mai puțin în codul nostru! Grozav.

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

În ceea ce privește starea dezactivată, atributul disabled este disponibil pentru elementul <button> , precum și pentru toate elementele de formular, inclusiv pentru <fieldset> . Fara gluma. Știați că puteți dezactiva o mulțime de intrări grupate împreună doar prin aplicarea unui singur atribut părintelui <fieldset> ?

Un grup de intrări dezactivate și un buton
O grămadă de intrări dezactivate cu un singur atribut (previzualizare mare)
 <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>

Acum știi! Acest atribut nu numai că dezactivează toate evenimentele din elementele formularului, ci le elimină și din ordinea tabulatorilor. Problema rezolvata!

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

Dar stai, mai sunt! De asemenea, declanșează pseudo-clasa :disabled în CSS, ceea ce înseamnă că putem scăpa de modificatorul BEM pentru a declara stiluri și de a folosi modificatorul dinamic încorporat.

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

În ceea ce privește stilurile urâte ale browserului, nu trebuie să folosim tot Normalize.css pentru a remedia un singur buton. Folosiți-l ca o sursă de înțelepciune: Cele trei rânduri suplimentare de mai jos vor rezolva majoritatea diferențelor enervante față de <div> . Dacă aveți nevoie vreodată de mai multe, puteți copia părțile relevante din acesta.

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

Terminat. HTML nu este atât de rău până la urmă!

Dar dacă vă surprinde din când în când, asigurați-vă că verificați specificația HTML pentru răspunsuri. A devenit mult mai prietenos de-a lungul anilor și este plin de exemple bune de utilizare și accesibilitate. Și, desigur, vechiul HTML5 Doctor este încă un loc de încredere pentru a afla diferența dintre elementele <section> și <article> și pentru a verifica dacă schița documentului este încă un lucru (nu chiar). Există șanse mari să ajungeți să citiți și documentația HTML de la Mozilla și nici nu veți regreta.

Această sarcină este acum gata! Ce urmeaza? Un calendar derulant carusel cu un câmp de căutare? Vai! Mult noroc cu asta. Dar rețineți: <button> este prietenul tău!

Citiți suplimentare despre SmashingMag:

  • Cum să proiectați butoane mai bune
  • Construirea de butoane de comutare inclusiv
  • Designul butonului fantomă: Este încă un lucru (și de ce)?
  • Modele de design: atunci când încălcarea regulilor este OK