Подписывайтесь на мой твиттер, там всегда что-нибудь интересное!

Великолепный hover эффект с CSS переменными

Для того, чтобы понять, что такое CSS переменные то советую прочитать статью — Руководство по работе с переменными в CSS.

Там вы поймете, что с ними делать и как с ними быть. Ничего сложного на самом деле, только нужно немного захотеть разобраться.

А в этой статье вы узнаете как применять эти самые переменные в реальном и очень полезном кейсе. Создавая великолепный hover эффект.

Перевод статьи Stunning hover effects with CSS variables

Недавно я был воодушевлён забавной hover анимацией на сайте Grover. Двигая мышкой над кнопкой подписки появляется цветной градиент, который следует за курсором во время его движения. Идея простая, но как результат мы получаем кнопку, которая выделяется на фоне других и прямо напрашивается на то, чтобы по ней кликнули.

Как мы можем достигнуть такого же эффекта, чтобы наш сайт тоже выделялся? Ну, это не так сложно, как вы уже могли подумать.

Отслеживание позиции

Первое, что нам нужно это позиция мышки.

document.querySelector('.button').onmousemove = (e) => {
  const x = e.pageX - e.target.offsetLeft
  const y = e.pageY - e.target.offsetTop
  e.target.style.setProperty('--x', `${ x }px`)
  e.target.style.setProperty('--y', `${ y }px`)
 
}

Выберите элемент и ждите пока пользователь не двинет мышкой вдоль него.

Высчитайте позицию относительно элемента.

Сохраните координаты в CSS переменную.

Да, всего 9 строчек кода, чтобы указать CSS где пользователь позиционирует мышку. Вообще количество эффектов, которое вы можете сделать с помощью этой информации просто бесчисленно. Но давайте завершим наш CSS, для начала.

Анимируем градиент

Теперь у нас есть координаты записанные в CSS переменные и мы можем использовать их по всему нашему CSS.

.button {
  position: relative;
  appearance: none;
  background: #f72359;
  padding: 1em 2em;
  border: none;
  color: white;
  font-size: 1.2em;
  cursor: pointer;
  outline: none;
  overflow: hidden;
  border-radius: 100px;
  span {
    position: relative;
  }
  &::before {
    --size: 0;
    content: '';
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: var(--size);
    height: var(--size);
    background: radial-gradient(circle closest-side, #4405f7, transparent);
    transform: translate(-50%, -50%);
    transition: width .2s ease, height .2s ease;
  }
  &:hover::before {
    --size: 400px;
  }
}

Оберните текст в span, чтобы избежать того, что градиент появится над ним.

Начните с width и height 0px и поднимайте до 400px, когда пользователь наведет на кнопку. И не забудьте выставить переход (transition), чтобы бы все это происходило плавно, быстро и красиво.

Используйте координаты, чтобы следовать за мышкой.

Примените radial-gradient для background и используйте closest-side circle. Closest-side заполнит весь before, не выходя за него.

Результат

И всё! Добавьте недостающий HTML и наслаждайтесь кнопкой.

<button class="button">
  <span>Hover me I'm awesome</span>
</button>

codepen пример

Огромные возможности

Вы можете сделать огромное количество эффектов, реагируя на позицию мышки. Это прекрасно и с этим забавно поиграться.

Вот схожая анимация, которую я использовал:

Или включите фантазию и сделайте 3D параллакс кнопку:

Возможности безграничным. Только попробуйте сами.

Вопросы и ответы

Почему анимация width и height вместо использования transform: scale()?

Производительность довольно плоха при анимации width и height, и вам надо всегда стараться использовать transform при доступной возможности. Так почему я так не делал? Проблема в том, что браузер рендерит элементы (которые трансформируются) в ускоренном слое. Этот слой может вызывать проблемы в случае, когда кнопка имеет не прямоугольные края.

Конечно же есть способы для применения transform, но некоторые браузеры этого не любят. Отказ от применения transition до transform это одно потенциальное решение. Есть также обходное решение для Safari, которое может исправить эту проблему с обрезкой.