От автора: меня бы удивило, если бы вы никогда не сталкивались с призрачными кнопками. Вы знаете их: у них прозрачный фон, который при наведении заливается сплошным цветом. В данной статье мы создадим призрачную кнопку в CSS, но это будет просто. Забавная и хитрая часть — это анимировать заливку этой призрачной кнопки так, чтобы фон заливался цветом в направлении, в котором на нее наводится курсор.
Вот с чего мы начинаем:
В большинстве случаев для заливки сплошным цветом background-color используется transition. Существуют макеты, в которых кнопка может заполняться слева направо, сверху вниз и т. д., для некоторого визуального изящества. Например, вот слева направо:
Тут есть моменты UX, к которым можно придираться. Например, если вы наводите курсор против направления заливки. Рассмотрим этот пример. Кнопка заливается слева, а вы наводите курсор справа.
Лучше, если кнопка заливается с начальной точки наведения.
Итак, как мы можем реализовать для кнопки определение направления наведения? Вашей первой мыслью может быть использовать решение на JavaScript, но вместо этого мы можем создать что-то с помощью CSS и небольшой дополнительной разметки.
Вот несколько чистых CSS кнопок-призраков с определением направления!
Давайте рассмотрим это шаг за шагом. Весь код доступен в этой коллекции CodePen.
Создание основы
Давайте начнем с создания основы призрачной кнопки. Разметка проста.
1 |
<button>Boo!</button> |
Наша CSS реализация будет использовать пользовательские свойства CSS. Это облегчает обслуживание. Они также позволяют легко выполнять настройку.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
button { --borderWidth: 5; --boxShadowDepth: 8; --buttonColor: #f00; --fontSize: 3; --horizontalPadding: 16; --verticalPadding: 8; background: transparent; border: calc(var(--borderWidth) * 1px) solid var(--buttonColor); box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888; color: var(--buttonColor); cursor: pointer; font-size: calc(var(--fontSize) * 1rem); font-weight: bold; outline: transparent; padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px); transition: box-shadow 0.15s ease; } button:hover { box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888; } button:active { box-shadow: 0 0 0 #888; } |
Объединение всего этого дает нам это:
Здорово! У нас есть кнопка и эффект наведения, но мы не можем ее закрасить цветом. Давайте сделаем это.
Добавление заливки
Для этого мы создаем элементы, которые показывают закрашенное состояние призрачной кнопки. Хитрость заключается в том, чтобы обрезать эти элементы через clip-path и скрыть их. Мы можем отобразить их при наведении курсора на кнопку путем перехода clip-path.
Дочерний элемент с 50% обрезки
Они должны совпадать с родительской кнопкой. Переменные CSS здесь очень помогут.
На первый взгляд, мы могли бы использовать псевдо-элементы. Однако этого не будет достаточно. Они также будут ухудшать доступность… но об этом позже.
Давайте начнем с добавления базовой заливки слева направо при наведении курсора. Во-первых, давайте добавим span. Этот span должен содержать тот же текстовый контент, что и кнопка.
1 2 3 |
<button>Boo! <span>Boo!</span> </button> |
Теперь нам нужно выровнять span с кнопкой. Переменные CSS сделают эту тяжелую работу.
1 2 3 4 5 6 7 8 9 10 11 |
button span { background: var(--buttonColor); border: calc(var(--borderWidth) * 1px) solid var(--buttonColor); bottom: calc(var(--borderWidth) * -1px); color: var(--bg, #fafafa); left: calc(var(--borderWidth) * -1px); padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px); position: absolute; right: calc(var(--borderWidth) * -1px); top: calc(var(--borderWidth) * -1px); } |
Наконец, мы обрезаем span вне поля зрения и добавляем правило, которое будет отображать его при наведении, обновляя обрезку. И в завершении мы определяем переход.
1 2 3 4 5 6 7 8 9 10 11 |
button span { --clip: inset(0 100% 0 0); -webkit-clip-path: var(--clip); clip-path: var(--clip); transition: clip-path 0.25s ease, -webkit-clip-path 0.25s ease; // ...Remaining div styles } button:hover span { --clip: inset(0 0 0 0); } |
Добавление определения направления
Итак, как мы можем добавить определение направления Нам нужны четыре элемента. Каждый элемент будет отвечать за обнаружение точки входа при наведении. С помощью clip-path мы можем разделить область кнопки на четыре сегмента.
Четыре сегмента :hover
Давайте добавим четыре span к кнопке и расположим их так, чтобы заполнить кнопку.
1 2 3 4 5 6 7 |
<button> Boo! <span></span> <span></span> <span></span> <span></span> </button> |
1 2 3 4 5 6 7 8 9 10 11 12 |
button span { background: var(--bg); bottom: calc(var(--borderWidth) * -1px); -webkit-clip-path: var(--clip); clip-path: var(--clip); left: calc(var(--borderWidth) * -1px); opacity: 0.5; position: absolute; right: calc(var(--borderWidth) * -1px); top: calc(var(--borderWidth) * -1px); z-index: 1; } |
Мы можем настроить выбор каждого элемента и назначить обрезку и цвет с помощью переменных CSS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
button span:nth-of-type(1) { --bg: #00f; --clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%); } button span:nth-of-type(2) { --bg: #f00; --clip: polygon(100% 0, 100% 100%, 50% 50%); } button span:nth-of-type(3) { --bg: #008000; --clip: polygon(0 100%, 100% 100%, 50% 50%); } button span:nth-of-type(4) { --bg: #800080; --clip: polygon(0 0, 0 100%, 50% 50%); } |
Здорово. Чтобы проверить это, давайте изменим непрозрачность при наведении.
1 2 3 4 5 6 |
button span:nth-of-type(1):hover, button span:nth-of-type(2):hover, button span:nth-of-type(3):hover, button span:nth-of-type(4):hover { opacity: 1; } |
Но есть проблема. Если мы наведем курсор через один элемент, а затем переместим его на другой, направление заливки изменится. Это будет отвлекать. Чтобы исправить это, мы можем установить z-index и clip-path при наведении, чтобы сегмент заполнял все пространство.
1 2 3 4 5 6 7 8 |
button span:nth-of-type(1):hover, button span:nth-of-type(2):hover, button span:nth-of-type(3):hover, button span:nth-of-type(4):hover { --clip: polygon(0 0, 100% 0, 100% 100%, 0 100%); opacity: 1; z-index: 2; } |
Собираем все вместе
Мы знаем, как создать анимацию заливки, и мы знаем, как определить направление. Как мы можем объединить их? Используя комбинатор элементов одного уровня!
Это означает, что при наведении курсора на определенный сегмент мы можем обнаружить определенный элемент заливки. Во-первых, давайте обновим разметку.
1 2 3 4 5 6 7 8 9 10 11 |
<button> Boo! <span></span> <span></span> <span></span> <span></span> <b>Boo!</b> <b>Boo!</b> <b>Boo!</b> <b>Boo!</b> </button> |
Теперь мы можем обновить CSS. Ссылаясь на заливку слева направо, мы можем повторно использовать стилизацию. Нам нужно только установить конкретный clip-path для каждого элемента. Я использовал тот же порядок, что имеют значения некоторых свойств. Первый дочерний элемент — верхний, второй — правый и так далее.
1 2 3 4 5 6 7 8 9 10 11 12 |
button b:nth-of-type(1) { --clip: inset(0 0 100% 0); } button b:nth-of-type(2) { --clip: inset(0 0 0 100%); } button b:nth-of-type(3) { --clip: inset(100% 0 0 0); } button b:nth-of-type(4) { --clip: inset(0 100% 0 0); } |
Последняя часть — обновить соответствующий элемент clip-path при наведении сегмента.
1 2 3 4 5 6 |
button span:nth-of-type(1):hover ~ b:nth-of-type(1), button span:nth-of-type(2):hover ~ b:nth-of-type(2), button span:nth-of-type(3):hover ~ b:nth-of-type(3), button span:nth-of-type(4):hover ~ b:nth-of-type(4) { --clip: inset(0 0 0 0); } |
Тада! У нас есть чистая кнопка-призрак с определением направления наведения на CSS.
Доступность
В своем текущем состоянии кнопка не соответствует критериям доступности.
Эти дополнительные элементы сбивают с толку, так как программа чтения с экрана будет повторять контент четыре раза. Нам нужно скрыть эти элементы от программы чтения с экрана.
1 2 3 4 5 6 7 8 9 10 11 |
<button> Boo! <span></span> <span></span> <span></span> <span></span> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> <b aria-hidden="true">Boo!</b> </button> |
Больше повторяющегося контента нет.
Вот и все! С помощью дополнительной разметки и некоторых хитростей CSS мы можем создавать призрачные кнопки с определением направления наведения. Используйте препроцессор или соберите компонент в своем приложении, и вам не нужно будет писать весь HTML. Вот демонстрация, использующая встроенные CSS-переменные для управления цветом кнопки.
Автор: Jhey Tompkins
Источник: //css-tricks.com
Редакция: Команда webformyself.