Стилизуем кнопки правильно
Кнопки есть практически в любом приложении. В их роли могут выступать самые разные элементы — собственно кнопки, ссылки и даже простые спаны. В любом случае важно правильно их оформить. В этом руководстве мы займемся созданием CSS-компонента кнопки.
Сброс стилей элемента
Выбор правильного элемента имеет несколько преимуществ: это SEO-friendly и делает ваш сайт более доступным при работе с клавиатуры и для скринридеров.
Однако разработчики редко используют элемент . На большинстве сайтов кнопки представлены тегами , или . В чем причина такой нелюбви?
- Незнание. Некоторые разработчики даже не догадываются, что тег button можно использовать вне форм.
- Сложности стилизации. У кнопок очень много стилей по умолчанию, которые мешают созданию кастомного дизайна.
К счастью, у нас есть CSS reset. Давайте сбросим стили кнопки и сделаем ее похожей на обычный текст:
Минус этого подхода заключается в том, что стиль сбросился у ВСЕХ кнопок, и теперь посетитель сайта не сможет опознать их на странице.
Можно воспользоваться препроцессором (SCSS) и написать миксин для использования в нужных местах:
Создание CSS-компонента кнопки
Теперь, когда мы удалили все лишнее, давайте определим собственные стили для кнопки. Создадим для этого отдельный класс .btn , который можно будет указать и для button , и для a , и для любого другого элемента.
Внимание: при разработке CSS-компонента кнопки важно учитывать, что он может быть применен к ссылкам. Значит, необходимо изменить также дефолтные свойства ссылок.
Избегайте использования для кнопок цветов с малым контрастом. Часть ваших пользователей может иметь проблемы со зрением, а другая изучает сайт в неблагоприятных условиях (например, на телефоне под светящим солнцем) — не затрудняйте им жизнь.
Стилизация различных состояний
Кнопка уже выглядит неплохо, но кое-чего не хватает. Это интерактивный элемент, имеющий несколько состояний. Мы должны стилизовать и их.
У браузеров есть собственные дефолтные стили для состояний :focus (фокус на кнопке) и :active (нажатие), но часть из них мы уже сбросили. Не забудем также про состояние :hover (наведение курсора).
- Для нажатой кнопки создадим олдскульный эффект «утопления» с небольшим изменением насыщенности.
- При наведении курсора поменяем местами цвета фона и текста и добавим рамку.
- Для обозначения фокусировки используем такой же стиль.
Обратите внимание: стили фокуса очень важны. Многие пользователи по разным причинам пользуются клавиатурой для навигации по странице. Только стилизованный :focus помогает им понять, где они находятся в данный момент.
Только после того как мы позаботились о собственном оформлении фокуса можно убрать у кнопки дефолтные браузерные стили ( outline ).
Разбираемся с «липким» фокусом
Осталось решить еще одну небольшую проблему.
В ряде браузеров когда вы кликаете на ссылку или кнопку, она получает два псевдокласса: :active и :focus .
:active убирается сразу после того, как вы перестали нажимать на кнопку мышки или трекпад. Но :focus зачастую остается до тех пор, пока вы не кликнете на какой-нибудь другой элемент страницы.
Это поведение можно пофиксить с помощью нового псевдокласса :focus-visible.
Это свойство еще не принято официально, но идея заключается в том, что состояние :focus-visible устанавливается для элемента только при получении фокуса с клавиатуры (а не при клике).
При необходимости можно использовать JS-полифилл.
Давайте разделим состояния :hover и :focus в нашем компоненте:
Теперь подключим полифилл focus-visible.js. Он добавит элементу body класс js-focus-visible . Используем его, чтобы удалить тень с элементов, у которых нет класса focus-visible (то есть тех элементов, на которых сфокусировались не с клавиатуры):
.js-focus-visible .btn:focus:not(.focus-visible)
Кажется, было бы проще установить стили только для .focus-visible элементов, однако, так мы лишимся фоллбэка на тот случай, если скрипт не сработает.
Overriding Default Button Styles
One challenge is getting all those elements to look and layout exactly the same. We’ll cover that a few ways.
Another challenge is getting people to use them correctly
This is a bit surprising to me — but I hear it often enough to worry about it — is that more and more developers are using
So, elements are a pain in the butt to style right? That doesn’t mean you should attach your JavaScript events to a or an though. You see, when you use a , you get keyboard events for free. You’re also helping screen reader users out because it’ll announce the element correctly.
And here’s Andy again helping you out with a chunk of CSS that’ll get you a cleanly styled button: See the Pen Button Pal — some basic button styles by Andy Bell (@hankchizljaw) on CodePen.
It’s that styling that just might be the mental roadblock
It’s a bit understandable. Buttons are weird! They have a good amount of default styling (that come from the “User Agent Stylesheet”) that varies from browser to browser and means you have work to do to get them exactly how you want. Firefox behaves a bit differently. See in the video above how setting border: 0; removed the border in Chrome, but also the background? Not the case in Firefox: I only point this out to say, I get it, buttons are truly weird things in browsers. Factor in a dozen other browsers, mobile, and the idea that we want to style all those different elements to look exactly the same (see the opening of the article), and I have a modicum of empathy for people wanting to avoid this.
Never hurts to consult Normalize
/** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea < font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ >/** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input < /* 1 */ overflow: visible; >/** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select < /* 1 */ text-transform: none; >/** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"]
I was a tiny bit surprised to see WTF, Forms? not cover buttons, only because of how much weirdness there is. But the form elements that project whips into shape are even more notoriously difficult!
A Style-Testing Kinda Thingy
I feel like the answer to this is basically a big ol’ block of CSS. That’s what Andy provided, and you could very likely come to one on your own by just being a little heavier handed than the usual of setting style rules with your buttons. Still, I felt compelled to make a little tester machine thingy so you can toggle styles on and off and see how they all go together in whatever browser you happen to be in: See the Pen Consistent button styles by Chris Coyier (@chriscoyier) on CodePen.
The biggest point here is to use the correct native elements, as you get a bunch of functionality and accessibility for free. But you might as well get the styling right, too! While we’re talking buttons, I’m gonna use the same quote I used in our When To Use The Button Element post from MDN:
Warning: Be careful when marking up links with the button role. Buttons are expected to be triggered using the Space key, while links are expected to be triggered through the Enter key. In other words, when links are used to behave like buttons, adding role=»button» alone is not sufficient. It will also be necessary to add a key event handler that listens for the Space key in order to be consistent with native buttons.
You don’t need role=»button» on
button:hover, button:focus < background: #0053ba; >button:focus < outline: 1px solid #fff; outline-offset: -4px; >button:active