Как сделать анимированное подчеркивание ссылок на CSS
Реализовать подчеркивание на CSS непросто. Сложности возникают, если вам нужно нечто более оригинальное, чем стандартный text-decoration: underline. Существует немало различных методов — но, к сожалению, все они имеют серьезные недостатки.
С некоторыми из этих недостатков я и столкнулся после того, как подсмотрел стили оформления ссылок в блоге Кэсси Эванс. Ссылки в нем имеют впечатляющий эффект — при наведении курсора первоначальное подчеркивание отступает и заменяется другим. При этом во время замещения между двумя подчеркиваниями остается небольшой промежуток.
Неприятность, с которой я столкнулся, заключалась в следующем — в моем блоге ссылки часто переносятся на следующую строчку — а это означает, что часть ссылки остается неподчеркнутой. К слову, в блоге Кэсси впечатляют не только ссылки — там прекрасно все, от кода до контента.
Задача
Цветная линия, подчеркивающая ссылки, должна реагировать на наведение курсора — отступать и замещаться подчеркиванием другого цвета. Линии не соприкасаются во время этого эффекта, между ними остается небольшой промежуток. Кроме того — эффект должен распространяться на вторую часть ссылки, если она разделена переносом на следующую строку.
Применение фона
Существует сразу несколько различных способов подчеркнуть текстовый фрагмент. Я остановился на методе, который удовлетворяет всем критериям, и использует CSS свойство background-image. Фон background-image можно залить сплошным цветом, применяя функцию linear-gradient так, чтобы первый цвет перетекал во второй такой же.
Зачем использовать background-image, а не background-color, если предполагается заливка сплошным цветом? Дело в том, что background-image предоставляет больше свойств для манипуляций с фоном.
Размер фона ограничен по высоте и ширине и полностью заполняет ширину элемента ссылки — с помощью указания параметров background-size 2px и 100% соответственно. Это приводит к сплошному заполнению фона, поэтому я установил no-repeat для background-repeat.
Подчеркивание окажется сверху ссылки. Расположение линии меняем на нижнюю левую границу, устанавливая 0 100% для background-position — тогда она окажется внизу, под текстом ссылки.
Два фона
Для использования нескольких фоновых изображений и манипулирования их свойствами, установите для background-* несколько значений, разделенных запятыми. Первая запись из списка окажется верхним слоем, последующие будут нижними слоями. Фон элемента анкора будет сплошным черным (#000000). Белый (#FFFFFF) фон скрыт под ним:
a {
background-image: linear-gradient(#000000, #000000), linear-gradient(#ffffff, #ffffff);
}
В следующем примере используются два фона — оба находятся внизу, первый перекрывает второй:
a {
color: #dfe5f3;
text-decoration: none;
background-image: linear-gradient(rgb(176, 251, 188), rgb(176, 251, 188)),
linear-gradient(#feb2b2, #feb2b2);
background-size: 100% 2px, 100% 2px;
background-position: 100% 100%, 0 100%;
background-repeat: no-repeat, no-repeat;
}
Переход для background-size
Обратили внимание, чем отличаются параметры background-position, хотя визуально разницы нет? Один параметр привязан к левой стороне, второй — к правой.
Теперь я сделаю переход между одним фоном, который обычно заполняет всю ширину элемента анкора, и отступает при наведении курсора — и между вторым, который повторяет эту же операцию в зеркальном отражении. При этом привязка фонов будет влиять на то, в какую сторону они смещаются:
a {
color: #dfe5f3;
text-decoration: none;
background-image: linear-gradient(rgb(176, 251, 188), rgb(176, 251, 188)),
linear-gradient(#feb2b2, #feb2b2);
background-size: 100% 2px, 0 2px;
background-position: 100% 100%, 0 100%;
background-repeat: no-repeat;
transition: background-size 2s linear;
}
a:hover {
background-size: 0 2px, 100% 2px;
}
Три фона
Задача почти выполнена — осталось добавить промежуток между подчеркиваниями. Пробел между линиями можно имитировать, передвигая разделительный блок, цвет которого совпадает с фоновым. Что собой представляет подобный цветной разделитель? Верно, еще один фон. Что может быть лучше, чем два фона? Только три фона.
Этот фон я размещу поверх двух первых, указывая его первым в списке свойств для background-image. Не забудьте, что первое значение в списке свойств background-* теперь также относится к новому фону background-image. Высоту и ширину задаем с помощью background-size. Высота идентична параметрам предыдущих фонов (2px в нашем случае), а ширина установлена небольшая — 20px.
Переход для background-position
Разделительный фрагмент должен быть невидимым до наведения курсора, поэтому позиция фона background-position установлена отрицательной — это разместит разделитель слева от анкора, и таким образом полностью его скроет. В момент наведения курсора разделитель должен сдвинуться по подчеркиванию в противоположном направлении — и снова исчезнуть из вида.
Для вычисления обеих позиций воспользуемся функцией calc():
a {
color: #dfe5f3;
text-decoration: none;
background-image: linear-gradient(#222b40, #222b40), linear-gradient(
rgb(176, 251, 188),
rgb(176, 251, 188)
), linear-gradient(#feb2b2, #feb2b2);
background-size: 20px 2px, 100% 2px, 0 2px;
background-position: calc(20px * -1) 100%, 100% 100%, 0 100%;
background-repeat: no-repeat;
transition: background-size 2s linear, background-position 2s linear;
}
a:hover {
background-size: 20px 2px, 0 2px, 100% 2px;
background-position: calc(100% + 20px) 100%, 100% 100%, 0 100%;
}
Теперь анимированное подчеркивание работает так, как и требовалось. Мы благодарим Джея Томпкинса — настоящего волшебника в сфере CSS анимации. Именно он предложил метод анимации, основанный на манипуляции со свойством background-position.