Hover CSS эффекты для блока и ссылок с примерами кода

Hover CSS эффекты для блока задаются псевдоклассом :hover: он меняет стиль элемента, пока указатель находится над ним. CSS при наведении позволяет менять цвет ссылки, поднимать карточку и раскрывать подменю. Соберите плавные эффекты по примерам кода и учтите клавиатуру, сенсорные экраны и производительность.

Что такое :hover в CSS

Псевдокласс :hover выбирает элемент под указателем. Браузер применяет правило, пока состояние сохраняется.

Селектор ставит двоеточие перед названием состояния. Запись .card:hover выбирает элемент с классом card, когда курсор находится над карточкой.

.card {
  color: #fff;
  background-color: #40577d;
}

.card:hover {
  background-color: #9a4771;
}

CSS меняет оформление без JavaScript и не переписывает HTML. Элемент должен существовать в документе, а селектор должен его выбрать.

Для ссылок сохраняйте порядок LVHA: :link → :visited → :hover → :active. При одинаковой специфичности более позднее правило получает приоритет.

a:link {
  color: #2457a6;
}

a:visited {
  color: #7040a0;
}

a:hover {
  color: #d04444;
}

a:active {
  color: #111;
}

Состояние :active идет после :hover, поэтому нажатая ссылка может получить цвет правила :active. Синтаксис описан в справке MDN о :hover.

Hover для ссылок и подчеркивания

Селектор a:hover задает оформление ссылки при наведении. Чтобы изменить ее цвет в CSS, задайте базовое правило и правило состояния.

<a class="link" href="/catalog.html">Открыть каталог</a>
.link {
  color: #2457a6;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.link:hover,
.link:focus-visible {
  color: #c43d3d;
  text-decoration-thickness: 0.14em;
}

text-underline-offset отодвигает линию от букв. :focus-visible повторяет сигнал для пользователя, который перемещается клавишей Tab.

Плавное подчеркивание при наведении в CSS можно создать фоновой полосой. В исходном состоянии ширина фона равна нулю.

.link--line {
  color: #2457a6;
  text-decoration: none;
  background: linear-gradient(#f0c928, #f0c928) 0 100% / 0 0.25em no-repeat;
  transition: background-size 180ms ease;
}

.link--line:hover,
.link--line:focus-visible {
  background-size: 100% 0.25em;
}

Полоса вырастает до ширины текста и плавно возвращается к нулю после ухода курсора.

Волнистую линию можно нарисовать статичным SVG внутри background-image. Такой вариант не требует отдельной картинки.

.wave-link {
  color: #2457a6;
  text-decoration: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 6'%3E%3Cpath d='M0 3 Q5 0 10 3 T20 3 T30 3 T40 3' fill='none' stroke='%23d04444' stroke-width='2'/%3E%3C/svg%3E");
  background-position: 0 100%;
  background-repeat: repeat-x;
  background-size: 40px 6px;
}

.wave-link:hover,
.wave-link:focus-visible {
  background-size: 28px 6px;
}

При наведении волна станет плотнее под текстом. Если фон снижает читаемость, оставьте обычное подчеркивание.

Плавный переход через transition

transition описывает переход между двумя значениями свойства. В записи участвуют свойство, длительность, функция времени и задержка.

.button {
  transition-property: color, background-color, transform;
  transition-duration: 180ms;
  transition-timing-function: ease-out;
  transition-delay: 0ms;
}

Краткая запись объединяет параметры: transition: color 180ms ease-out 0ms. Длительность задавайте в миллисекундах или секундах.

Пишите transition в базовом состоянии. Тогда браузер анимирует включение эффекта и возврат после ухода указателя.

.card {
  transition: transform 180ms ease, box-shadow 180ms ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 10px 24px rgb(0 0 0 / 18%);
}

Карточка поднимется на 4 пикселя и получит тень. После ухода курсора она плавно вернется.

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

Полный синтаксис разобран в документации MDN о transition.

Hover css эффекты для блока

Hover css эффекты для блока меняют масштаб, положение и оформление. Общий класс задает базовый вид, а каждый рецепт меняет одно свойство.

<article class="demo-card">
  <a class="demo-card__link" href="/catalog.html">Открыть каталог</a>
</article>
.demo-card {
  width: 220px;
  min-height: 120px;
  padding: 24px;
  color: #fff;
  background-color: #40577d;
  border-radius: 12px;
  transition: transform 180ms ease, opacity 180ms ease,
    box-shadow 180ms ease, border-radius 180ms ease,
    background-color 180ms ease;
}

.demo-card__link {
  color: inherit;
}

.demo-card__link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

Масштаб увеличивает отрисовку блока, но не меняет его width и height. Соседи сохраняют прежние места.

.demo-card:hover,
.demo-card:focus-within {
  transform: scale(1.06);
}

Карточка станет крупнее при наведении или фокусе ссылки внутри.

.demo-card:hover,
.demo-card:focus-within {
  transform: rotate(-3deg);
}

Блок повернется на 3 градуса против часовой стрелки.

.demo-card:hover,
.demo-card:focus-within {
  transform: translateY(-8px);
}

Верхний край поднимется на 8 пикселей без изменения места в потоке.

.demo-card:hover,
.demo-card:focus-within {
  opacity: 0.65;
  box-shadow: 0 12px 28px rgb(0 0 0 / 22%);
  border-radius: 28px;
  background-color: #9a4771;
}

Блок станет прозрачнее, получит тень, более круглые углы и новый фон. Проверьте контраст текста после смены цвета.

CSS hover на другой элемент

Чтобы при наведении изменить другой элемент, используйте комбинаторы селекторов. Наведенный элемент и цель должны быть связаны соседством или общей вложенностью.

Комбинатор + выбирает только следующего соседа. Цель должна идти сразу после триггера.

<button class="trigger" type="button">Навести</button>
<span class="target">Текст изменится</span>
.trigger:hover + .target,
.trigger:focus-visible + .target {
  color: #d04444;
}

Текст справа изменит цвет при наведении или клавиатурном фокусе.

Комбинатор ~ выбирает всех подходящих соседей после триггера.

.trigger:hover ~ .target,
.trigger:focus-visible ~ .target {
  color: #d04444;
}

Цвет изменится у каждого последующего элемента с классом target.

Пробел между селекторами выбирает потомка. Запись .card:hover .title работает, если заголовок находится внутри карточки.

.card:hover .title {
  color: #f0c928;
}

.card:hover .icon {
  transform: translateY(-3px);
}

Заголовок пожелтеет, а значок поднимется на 3 пикселя.

Псевдокласс :has() выбирает карточку, внутри которой находится наведенная кнопка.

.card:has(.button:hover),
.card:has(.button:focus-visible) {
  outline: 2px solid #f0c928;
}

Контур появится вокруг карточки при наведении на кнопку или ее фокусе.

Тот же прием меняет предыдущий элемент внутри общего родителя.

.row:has(.status:hover) .label,
.row:has(.status:focus-visible) .label {
  color: #d04444;
}

Подпись перед кнопкой изменит цвет. Селектор не достает произвольный несвязанный узел: цель должна быть потомком, соседом или частью общего родителя.

Для окружений без :has() оставьте базовый стиль и продублируйте действие на общем контейнере. Если изменить разметку нельзя, используйте JavaScript для переключения класса на родителе.

Синтаксис :has() описан в справке MDN. Такое правило стоит применять после проверки целевых браузеров и с нейтральным оформлением по умолчанию.

Выпадающее меню при наведении

Родительский пункт списка удерживает подменю под курсором. Состояние :focus-within открывает тот же блок при переходе клавишей Tab.

<nav class="menu" aria-label="Основное меню">
  <ul class="menu__list">
    <li class="menu__item">
      <a href="/catalog.html">Каталог</a>
      <ul class="menu__submenu">
        <li><a href="/books.html">Книги</a></li>
        <li><a href="/courses.html">Курсы</a></li>
      </ul>
    </li>
  </ul>
</nav>
.menu__list,
.menu__submenu {
  margin: 0;
  padding: 0;
  list-style: none;
}

.menu__item {
  position: relative;
}

.menu__submenu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 180px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity 160ms ease, transform 160ms ease,
    visibility 0s linear 180ms;
}

.menu__item:hover .menu__submenu,
.menu__item:focus-within .menu__submenu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

При закрытии visibility сохраняет подменю еще 180 миллисекунд. Курсор успевает перейти к дочерним ссылкам.

Нажмите Tab до ссылки «Каталог», затем перейдите к «Книгам» и «Курсам». Подменю останется открытым, пока фокус находится внутри пункта.

Hover на телефонах и для клавиатуры

Тач-устройство не дает такого же постоянного указателя, как мышь. При этом браузер может имитировать или сохранять состояние :hover после касания, поэтому эффект иногда выглядит «залипающим».

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

@media (hover: hover) and (pointer: fine) {
  .card:hover {
    transform: translateY(-4px);
  }

  .link:hover {
    color: #c43d3d;
  }
}

Клавиатурные состояния оставляйте вне этого блока. Так ссылка сохраняет обратную связь без мыши.

.card:focus-within {
  outline: 2px solid #f0c928;
  outline-offset: 4px;
}

.card__link:focus-visible {
  outline: 3px solid #2457a6;
  outline-offset: 4px;
}

Если сенсорный экран не поддерживает нужное поведение, не прячьте важное действие только в :hover. Для меню можно оставить подменю раскрытым или добавить отдельную кнопку.

@media (hover: none) {
  .menu__submenu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
  }
}

Ссылки подменю появятся сразу под пунктом «Каталог». Медиазапрос (hover: none) не заменяет проверку реального сценария на телефоне.

Уважайте настройку уменьшения движения пользователя.

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms;
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    scroll-behavior: auto;
  }
}

Цвет, контраст и видимый фокус сохраняются, а длительные переходы почти исчезают. Справка о фокусе находится в документации MDN о :focus-visible.

Производительность hover-анимаций

Для плавности выбирайте свойства, которые не меняют геометрию документа. Обычно подходят transform и opacity.

.tile {
  transition: transform 180ms ease, opacity 180ms ease;
}

.tile:hover {
  transform: translateY(-6px) scale(1.02);
  opacity: 0.92;
}

Блок поднимется, немного увеличится и сохранит прежнее место в раскладке.

Изменение width, height, top или margin может запустить перерасчет раскладки. В сетке карточек такой эффект сдвигает соседей.

Фон, тень и скругление способны вызвать перерисовку. Свойство will-change применяйте точечно, когда элемент готовится к сложной анимации.

.hero-card {
  will-change: transform;
}

.hero-card:hover {
  transform: scale(1.04);
}

Не добавляйте will-change всем карточкам. Браузер потратит лишние ресурсы на подготовку множества элементов.

В DevTools откройте панель Rendering, включите Paint flashing и наведите курсор на элемент. Зеленая подсветка покажет области, которые браузер перерисовывает.

Описание режима находится в документации Chrome DevTools о Rendering.

Ошибки при работе с :hover

Нарушенный порядок LVHA создает неожиданный цвет ссылки. При одинаковой специфичности оставляйте состояния в порядке :link, :visited, :hover, :active.

Переход только в :hover исчезает рывком после ухода курсора. Перенесите transition в базовый селектор.

Изменение размера или добавление границы сдвигает соседей. Оставьте место под границу заранее.

.button {
  border: 2px solid transparent;
}

.button:hover,
.button:focus-visible {
  border-color: #f0c928;
}

Цвет границы изменится без роста внешнего размера кнопки.

Меню закрывается по пути к подменю, когда между ними остается просвет. Общий родитель, абсолютное позиционирование и задержка visibility сохраняют область меню.

Эффект только для мыши недоступен пользователям клавиатуры. Добавляйте важное состояние к :focus-visible, а вложенное меню открывайте через :focus-within.

Слишком сильный масштаб отвлекает от содержимого. Ограничьте движение и учтите prefers-reduced-motion: reduce.

Комментарии

Оставьте свой комментарий
Пока никто не оставил комментариев