Изменяем поведение элементов при наличии точного указателя
Предположим, нам нужно сверстать накладывающиеся друг на друга элементы, которые будут полностью отображаться при наведении. Когда у нас есть курсор, мы без проблем можем навести его на элемент, и при срабатывании события hover, мы отображаем элемент.
Но на сенсорных экранах у нас нет такого точного указателя, как курсор, и даже если срабатывает событие наведения :hover , то эффект остаётся и после того, как мы уберем палец/стилус с элемента, и будет сохранятся до тех пор, пока не произойдёт другое событие. Это некорректное поведение и может запутать пользователя.
На данный момент, есть специальные @media запросы, которые определяют наличие точного указателя, и в статье мы рассмотрим один из вариантов их применения для решения вышеописаной проблемы
Немного теории
Так как сам только исследую эту тему, приведу несколько ссылок на которые я опирался, при написании этого раздела:
Для начала определимся, что у каждого устройства может быть как основное(первичное) устройство ввода, так и второстепенные, и их может быть несколько. Например у ноутбука есть touchpad и клавиатура, можно дополнительно подключить мышь и еще клавиатуру, а также может быть и сенсорный экран. К планшету/смартфону также можно подключить дополнительные устройства ввода
Устройства ввода могут быть точными указателями, как курсор мыши, и могут быть неточными, как касание сенсорного экрана пальцем/стилусом
Перейдём к @media запросам — итак, в нашем распоряжении четыре @media запроса — pointer , hover , any-pointer , any-hover
В чем их отличие?
@media запросы pointer и hover опираются только на основное(первичное) устройство ввода. Так как мы не хотим ограничивать пользователя единственным способом ввода, мы будем использовать другие @media запросы
@media запрос any-pointer будет выполнен, если хотя бы одно устройство ввода имеет точный указатель
@media запрос any-hover будет выполнены если хотя бы одно устройство ввода имеет возможность наведения, то есть может “повиснуть” над элементом, не производя над ним никаких других манипуляций
any-pointer имеет следующие значения
- none — указатель отсутствует
- coarse — есть хотя бы один указатель ограниченной точности
- fine — есть хотя бы один точный указатель
any-hover имеет следующие значения
- none — нет устройств ввода, которые имеют возможность наведения
- hover — есть хотя бы одно устройство ввода, которое имеет возможность наведения
Применение на практике
Применять эту возможность на практике можно в случаях, когда нужно или изменить внешний вид элемента, или его поведение в зависимости от устройства, на котором просматривается сайт
Для сенсорных экранов некоторые элементы можно делать больше по размеру, например область checkbox с галочкой. Такой checkbox будет доступней для пользователя на устройствах без курсора или другого точного устройства ввода
Теперь рассмотрим пример, который был описан в начале статьи.
Practice
Суть будет в следующем — изначально будем отображать все карточки целиком, а если устройство имеет хотя бы одно устройтво с точным указателем и имеет возможность наведения, то накладываем карточки друг на друга, и при наведении будем отображать необходимый элемент
Пишем стили для устройств, которые не имеют точного указателя, то есть изначально элементы будут отображены полностью, никакого дополнительного поведения у элементов пока не будет
.container < max-width: 1120px; padding: 0 16px; margin: 0 auto; >.section < padding: 64px 0; --color: #f7f3f3; background: var(--color); min-height: 100vh; >.grid < position: relative; >.grid__items < overflow-x: auto; display: flex; position: relative; >.grid__item < height: 128px; width: 128px; border-radius: 50%; background: var(--color); border: 2px solid #000; transition: 0.4s; overflow: hidden; position: relative; flex-shrink: 0; >.grid__item:not(:first-child) < margin-left: -1.4em; >.grid__item img

Чтобы добавить элементам дополнительное поведение для устройств с точным указателем и с возможностью наведения на элемент, будем использовать комбинацию @media запросов
Добавим следующие стили
@media (any-pointer: fine) and (any-hover: hover) < .grid__item:not(:first-child) < margin-left: -4.4em; >.grid__item:hover img < transform: scale(1.2) translateX(-8%); >.grid__item:hover + * < margin-left: -1.4em; >>

Посмотрим результат и разницу отображения и поведения на видео
Итоги
Если до этого мы в основном ориентировались только на разрешение устройства, и в зависимости от этого меняли внешний вид или поведение элементов, то теперь можно ориентироваться на возможности взаимодействия пользователя с устройством
Буду рад, если статья оказалась полезной
Спасибо за ваше внимание и уделённое время!
Стилизация старого доброго элемента button
Кнопка — это один из тех элементов, которые чаще всего используются на веб-страницах. Тег может быть применён для запуска некоего процесса вроде вывода данных, открытия модального окна, отправки формы и так далее. В материале, перевод которого мы публикуем, речь пойдёт о тонкостях стилизации элемента button и о том, как оформлять кнопки с учётом того, чтобы они хорошо работали бы в любых браузерах. Кроме того, тут будет рассмотрено большинство часто используемых стилей кнопок. Поговорим мы здесь и о некоторых сложностях, которые возникают при работе с кнопками.

Стили, применяемые к кнопкам по умолчанию
Может, разговор о «стандартных стилях» покажется кому-то обсуждением каких-то элементарных вещей, но, на самом деле, поговорить об этом довольно интересно. Вот стандартная таблица стилей для кнопок из пользовательского агента Google Chrome.
.c-button
А вот как выглядит стандартная кнопка, при выводе которой стили по умолчанию не менялись.

Простая кнопка, к которой применены стандартные стили
Для начала переопределим свойство appearance . Оно используется для стилизации, характерной для конкретной платформы. Внешний вид кнопки при таком подходе основан на стилях, применяемых в операционной системе пользователя.
.c-button
Теперь, после сброса свойства appearance , взглянем на то, как кнопки выглядят в разных браузерах.

Свойство appearance этих кнопок установлено в none
Далее, прежде чем мы перейдём, собственно, к стилизации, нам нужно сбросить ещё некоторые свойства. Это — border , border-radius , background .
.c-button

Кнопка после сброса свойств
Теперь, когда мы сбросили стандартные стили кнопки, пришло время двигаться дальше. А именно, я хочу рассказать о том, как стилизовать кнопки, основываясь требованиях, предъявляемых к их дизайну.
Стилизация обычных кнопок
Начнём с базового примера, поговорив о стилизации обычных кнопок, на которых выводится лишь текст. На следующем рисунке представлена «анатомия» обычной кнопки.

Цвет текста (Text Color), размер шрифта (Font Size), фон (Background), скругление углов (Roundness), внутренний отступ (Padding)
.c-button
Имея вышеприведённый CSS-код, мы можем получить кнопку, похожую на ту, которая показана на предыдущем рисунке. После того, как базовый стиль кнопки задан, нужно позаботиться о внешнем виде кнопки в различных состояниях.

Обычное состояние кнопки (Normal), получение фокуса (Focus), наведение на кнопку указателя мыши (Hover), отключение кнопки (Disabled)
▍Стили, применяемые к кнопкам при наведении на них мыши и при получении ими фокуса
Для того чтобы указать пользователю на то, что на кнопку наведён указатель мыши, важно оснастить кнопку стилем, рассчитанным на это событие. То же самое касается и изменения внешнего вида кнопки при получении ей фокуса в ситуации, когда со страницей работает пользователь, применяющий клавиатуру.
Этот материал указывает на то, что важен порядок добавления стилей, применяемых к кнопке при наведении на неё мыши ( hover ) и при получении ей фокуса ( focus ).
Когда стиль hover добавляют до стиля focus , все стили работают правильно. Проблема появляется тогда, когда стиль focus добавляют до стиля hover . Когда элемент щёлкают мышью, стиль focus никак себя не проявляет, видимым оказывается лишь представление кнопки, определяемое стилем hover .

Хорошо, если сначала идёт стиль hover, а потом — стиль focus
Вот как выглядит правильный порядок описания стилей:
.c-button:hover < background: #1d49aa; >.c-button:focus
▍Минимальная ширина кнопки
Для того чтобы кнопка хорошо выглядела, она должна иметь определённую ширину. Важно заранее об этом подумать и принять во внимание длинные и короткие надписи, которые могут содержаться на кнопках. Благодаря свойству min-width можно установить минимальную ширину кнопки. Вот моя статья, где в подробностях обсуждается это и другие подобные свойства.
Взгляните на следующий рисунок. Там можно видеть несколько кнопок, содержащих надписи разной длины на английском и арабском языках. Если не задавать минимальную ширину кнопки, кнопка, когда надпись на ней будет короткой, окажется слишком маленькой. Лучше этого не допускать и пользоваться свойством min-width .

Стоит задавать свойство кнопок min-width
.c-button < min-width: 100px; /* другие стили*/ >
▍Внутренние отступы
Привлекательной может выглядеть идея, в соответствии с которой кнопкам не назначают горизонтальные внутренние отступы. Ведь кнопки имеют определённую ширину, а значит — между краями кнопок и надписями, содержащимися на них, будет достаточно места. Так? Нет, не так. Реализация этой идеи может иметь негативные последствия в тех случаях, когда надпись на кнопке меняется.
Взглянем на следующий рисунок.

Рекомендовано назначать кнопкам внутренние отступы
Обратите внимание на то, что если кнопке не назначены внутренние отступы, надпись, расположенная на ней, может очень близко подходить к краям. Даже в том случае, если у кнопки есть свойство min-width . В нижней части рисунка используется и свойство padding , и свойство min-width . Это даёт больше уверенности в том, что кнопка будет хорошо выглядеть в ситуации, когда заранее неизвестна длина выводимой на ней надписи.
▍Семейство шрифта, используемого для надписей, расположенных на кнопках
Элементы форм, по умолчанию, не наследуют семейство шрифта, назначенное элементам или . Интересно заметить, что я написал 70% этой статьи и понял, что, во-первых, не поменял шрифт кнопки, используемой в демонстрационных целях, и, во-вторых, ничего об этом не написал.
Для решения этой проблемы свойство font-family должно быть установлено в значение inherit .
.c-button < font-family: inherit; /* другие стили */ >
▍Стилизация отключённых кнопок
Для того чтобы указать пользователю на то, что кнопка отключена, к ней можно добавить атрибут disabled и стилизовать кнопку средствами CSS.
Вот HTML-код, описывающий отключённую кнопку:
Вот CSS-код стилизации такой кнопки:
.c-button[disabled]
Когда кнопка отключена, она не может получить фокус с клавиатуры и удаляется из дерева доступности элементов страницы.
▍Внешний вид указателя мыши при наведении его на кнопку
Стандартный указатель мыши, наведённый на кнопку, выглядит как стрелка. Мне нравится этот ответ на StackOverflow: «Кнопки — это традиционный элемент управления настольных программ. Это — среда, в которой указатель в виде руки никогда не использовался до наступления эры интернета. Когда на веб-страницах стали применять тот же самый элемент управления, разработчики просто пытались сделать так, чтобы кнопки выглядели так же, как в настольных приложениях».
Для того чтобы переопределить обычное поведение указателя, рекомендовано поменять стандартный курсор-стрелку на курсор в виде руки.

Стандартный курсор-стрелка и улучшенный курсор в виде руки.
Теперь, когда мы обсудили базовые вопросы стилизации кнопок, приведём полный CSS-код, включающий в себя всё то, чего мы коснулись выше:
.c-button < min-width: 100px; font-family: inherit; appearance: none; border: 0; border-radius: 5px; background: #4676d7; color: #fff; padding: 8px 16px; font-size: 1rem; cursor: pointer; >.c-button:hover < background: #1d49aa; >.c-button:focus
В следующих разделах мы поговорим о разных стилях и типах кнопок, которые вы можете использовать в своих проектах.
Кнопки со значком
Иногда нужно, чтобы на кнопке был бы некий значок. Это может понадобиться для того, чтобы выделить кнопку, или чтобы лучше проинформировать пользователя о роли кнопки. Важно, чтобы кнопки со значками были бы доступны пользователям с ограниченными возможностями.

Примеры кнопок со значками
На предыдущем изображении имеются кнопки со значками. Ниже показан код, в котором к значку добавлен атрибут aria-hidden , что позволяет убрать его из дерева доступности. Я так же добавил атрибут focusable=»false» для того чтобы значок не получал бы фокус в IE.
Обратите внимание на то, что я воспользовался стилем vertical-align: middle для того чтобы выровнять значок и содержимое кнопки по вертикали.
Вот HTML-код кнопки, о которой идёт речь:
.c-button svg
То, что мы только что рассмотрели, может работать до тех пор, пока мы не решим скрыть текст кнопки и сделать её кнопкой, на которой находится только значок. Как это сделать? Сначала текст надо обернуть, например, в элемент span . Затем можно заняться дальнейшим улучшением внешнего вида кнопки. Вот HTML-описание кнопки:
Может показаться, что теперь достаточно просто скрыть элемент span и дело будет сделано:
.c-button--icon span
Хотя при таком подходе текст пропадает, а значок остаётся, это очень плохо в плане доступности контента. Кнопку уже «не видят» инструменты для чтения с экрана. Например, VoiceOver в macOS сообщает о том, что такая кнопка — это просто «Button», без каких-либо подробностей о ней. У этой проблемы есть несколько решений.
▍Использование SVG-значков
Я предпочитаю пользоваться SVG-значками. Рекомендуется собирать все SVG-описания графических элементов в один файл и подключать каждый значок в теге с использованием элемента . Вот пример:
Здесь показан код SVG-значка, описание которого хранится в файле icons.svg и имеет идентификатор #facebook . Этот подход позволяет снизить уровень дублирования кода.
▍Настройка размеров кнопки со значком
Так как текст кнопки больше не виден, и при этом для кнопки задано CSS-свойство min-width , ширина кнопки не будет соответствовать размеру значка. Для того чтобы учесть эту особенность, лучше в явном виде задать ширину кнопки со значком.

Кнопка, у которой задано CSS-свойство min-width, и кнопка, у которой это свойство не задано
.c-button--icon
▍Визуальное скрытие текста
Элемент, с помощью популярного класса .sr-only , можно скрыть визуально, убрав с экрана, но оставив доступным для средств чтения с экрана.
.sr-only
▍Установка размера шрифта в 0
Если установить свойство font-size в значение 0 , то элемент span не будет занимать вообще никакого места на экране. То есть он будет скрыт.
.c-button--icon span
Но тут я склоняюсь к решению, предусматривающему использование класса .sr-only . С моей точки зрения оно выглядит более логичным. Приём скрытия текста путём установки размера шрифта в 0, как мне кажется, похож на некий хак.
▍Использование атрибута aria-label
Если в кнопке нет элемента , тогда должен быть способ обойтись и без него. Один из таких способов заключается в использовании атрибута aria-label . Атрибут либо назначают самому элементу , либо — элементу .
Если вы хотите больше узнать о кнопках со значками — взгляните на этот материал.
Кнопки, содержащие несколько строк текста
В некоторых случаях может понадобиться, чтобы кнопка содержала бы две строки текста. Ниже показан пример такой кнопки.

Кнопка, содержащая две строки текста
Тут показана кнопка для формы подписки, содержащая основной и вспомогательный текст. Как сделать такую кнопку и при этом не забыть о её доступности для людей с ограниченными возможностями? Вот соответствующий HTML-код:
Средство для чтения с экрана «озвучит» эту кнопку как «Subscribe to our newsletter 240K+ subscribers». Когда пользователь это услышит, это его может запутать, так как ничто не будет разделять две строки текста, выводимые на кнопке. Взгляните на скриншот инструмента Chrome для исследования доступности элементов.

Исследование доступности элементов в Chrome
Для того чтобы не путать пользователей, я предпочёл бы скрыть вторую строку текста от средств для чтения с экрана. Сделать это можно, использовав атрибут aria-hidden в соответствующем элементе :
Если по какой-то причине изменить HTML-разметку нельзя, есть и другой способ добавления дополнительного текста на кнопку. Решение этой проблемы, которое показалось мне интересным, я нашёл на сайте Smashing Magazine. Оно заключается в том, чтобы размещать содержимое, пользуясь псевдоэлементами. При таком подходе средства для чтения с экрана не будут видеть ничего лишнего. Вот CSS-код этого решения:
.c-button--multiple span:after
Ссылки () или кнопки ()?
Когда стоит пользоваться ссылками, а когда — кнопками? Для начала давайте поговорим о том, чем они отличаются друг от друга.
▍Ссылки
▍Кнопки
Элемент сам по себе, без подключения к нему JavaScript-кода, не выполняет никаких действий. С ним можно использовать псевдоклассы :hover , :focus и :active . Если говорить о доступности, то с кнопкой можно взаимодействовать с помощью клавиатурных клавиш Enter и Пробел . Средства для чтения с экрана «читают» содержимое кнопок.
Если вспомнить о дизайне, то случается так, что веб-страница содержит кнопки одного и того же стиля, различающиеся в плане используемого для их описания HTML-кода. С учётом этого CSS-код для стилизации класса .c-button должен быть написан так, чтобы его можно было бы использовать и для элементов , и для элементов . Рассмотрим следующий пример.

Использование ссылок и кнопок
Обратите внимание на то, что «кнопки» на странице стилизованы одинаково. Однако первая из них — это, на самом деле, элемент , а вторая — это элемент . Это означает, что кнопка необязательно выглядит в HTML как элемент .
Тут имеется два дополнения к стилю .c-button . Это — свойства text-decoration: none; и text-align: center; . По умолчанию текст ссылок подчёркивается, поэтому мы хотим это изменить благодаря стилизации используемого класса. Кроме того, нам важно центрировать содержимое кнопки в тех случаях, когда для описания кнопки используется HTML-элемент, отличный от .
.c-button < /* другие стили */ /* Работает только для ссылок */ text-decoration: none; text-align: center; >
▍Элемент не обязан выглядеть как кнопка
Мне нравится этот пример, в котором, с учётом требований доступности контента, реализована панель-«аккордеон». Вначале, если представить, что JavaScript недоступен, результат рендеринга разметки выглядит так, как показано ниже.

Материалы страницы в условиях недоступности JavaScript
Вот HTML-код фрагмента такой разметки:
Heading of my panel Content goes here
В случае доступности JavaScript вышеприведённая разметка позволит описать элементы, которые могут сворачиваться и раскрываться. Достигается это путём создания кнопки и добавления её в элемент .

Материалы страницы в условиях, когда JavaScript-функциональность доступна
В данном случае можно сказать, что использование элемента — это правильный выбор, так как кнопка решает задачу разворачивания и сворачивания блоков текста.
▍Кнопка загрузки
Предположим, у нас имеется некий документ. Нам надо описать ссылку для его загрузки. Какой элемент стоит использовать для решения этой задачи? Тут нам на помощь придёт ссылка! Если добавить к ссылке атрибут download , при щелчке на неё будет инициирована загрузка соответствующих материалов.

Ссылка для загрузки документа, оформленная как кнопка
Вот код этой ссылки:
При таком подходе в нашем распоряжении оказывается ссылка, стилизованная как кнопка, которая делает своё дело, используя лишь семантические структуры HTML.
Кнопки с обводкой

Обычная кнопка при наведении на неё мыши становится кнопкой с обводкой
На предыдущем рисунке показана кнопка, которая становится кнопкой с обводкой при наведении на неё мыши. Какой способ лучше всего использовать для реализации подобного изменения внешнего вида кнопки? Для начала, стиль кнопки должен включать в себя свойство border , в котором, по умолчанию, используется прозрачный цвет. Предусмотрев такое свойство, мы делаем так, чтобы границы кнопки, при наведении на неё мыши, не перерисовывались бы.
.c-button < border: 2px solid transparent; /* другие стили */ >.c-button:hover
Благодаря такому подходу в нашем распоряжении оказывается кнопка, вокруг которой, при наведении на неё мыши, выводятся её границы. При этом фон кнопки становится прозрачным.
Градиентные кнопки
Когда я работал над статьёй о позиционировании элементов, мне понадобилась кнопка с градиентным заполнением.
Мне было нужно нечто, подобное следующему рисунку.

Градиентная кнопка и её вариант с обводкой
Тут представлены два варианта кнопки — градиентная кнопка и кнопка с обводкой. Для того чтобы добиться такого внешнего вида кнопки, мне нужно было, чтобы у базовой (градиентной) кнопки имелась бы прозрачная граница. Эта граница будет показана только для кнопки с обводкой.
.c-button < display: inline-block; color: #fff; background: linear-gradient(to bottom, #00acee, #0072e0); font-size: 18px; font-weight: 500; padding: 12px 26px; border-radius: 100px; /* Прозрачная граница, предназначенная для вывода варианта той же кнопки с обводкой */ border: 3px solid transparent; text-decoration: none; >.c-button--outline
Тут всё, вроде бы, выглядит разумно, но в ходе работы я столкнулся со странной проблемой. Я даже попытался решить её, попросив помощи у пользователей Twitter. Эта проблема представлена на следующем рисунке.

Обычная кнопка, кнопка с градиентом (граница, на самом деле, прозрачная; цветом она выведена лишь для наглядности), кнопка со странными краями
Теперь, когда мы разобрались с тем, как выглядит градиентная кнопка с прозрачной границей, позвольте мне рассказать о причинах вышеописанных странностей.
У каждого элемента есть свойство background-origin , определяющее область позиционирования фонового рисунка, которое по умолчанию установлено в значение padding-box . При таком подходе размер градиента подбирается так, чтобы он соответствовал бы размеру элемента с учётом толщины границы.
Я попробовал добавить к кнопке широкую границу для того чтобы понаблюдать за тем, что из этого получится. Обратите внимание на то, как повторяется градиент, и на то, что его размер соответствует свойству padding кнопки.

Кнопка с широкими границами и градиент
Для решения этой проблемы область позиционирования фонового рисунка нужно задать, воспользовавшись стилем background-origin: border-box; , изменив стандартное значение padding-box на border-box :
.c-button < /* другие стили */ background-origin: border-box; >
Вот, если хотите поэкспериментировать, пример на CodePen.
Что лучше — height или padding?
У каждой кнопки есть высота. Управлять высотой кнопки можно, либо задавая в явном виде её свойство height , либо задавая свойство padding для верхней и нижней сторон кнопки. Обратите внимание на то, что проблемы, о которых мы будем говорить ниже, характерны, в основном, для элементов .
▍Фиксированная высота
Предположим, что у нас имеется кнопка, стилизованная следующим образом:
.c-button < /* другие стили */ min-width: 120px; height: 45px; >
При таком подходе текст не выравнивается по центру. Выглядит всё это так, как показано ниже.

Кнопка, текст которой не выровнен по центру
Для того чтобы это исправить и выровнять текст, можно либо воспользоваться свойством padding , либо — свойством line-height . Устанавливая line-height в значение, равное или близкое к высоте кнопки, мы сможем выровнять текст по центру.
.c-button < /* другие стили */ min-width: 120px; height: 45px; line-height: 45px; >
Но у этого метода есть минусы:
- Не гарантировано то, что текст кнопки всегда будет правильно выровнен по центру. При изменении шрифта его выравнивание может быть нарушено.
- При увеличении значения, задаваемого свойством font-size , нужно подбирать новое значение для свойства line-height .
- Свойство line-height может работать по-разному для текстов, выводимых на разных языках. Это актуально для многоязычных сайтов.
- Если имеется кнопка с двумя строками текста — этот метод для выравнивания содержимого кнопки не подходит.
▍Вертикальный внутренний отступ
Если задают одинаковые значения для свойств padding-top и padding-bottom , то ожидают, что содержимое кнопки будет выровнено по центру. Так оно и есть? На самом деле, это зависит от конкретной ситуации.
Существуют шрифты, которые центруются очень хорошо. А есть такие, которые ведут себя иначе. Иногда для достижения цели одно из значений вертикального внутреннего отступа нужно немного изменить. Взгляните на следующую кнопку.

Попытка центровки текста кнопки
Вот CSS-код стилизации этой кнопки:
.c-button < /* другие стили */ min-width: 120px; padding: 16px 14px; >
В этом случае содержимое кнопки выглядит слегка смещённым. Значение верхнего внутреннего отступа нужно немного уменьшить:
.c-button < /* другие стили */ min-width: 120px; padding: 14px 14px 16px 14px; /* Верх, правая сторона, низ, левая сторона */ >
Оборачивание содержимого кнопки в тег
В ходе экспериментов я выяснил, что центровка текста кнопок Adobe немного сбита. Вот как это выглядит.

Центровка немного сбита
Я исследовал эти кнопки и заметил интересный паттерн. Содержимое обёрнуто в элемент с указанием фиксированной высоты для кнопки.
Для элемента элемент , по умолчанию, выравнивается по центру. Когда высота меняется, содержимое центрируется автоматически, без необходимости использования свойства padding или чего-нибудь ещё. Вот анимированная демонстрация этого поведения.
Изменение высоты кнопки и автоматическое центрирование её содержимого
Правда, если речь идёт о ссылке, выглядящей как кнопка, тогда элемент нужно выравнивать по центру. Для того чтобы учесть эту особенность, можно использовать способ компоновки элементов flexbox .
.c-button < /* другие стили */ display: inline-flex; *To keep the button inline, and flex container at the same time* align-items: center; justify-content: center; >
Вот и всё. Хочу отметить, что при написании данного раздела мне помогла эта статья.
Кнопки внутри flexbox- или grid-контейнеров
Тут у вас может появиться вопрос о том, какое отношение кнопки имеют к flex- и grid-макетам. Позвольте мне прояснить этот вопрос.
Я работал над разделом одного проекта. Мне нужно было вертикально центрировать его содержимое. Поэтому я использовал flex-макет:
.c-hero
То, что у меня получилось, меня несколько удивило.

Результат использования flex-макета
По умолчанию каждый flex-элемент растягивается в пределах ширины родительского элемента. Именно это и произошло с кнопкой, представленной на предыдущем рисунке. Для того чтобы избежать этой неприятности, нужно настроить свойство align-self :
.c-button < /* другие стили */ align-self: flex-start; >
Вот как кнопка будет выглядеть после этого.

Кнопка выглядит гораздо лучше
Ещё одна распространённая проблема возникает в ситуации, когда кнопка помещена во flex-контейнер, в котором, по умолчанию, задано свойство flex-direction: row . Высота кнопки будет подогнана под высоту родительского элемента. Для того чтобы исправить эту проблему, нужно использовать свойство кнопки align-self или свойство flex-контейнера align-items .

Кнопка, растянутая по высоте
.c-button
Задавая выравнивание кнопки относительно центра контейнера, мы решаем проблему. Вот как теперь будет выглядеть тот же пример.

Решение проблемы растянутой кнопки
Использование единиц измерения em
Единицу измерения em можно использовать для правильной настройки размеров кнопок. Эта единица измерения в такой ситуации весьма полезна. Единица измерения em равна font-size элемента ( px или rem ). Взглянем на следующий пример:
.element
В данном случае значение padding равно 16 * 0.5 px .
Предположим, что в проекте используются кнопки трёх размеров: обычные, средние, и большие. Когда для указания значений padding , width , height , margin используются единицы измерения em , это позволяет создавать кнопки, размеры которых очень легко менять. Вот как это выглядит.

Кнопки разных размеров
А вот фрагменты CSS-кода, в котором используется единица измерения em :
.c-button < /* другие стили */ font-size: 1rem; min-width: 6.25em; border-radius: 0.3125em; padding: 0.625em 1em; >.c-button svg
Для кнопок разного типа нужно создать классы, в которых задаётся разный размер шрифта:
.c-button--md < font-size: 22px; >.c-button--lg
→ Вот пример использования подобных кнопок на CodePen
→ Вот моя статья на эту тему. Рекомендую с ней ознакомиться
Анимация и переходы
Для того чтобы пользователю было бы приятнее работать со страницей важно подумать о том, чтобы при наведении мыши на кнопку использовался бы некий переход. Проще всего это сделать, организовав изменение цвета фона. Вот пример на CodePen, где можно увидеть реализацию этой идеи.
Итоги
Мне было очень приятно работать над этим материалом. Его написание заняло у меня больше года. Я счастлив от того, что он, наконец, опубликован. Надеюсь, вы нашли здесь что-то такое, что вам пригодится.
Уважаемые читатели! Известны ли вам какие-нибудь полезные способы работы с кнопками, которые остались за рамками этой статьи?
Пользовательский интерфейс
Электронный учебник
Представляем книгу Издательства Бюро Горбунова — практическое руководство по пользовательскому интерфейсу. Учебник предназначен для дизайнеров, редакторов, руководителей, разработчиков и всех, кто причастен к созданию продуктов.
Об интерфейсе написано много, но главные труды слишком академичны и проиллюстрированы устаревшими примерами. Современные же авторы обсуждают моду и частности, выражают личное мнение, но не дают базовых знаний. У читателя не создаётся цельной картины и системы ценностей, и он вынужден черпать вдохновение на Дрибле и Бехансе.
В книге последовательно раскрываются ключевые принципы хорошего интерфейса. Они работали двадцать лет назад и будут работать через двадцать лет. Поэтому каждый показан и на исторических, и на современных примерах.
От принципов автор переходит к законам взаимодействия, потом рассматривает язык интерфейса — текстовый и графический. В завершающем разделе речь идёт об организации экранов.
Автор — Илья Бирман
Арт‑директор бюро, соавтор «Советов», преподаватель Школы бюро
КПД ❔
16 дизайнеру, 12 редактору и руководителю
Оглавление
Принципы
Что такое интерфейс
Человечность
Технозависимость
Модальность
Последовательное волшебство
Взгляд новичка
Взаимодействие
Прицеливание
Информативность
Обратная связь
Листание и прокрутка
Язык
Элементы управления
Пиктограммы
Язык роботов
Экраны
В бюро радикально переосмыслили формат электронной книги
В бюро радикально переосмыслили формат электронной книги
Было
Существующие «е‑буки» далеки от высоких издательских стандартов оформления, неудобны для навигации и поиска. Типографика не выдерживает критики, причём шрифты и вёрстка неконтролируемы авторами и издателями. Книги случайно разбиты на экранные страницы — сколько ни открывай, одна и та же иллюстрация может оказаться наверху, внизу или даже на следующей странице. На планшете страницы сбиваются от случайного поворота устройства.
Стало
Бюрошная экранная книга соединяет удобство прокрутки и наглядность бумажной книги. Она поделена на развороты, которые можно прокрутить от начала до конца. Текст на развороте прокручивается, когда это необходимо, а иллюстрации сохраняют положение на экране. Читателю легко запомнить место и позднее вернуться к материалу. Разворот — смысловая единица, а не результат математического деления книги на «экраны».
Книга на экране
Интерактивный интерфейс, основанный на прокрутке, открывает возможности, неосуществимые в бумажной книге. Читатель интуитивно управляет сменой иллюстраций и даже процессом редизайна макетов, в любой момент возвращаясь назад или пропуская несколько шагов.
В Издательстве бюро установлены типографические стандарты и требования к электронным книгам, сравнимые или более жёсткие, чем в обычных «бумажных» издательствах. Книга служит образцом описанных в ней подходов, приёмов и принципов.
Книга разделена на развороты. Каждый разворот состоит из рассказа и иллюстрированных примеров
По удобству чтения на простых мониторах книга приближается к бумажной, а на «ретине» её читать ещё удобнее и приятнее
По удобству чтения на простых мониторах книга приближается к бумажной, а на «ретине» её читать ещё удобнее и приятнее
Книга разделена на развороты. Каждый разворот состоит из рассказа и иллюстрированных примеров
Книга разделена на развороты. Каждый разворот состоит из рассказа и иллюстрированных примеров
Проверка знаний
В бумажных книгах «вопросы в конце главы» вызывают недоумение и раздражение. Интерактивные тесты, наоборот, побуждают читателя попробовать свои силы на иллюстрированных примерах и мгновенно узнать результат.
Тесты помогают глубже понять материал. Если результат не устраивает, читатель снова изучает материал и пересдаёт тест
Тест предлагает вопросы на знание материала и анализ примеров: что хорошо и плохо, как улучшить
Тест предлагает вопросы на знание материала и анализ примеров: что хорошо и плохо, как улучшить
Тесты помогают глубже понять материал. Если результат не устраивает, читатель снова изучает материал и пересдаёт тест
Тесты помогают глубже понять материал. Если результат не устраивает, читатель снова изучает материал и пересдаёт тест
Справочник
«Пользовательский интерфейс» — настольная книга дизайнера интерфейса. Он пользуется ей как учебным пособием и справочником во время работы:
Дизайнер находит нужный пример в закладках, иллюстрированном оглавлении или поиске
Знания о синтаксисе элементов интерфейса сведены в подробную таблицу
Знания о синтаксисе элементов интерфейса сведены в подробную таблицу
Дизайнер находит нужный пример в закладках, иллюстрированном оглавлении или поиске
Дизайнер находит нужный пример в закладках, иллюстрированном оглавлении или поиске
Не забудьте купить плакат о синтаксисе интерфейса
Не забудьте купить плакат о синтаксисе интерфейса
Не забудьте купить плакат о синтаксисе интерфейса
Теория плюс примеры
Каждый принцип проиллюстрирован множеством примеров:
Предисловие издателя
В детстве я пытался зажигать плиту спичкой. Я чиркал спичкой, поворачивал с прижимом ручку — спичка обжигала пальцы, я чувствовал запах газа, но конфорка всё не зажигалась. Оказывалось, что я неправильно понимал обозначения и крутил не ту ручку. Тогда я решил, что просто на той плите непонятные значки.
В юности на своей первой съёмной квартире я смотрел телевизор по ночам. На пульте рядом с тремя рядами цифровых кнопок стоял точно такой же четвёртый ряд кнопок управления, и поэтому в темноте я не мог нащупать цифры. Кнопки управления громкостью и переключения каналов были одинаковыми «коромыслами», стоявшими рядом, так что вместо настройки громкости я переключал канал. Выключить телевизор перед сном тоже было непросто — кнопка выключения была лишь одной из четырёх одинаковых в верхнем ряду, громкость и каналы одинаковые. Тогда я понял, что это плохой пульт.
Когда я начал работать с компьютером, меня бесили ошибки из‑за неправильной раскладки клавиатуры. Индикатор раскладки был где‑то в углу, а проверять его каждый раз не хватит никакого внимания. С этим интерфейсом было что‑то не то.
В уходящем году я получил мотоциклетные права. И пока учился, испытал ужасные неудобства от включения нейтральной передачи. В отличие от автомобиля, где нейтраль включается простым жестом из любой передачи и моментально определяется по свободному движению ручки, нейтраль на мотоцикле — это зыбкое переходное состояние между верхним и нижним положением педали, которое нужно поймать филигранным движением ноги. А обозначается только зелёной лампочкой на панели. Как назло, на учебном повидавшем виды мотоцикле эта лампочка включалась через раз. Но потом выяснилось, что на новом необкатанном мотоцикле попасть в нейтраль ещё сложнее — в первый раз я минут пять не мог отпустить сцепление во дворе, пока дёргал педаль вверх‑вниз, потому что заветная лампочка никак не зажигалась. Нейтральная передача на мотоцикле включается неудобно.
В последней версии Ай‑ОСа появилась маленькая кнопка возврата к родительскому приложению из открытых внешних ссылок и приложений. К сожалению, эта кнопка не только слишком маленькая, но и расположена в том же углу, что и стандартная кнопка «назад» в текущем приложении. Поэтому я часто попадаю пальцем не в ту кнопку и испытываю раздражение, как, уверен, и другие миллионы пользователей.
Когда я становился дизайнером интерфейсов, я прочитал книгу Нормана и узнал, что проблема с плитами вовсе не в плохих значках, а в принципе соответствия.
Когда я работал над дизайном телевизионных пультов ББК , я установил требования ко всем пультам в серии: кнопка включения должна стоять в особом положении сверху, рядом с цифровыми кнопками не должно быть функциональных, коромысла громкости и переключения каналов должны быть перпендикулярны, а кнопки управления воспроизведением — узнаваться вслепую по форме. Об этих пультах писал Артемий Лебедев.
Проблема переключения раскладки клавиатуры в том, что неосознанные режимы вызывают модальные ошибки. Следить за индикатором клавиатуры неудобно, значит человек должен при печати мгновенно понимать, какая раскладка сейчас включена.
Если дизайнер понимает, что такое жесты и как формируются привычки, он распознает проблему нейтральной передачи на мотоцикле — это модальный интерфейс с неоднозначными жестами. Если включена первая передача, нейтраль включается движением носка вверх, если вторая — то движением вниз. Но если движение слишком резкое, то из первой передачи может сразу включится вторая, а из второй — первая. В результате в голове и теле с тремя разными задачами (включить нейтраль, первую или вторую передачу) связываются четыре разные привычки (нажать вниз осторожно, нажать вверх осторожно, нажать вниз уверенно, нажать вверх уверенно).
Дизайнер в Эпле, знакомый с законом Фиттса, вряд ли допустил бы ошибку с расположением кнопки «назад» осознанно и добровольно. Очевидно, это следствие корпоративного компромисса.
Эти и подобные знания о проектировании интерфейса накапливались в бюро в течение почти десяти лет из личных наблюдений, книг и проектов. Когда мы делали в 2007 году наш курс об интерфейсе, я даже немного стеснялся, что рассказываю в нём о вещах, известных из книг — о законе Фиттса, о привычках и жестах.
Но за десять лет выросла новая отрасль — мобильные приложения и интерфейсы, а многие дизайнеры до сих пор не имеют понятия об основах проектирования интерфейса. Я считаю, что эстетика — важнейшее требование к продукту, но, к сожалению, современная культура Дрибла принизила требовательность ко всему остальному.
Поэтому я с большим удовольствием представляю электронный учебник «Пользовательский интерфейс» своего коллеги Ильи Бирмана. Эта книга объясняет основы на классических и современных примерах продуктов, сайтов и приложений. Мы начинаем с общих принципов дизайна, объясняем особенности взаимодействия человека с продуктом, затем рассказываем о том, какими элементами интерфейс взаимодействует с пользователем.
В книге есть и собственные наработки. Синтаксис элементов интерфейса в русском языке — важнейший вклад бюро в знания об интерфейсах. Это подход к дизайну графического интерфейса, как к языку. Он отвечает на вопросы, почему один ряд названий пунктов меню или радиокнопок связно читается, а об другой спотыкаешься на каждом элементе. Синтаксис объясняет, почему подпись «введите» рядом с полем ввода выглядит наивно (хотя и может быть полезной новичку).
Стилизация старого доброго элемента button
Кнопка — это один из тех элементов, которые чаще всего используются на веб-страницах. Тег может быть применён для запуска некоего процесса вроде вывода данных, открытия модального окна, отправки формы и так далее. В материале, перевод которого мы публикуем, речь пойдёт о тонкостях стилизации элемента button и о том, как оформлять кнопки с учётом того, чтобы они хорошо работали бы в любых браузерах. Кроме того, тут будет рассмотрено большинство часто используемых стилей кнопок. Поговорим мы здесь и о некоторых сложностях, которые возникают при работе с кнопками.
Стили, применяемые к кнопкам по умолчанию
Может, разговор о «стандартных стилях» покажется кому-то обсуждением каких-то элементарных вещей, но, на самом деле, поговорить об этом довольно интересно. Вот стандартная таблица стилей для кнопок из пользовательского агента Google Chrome.
.c-button
А вот как выглядит стандартная кнопка, при выводе которой стили по умолчанию не менялись.

Простая кнопка, к которой применены стандартные стили
Для начала переопределим свойство appearance . Оно используется для стилизации, характерной для конкретной платформы. Внешний вид кнопки при таком подходе основан на стилях, применяемых в операционной системе пользователя.
.c-button
Теперь, после сброса свойства appearance , взглянем на то, как кнопки выглядят в разных браузерах.

Свойство appearance этих кнопок установлено в none
Далее, прежде чем мы перейдём, собственно, к стилизации, нам нужно сбросить ещё некоторые свойства. Это — border , border-radius , background .
.c-button

Кнопка после сброса свойств
Теперь, когда мы сбросили стандартные стили кнопки, пришло время двигаться дальше. А именно, я хочу рассказать о том, как стилизовать кнопки, основываясь требованиях, предъявляемых к их дизайну.
Стилизация обычных кнопок
Начнём с базового примера, поговорив о стилизации обычных кнопок, на которых выводится лишь текст. На следующем рисунке представлена «анатомия» обычной кнопки.

Цвет текста (Text Color), размер шрифта (Font Size), фон (Background), скругление углов (Roundness), внутренний отступ (Padding)
.c-button
Имея вышеприведённый CSS-код, мы можем получить кнопку, похожую на ту, которая показана на предыдущем рисунке. После того, как базовый стиль кнопки задан, нужно позаботиться о внешнем виде кнопки в различных состояниях.

Обычное состояние кнопки (Normal), получение фокуса (Focus), наведение на кнопку указателя мыши (Hover), отключение кнопки (Disabled)
▍Стили, применяемые к кнопкам при наведении на них мыши и при получении ими фокуса
Для того чтобы указать пользователю на то, что на кнопку наведён указатель мыши, важно оснастить кнопку стилем, рассчитанным на это событие. То же самое касается и изменения внешнего вида кнопки при получении ей фокуса в ситуации, когда со страницей работает пользователь, применяющий клавиатуру.
Этот материал указывает на то, что важен порядок добавления стилей, применяемых к кнопке при наведении на неё мыши ( hover ) и при получении ей фокуса ( focus ).
Когда стиль hover добавляют до стиля focus , все стили работают правильно. Проблема появляется тогда, когда стиль focus добавляют до стиля hover . Когда элемент щёлкают мышью, стиль focus никак себя не проявляет, видимым оказывается лишь представление кнопки, определяемое стилем hover .

Хорошо, если сначала идёт стиль hover, а потом — стиль focus
Вот как выглядит правильный порядок описания стилей:
.c-button:hover < background: #1d49aa; >.c-button:focus
▍Минимальная ширина кнопки
Для того чтобы кнопка хорошо выглядела, она должна иметь определённую ширину. Важно заранее об этом подумать и принять во внимание длинные и короткие надписи, которые могут содержаться на кнопках. Благодаря свойству min-width можно установить минимальную ширину кнопки. Вот моя статья, где в подробностях обсуждается это и другие подобные свойства.
Взгляните на следующий рисунок. Там можно видеть несколько кнопок, содержащих надписи разной длины на английском и арабском языках. Если не задавать минимальную ширину кнопки, кнопка, когда надпись на ней будет короткой, окажется слишком маленькой. Лучше этого не допускать и пользоваться свойством min-width .

Стоит задавать свойство кнопок min-width
.c-button < min-width: 100px; /* другие стили*/ >
▍Внутренние отступы
Привлекательной может выглядеть идея, в соответствии с которой кнопкам не назначают горизонтальные внутренние отступы. Ведь кнопки имеют определённую ширину, а значит — между краями кнопок и надписями, содержащимися на них, будет достаточно места. Так? Нет, не так. Реализация этой идеи может иметь негативные последствия в тех случаях, когда надпись на кнопке меняется.
Взглянем на следующий рисунок.

Рекомендовано назначать кнопкам внутренние отступы
Обратите внимание на то, что если кнопке не назначены внутренние отступы, надпись, расположенная на ней, может очень близко подходить к краям. Даже в том случае, если у кнопки есть свойство min-width . В нижней части рисунка используется и свойство padding , и свойство min-width . Это даёт больше уверенности в том, что кнопка будет хорошо выглядеть в ситуации, когда заранее неизвестна длина выводимой на ней надписи.
▍Семейство шрифта, используемого для надписей, расположенных на кнопках
Элементы форм, по умолчанию, не наследуют семейство шрифта, назначенное элементам или . Интересно заметить, что я написал 70% этой статьи и понял, что, во-первых, не поменял шрифт кнопки, используемой в демонстрационных целях, и, во-вторых, ничего об этом не написал.
Для решения этой проблемы свойство font-family должно быть установлено в значение inherit .
.c-button < font-family: inherit; /* другие стили */ >
▍Стилизация отключённых кнопок
Для того чтобы указать пользователю на то, что кнопка отключена, к ней можно добавить атрибут disabled и стилизовать кнопку средствами CSS.
Вот HTML-код, описывающий отключённую кнопку:
Вот CSS-код стилизации такой кнопки:
.c-button[disabled]
Когда кнопка отключена, она не может получить фокус с клавиатуры и удаляется из дерева доступности элементов страницы.
▍Внешний вид указателя мыши при наведении его на кнопку
Стандартный указатель мыши, наведённый на кнопку, выглядит как стрелка. Мне нравится этот ответ на StackOverflow: «Кнопки — это традиционный элемент управления настольных программ. Это — среда, в которой указатель в виде руки никогда не использовался до наступления эры интернета. Когда на веб-страницах стали применять тот же самый элемент управления, разработчики просто пытались сделать так, чтобы кнопки выглядели так же, как в настольных приложениях».
Для того чтобы переопределить обычное поведение указателя, рекомендовано поменять стандартный курсор-стрелку на курсор в виде руки.

Стандартный курсор-стрелка и улучшенный курсор в виде руки.
Теперь, когда мы обсудили базовые вопросы стилизации кнопок, приведём полный CSS-код, включающий в себя всё то, чего мы коснулись выше:
.c-button < min-width: 100px; font-family: inherit; appearance: none; border: 0; border-radius: 5px; background: #4676d7; color: #fff; padding: 8px 16px; font-size: 1rem; cursor: pointer; >.c-button:hover < background: #1d49aa; >.c-button:focus
В следующих разделах мы поговорим о разных стилях и типах кнопок, которые вы можете использовать в своих проектах.
Кнопки со значком
Иногда нужно, чтобы на кнопке был бы некий значок. Это может понадобиться для того, чтобы выделить кнопку, или чтобы лучше проинформировать пользователя о роли кнопки. Важно, чтобы кнопки со значками были бы доступны пользователям с ограниченными возможностями.

Примеры кнопок со значками
На предыдущем изображении имеются кнопки со значками. Ниже показан код, в котором к значку добавлен атрибут aria-hidden , что позволяет убрать его из дерева доступности. Я так же добавил атрибут focusable=»false» для того чтобы значок не получал бы фокус в IE.
Обратите внимание на то, что я воспользовался стилем vertical-align: middle для того чтобы выровнять значок и содержимое кнопки по вертикали.
Вот HTML-код кнопки, о которой идёт речь:
.c-button svg
То, что мы только что рассмотрели, может работать до тех пор, пока мы не решим скрыть текст кнопки и сделать её кнопкой, на которой находится только значок. Как это сделать? Сначала текст надо обернуть, например, в элемент span . Затем можно заняться дальнейшим улучшением внешнего вида кнопки. Вот HTML-описание кнопки:
Может показаться, что теперь достаточно просто скрыть элемент span и дело будет сделано:
.c-button--icon span
Хотя при таком подходе текст пропадает, а значок остаётся, это очень плохо в плане доступности контента. Кнопку уже «не видят» инструменты для чтения с экрана. Например, VoiceOver в macOS сообщает о том, что такая кнопка — это просто «Button», без каких-либо подробностей о ней. У этой проблемы есть несколько решений.
▍Использование SVG-значков
Я предпочитаю пользоваться SVG-значками. Рекомендуется собирать все SVG-описания графических элементов в один файл и подключать каждый значок в теге с использованием элемента . Вот пример:
Здесь показан код SVG-значка, описание которого хранится в файле icons.svg и имеет идентификатор #facebook . Этот подход позволяет снизить уровень дублирования кода.
▍Настройка размеров кнопки со значком
Так как текст кнопки больше не виден, и при этом для кнопки задано CSS-свойство min-width , ширина кнопки не будет соответствовать размеру значка. Для того чтобы учесть эту особенность, лучше в явном виде задать ширину кнопки со значком.

Кнопка, у которой задано CSS-свойство min-width, и кнопка, у которой это свойство не задано
.c-button--icon
▍Визуальное скрытие текста
Элемент, с помощью популярного класса .sr-only , можно скрыть визуально, убрав с экрана, но оставив доступным для средств чтения с экрана.
.sr-only
▍Установка размера шрифта в 0
Если установить свойство font-size в значение 0 , то элемент span не будет занимать вообще никакого места на экране. То есть он будет скрыт.
.c-button--icon span
Но тут я склоняюсь к решению, предусматривающему использование класса .sr-only . С моей точки зрения оно выглядит более логичным. Приём скрытия текста путём установки размера шрифта в 0, как мне кажется, похож на некий хак.
▍Использование атрибута aria-label
Если в кнопке нет элемента , тогда должен быть способ обойтись и без него. Один из таких способов заключается в использовании атрибута aria-label . Атрибут либо назначают самому элементу , либо — элементу .
Если вы хотите больше узнать о кнопках со значками — взгляните на этот материал.
Кнопки, содержащие несколько строк текста
В некоторых случаях может понадобиться, чтобы кнопка содержала бы две строки текста. Ниже показан пример такой кнопки.

Кнопка, содержащая две строки текста
Тут показана кнопка для формы подписки, содержащая основной и вспомогательный текст. Как сделать такую кнопку и при этом не забыть о её доступности для людей с ограниченными возможностями? Вот соответствующий HTML-код:
Средство для чтения с экрана «озвучит» эту кнопку как «Subscribe to our newsletter 240K+ subscribers». Когда пользователь это услышит, это его может запутать, так как ничто не будет разделять две строки текста, выводимые на кнопке. Взгляните на скриншот инструмента Chrome для исследования доступности элементов.

Исследование доступности элементов в Chrome
Для того чтобы не путать пользователей, я предпочёл бы скрыть вторую строку текста от средств для чтения с экрана. Сделать это можно, использовав атрибут aria-hidden в соответствующем элементе :
Если по какой-то причине изменить HTML-разметку нельзя, есть и другой способ добавления дополнительного текста на кнопку. Решение этой проблемы, которое показалось мне интересным, я нашёл на сайте Smashing Magazine. Оно заключается в том, чтобы размещать содержимое, пользуясь псевдоэлементами. При таком подходе средства для чтения с экрана не будут видеть ничего лишнего. Вот CSS-код этого решения:
.c-button--multiple span:after
Ссылки () или кнопки ()?
Когда стоит пользоваться ссылками, а когда — кнопками? Для начала давайте поговорим о том, чем они отличаются друг от друга.
▍Ссылки
▍Кнопки
Элемент сам по себе, без подключения к нему JavaScript-кода, не выполняет никаких действий. С ним можно использовать псевдоклассы :hover , :focus и :active . Если говорить о доступности, то с кнопкой можно взаимодействовать с помощью клавиатурных клавиш Enter и Пробел . Средства для чтения с экрана «читают» содержимое кнопок.
Если вспомнить о дизайне, то случается так, что веб-страница содержит кнопки одного и того же стиля, различающиеся в плане используемого для их описания HTML-кода. С учётом этого CSS-код для стилизации класса .c-button должен быть написан так, чтобы его можно было бы использовать и для элементов , и для элементов . Рассмотрим следующий пример.

Использование ссылок и кнопок
Обратите внимание на то, что «кнопки» на странице стилизованы одинаково. Однако первая из них — это, на самом деле, элемент , а вторая — это элемент . Это означает, что кнопка необязательно выглядит в HTML как элемент .
Тут имеется два дополнения к стилю .c-button . Это — свойства text-decoration: none; и text-align: center; . По умолчанию текст ссылок подчёркивается, поэтому мы хотим это изменить благодаря стилизации используемого класса. Кроме того, нам важно центрировать содержимое кнопки в тех случаях, когда для описания кнопки используется HTML-элемент, отличный от .
.c-button < /* другие стили */ /* Работает только для ссылок */ text-decoration: none; text-align: center; >
▍Элемент не обязан выглядеть как кнопка
Мне нравится этот пример, в котором, с учётом требований доступности контента, реализована панель-«аккордеон». Вначале, если представить, что JavaScript недоступен, результат рендеринга разметки выглядит так, как показано ниже.

Материалы страницы в условиях недоступности JavaScript
Вот HTML-код фрагмента такой разметки:
Heading of my panel Content goes here
В случае доступности JavaScript вышеприведённая разметка позволит описать элементы, которые могут сворачиваться и раскрываться. Достигается это путём создания кнопки и добавления её в элемент .

Материалы страницы в условиях, когда JavaScript-функциональность доступна
В данном случае можно сказать, что использование элемента — это правильный выбор, так как кнопка решает задачу разворачивания и сворачивания блоков текста.
▍Кнопка загрузки
Предположим, у нас имеется некий документ. Нам надо описать ссылку для его загрузки. Какой элемент стоит использовать для решения этой задачи? Тут нам на помощь придёт ссылка! Если добавить к ссылке атрибут download , при щелчке на неё будет инициирована загрузка соответствующих материалов.

Ссылка для загрузки документа, оформленная как кнопка
Вот код этой ссылки:
При таком подходе в нашем распоряжении оказывается ссылка, стилизованная как кнопка, которая делает своё дело, используя лишь семантические структуры HTML.
Кнопки с обводкой

Обычная кнопка при наведении на неё мыши становится кнопкой с обводкой
На предыдущем рисунке показана кнопка, которая становится кнопкой с обводкой при наведении на неё мыши. Какой способ лучше всего использовать для реализации подобного изменения внешнего вида кнопки? Для начала, стиль кнопки должен включать в себя свойство border , в котором, по умолчанию, используется прозрачный цвет. Предусмотрев такое свойство, мы делаем так, чтобы границы кнопки, при наведении на неё мыши, не перерисовывались бы.
.c-button < border: 2px solid transparent; /* другие стили */ >.c-button:hover
Благодаря такому подходу в нашем распоряжении оказывается кнопка, вокруг которой, при наведении на неё мыши, выводятся её границы. При этом фон кнопки становится прозрачным.
Градиентные кнопки
Когда я работал над статьёй о позиционировании элементов, мне понадобилась кнопка с градиентным заполнением.
Мне было нужно нечто, подобное следующему рисунку.

Градиентная кнопка и её вариант с обводкой
Тут представлены два варианта кнопки — градиентная кнопка и кнопка с обводкой. Для того чтобы добиться такого внешнего вида кнопки, мне нужно было, чтобы у базовой (градиентной) кнопки имелась бы прозрачная граница. Эта граница будет показана только для кнопки с обводкой.
.c-button < display: inline-block; color: #fff; background: linear-gradient(to bottom, #00acee, #0072e0); font-size: 18px; font-weight: 500; padding: 12px 26px; border-radius: 100px; /* Прозрачная граница, предназначенная для вывода варианта той же кнопки с обводкой */ border: 3px solid transparent; text-decoration: none; >.c-button--outline
Тут всё, вроде бы, выглядит разумно, но в ходе работы я столкнулся со странной проблемой. Я даже попытался решить её, попросив помощи у пользователей Twitter. Эта проблема представлена на следующем рисунке.

Обычная кнопка, кнопка с градиентом (граница, на самом деле, прозрачная; цветом она выведена лишь для наглядности), кнопка со странными краями
Теперь, когда мы разобрались с тем, как выглядит градиентная кнопка с прозрачной границей, позвольте мне рассказать о причинах вышеописанных странностей.
У каждого элемента есть свойство background-origin , определяющее область позиционирования фонового рисунка, которое по умолчанию установлено в значение padding-box . При таком подходе размер градиента подбирается так, чтобы он соответствовал бы размеру элемента с учётом толщины границы.
Я попробовал добавить к кнопке широкую границу для того чтобы понаблюдать за тем, что из этого получится. Обратите внимание на то, как повторяется градиент, и на то, что его размер соответствует свойству padding кнопки.

Кнопка с широкими границами и градиент
Для решения этой проблемы область позиционирования фонового рисунка нужно задать, воспользовавшись стилем background-origin: border-box; , изменив стандартное значение padding-box на border-box :
.c-button < /* другие стили */ background-origin: border-box; >
Вот, если хотите поэкспериментировать, пример на CodePen.
Что лучше — height или padding?
У каждой кнопки есть высота. Управлять высотой кнопки можно, либо задавая в явном виде её свойство height , либо задавая свойство padding для верхней и нижней сторон кнопки. Обратите внимание на то, что проблемы, о которых мы будем говорить ниже, характерны, в основном, для элементов .
▍Фиксированная высота
Предположим, что у нас имеется кнопка, стилизованная следующим образом:
.c-button < /* другие стили */ min-width: 120px; height: 45px; >
При таком подходе текст не выравнивается по центру. Выглядит всё это так, как показано ниже.

Кнопка, текст которой не выровнен по центру
Для того чтобы это исправить и выровнять текст, можно либо воспользоваться свойством padding , либо — свойством line-height . Устанавливая line-height в значение, равное или близкое к высоте кнопки, мы сможем выровнять текст по центру.
.c-button < /* другие стили */ min-width: 120px; height: 45px; line-height: 45px; >
Но у этого метода есть минусы:
- Не гарантировано то, что текст кнопки всегда будет правильно выровнен по центру. При изменении шрифта его выравнивание может быть нарушено.
- При увеличении значения, задаваемого свойством font-size , нужно подбирать новое значение для свойства line-height .
- Свойство line-height может работать по-разному для текстов, выводимых на разных языках. Это актуально для многоязычных сайтов.
- Если имеется кнопка с двумя строками текста — этот метод для выравнивания содержимого кнопки не подходит.
▍Вертикальный внутренний отступ
Если задают одинаковые значения для свойств padding-top и padding-bottom , то ожидают, что содержимое кнопки будет выровнено по центру. Так оно и есть? На самом деле, это зависит от конкретной ситуации.
Существуют шрифты, которые центруются очень хорошо. А есть такие, которые ведут себя иначе. Иногда для достижения цели одно из значений вертикального внутреннего отступа нужно немного изменить. Взгляните на следующую кнопку.

Попытка центровки текста кнопки
Вот CSS-код стилизации этой кнопки:
.c-button < /* другие стили */ min-width: 120px; padding: 16px 14px; >
В этом случае содержимое кнопки выглядит слегка смещённым. Значение верхнего внутреннего отступа нужно немного уменьшить:
.c-button < /* другие стили */ min-width: 120px; padding: 14px 14px 16px 14px; /* Верх, правая сторона, низ, левая сторона */ >
Оборачивание содержимого кнопки в тег
В ходе экспериментов я выяснил, что центровка текста кнопок Adobe немного сбита. Вот как это выглядит.

Центровка немного сбита
Я исследовал эти кнопки и заметил интересный паттерн. Содержимое обёрнуто в элемент с указанием фиксированной высоты для кнопки.
Для элемента элемент , по умолчанию, выравнивается по центру. Когда высота меняется, содержимое центрируется автоматически, без необходимости использования свойства padding или чего-нибудь ещё. Вот анимированная демонстрация этого поведения.
Изменение высоты кнопки и автоматическое центрирование её содержимого
Правда, если речь идёт о ссылке, выглядящей как кнопка, тогда элемент нужно выравнивать по центру. Для того чтобы учесть эту особенность, можно использовать способ компоновки элементов flexbox .
.c-button < /* другие стили */ display: inline-flex; *To keep the button inline, and flex container at the same time* align-items: center; justify-content: center; >
Вот и всё. Хочу отметить, что при написании данного раздела мне помогла эта статья.
Кнопки внутри flexbox- или grid-контейнеров
Тут у вас может появиться вопрос о том, какое отношение кнопки имеют к flex- и grid-макетам. Позвольте мне прояснить этот вопрос.
Я работал над разделом одного проекта. Мне нужно было вертикально центрировать его содержимое. Поэтому я использовал flex-макет:
.c-hero
То, что у меня получилось, меня несколько удивило.

Результат использования flex-макета
По умолчанию каждый flex-элемент растягивается в пределах ширины родительского элемента. Именно это и произошло с кнопкой, представленной на предыдущем рисунке. Для того чтобы избежать этой неприятности, нужно настроить свойство align-self :
.c-button < /* другие стили */ align-self: flex-start; >
Вот как кнопка будет выглядеть после этого.

Кнопка выглядит гораздо лучше
Ещё одна распространённая проблема возникает в ситуации, когда кнопка помещена во flex-контейнер, в котором, по умолчанию, задано свойство flex-direction: row . Высота кнопки будет подогнана под высоту родительского элемента. Для того чтобы исправить эту проблему, нужно использовать свойство кнопки align-self или свойство flex-контейнера align-items .

Кнопка, растянутая по высоте
.c-button
Задавая выравнивание кнопки относительно центра контейнера, мы решаем проблему. Вот как теперь будет выглядеть тот же пример.

Решение проблемы растянутой кнопки
Использование единиц измерения em
Единицу измерения em можно использовать для правильной настройки размеров кнопок. Эта единица измерения в такой ситуации весьма полезна. Единица измерения em равна font-size элемента ( px или rem ). Взглянем на следующий пример:
.element
В данном случае значение padding равно 16 * 0.5 px .
Предположим, что в проекте используются кнопки трёх размеров: обычные, средние, и большие. Когда для указания значений padding , width , height , margin используются единицы измерения em , это позволяет создавать кнопки, размеры которых очень легко менять. Вот как это выглядит.

Кнопки разных размеров
А вот фрагменты CSS-кода, в котором используется единица измерения em :
.c-button < /* другие стили */ font-size: 1rem; min-width: 6.25em; border-radius: 0.3125em; padding: 0.625em 1em; >.c-button svg
Для кнопок разного типа нужно создать классы, в которых задаётся разный размер шрифта:
.c-button--md < font-size: 22px; >.c-button--lg
→ Вот пример использования подобных кнопок на CodePen
→ Вот моя статья на эту тему. Рекомендую с ней ознакомиться
Анимация и переходы
Для того чтобы пользователю было бы приятнее работать со страницей важно подумать о том, чтобы при наведении мыши на кнопку использовался бы некий переход. Проще всего это сделать, организовав изменение цвета фона. Вот пример на CodePen, где можно увидеть реализацию этой идеи.
Итоги
Мне было очень приятно работать над этим материалом. Его написание заняло у меня больше года. Я счастлив от того, что он, наконец, опубликован. Надеюсь, вы нашли здесь что-то такое, что вам пригодится.
Уважаемые читатели! Известны ли вам какие-нибудь полезные способы работы с кнопками, которые остались за рамками этой статьи?
