Градиентная прозрачность карточек, трансформация курсора при наведении
В данной статье рассмотрим как добиться градиентной прозрачности карточек и сделаем эффект трансформации курсора при наведении на карточку
HTML структура
Напишем простейшую структуру для примера
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Cards</title>
<link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
<link rel="preconnect" href="https://fonts.gstatic.com"/>
<link href="https://fonts.googleapis.com/css2?family=Teko:wght@300&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="css/main.css"/>
</head>
<body>
<div class="section">
<div class="container">
<div class="section__grid">
<div class="section__shape shape"></div>
<div class="section__card card">
<div class="card__image"><img src="https://images.unsplash.com/photo-1566480047210-b10eaa1f8095?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80" alt=""/></div>
<div class="card__title">mountain bike <b>RUDE</b></div>
</div>
<div class="section__card card">
<div class="card__image"><img src="https://images.unsplash.com/photo-1574117482334-14b040604998?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80" alt=""/></div>
<div class="card__title">mountain bike <b>GEAR</b></div>
</div>
</div>
</div>
</div>
<script src="js/main.js"></script>
</body>
</html>
CSS стили
За градиентную прозрачность отвечает свойство mask-image, которое может принимать в качестве значения градиенты, а также svg, png изображения
.card__image {
position: absolute;
z-index: 0;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 100%;
height: 100%;
-webkit-mask-image: linear-gradient(#222 48%, transparent);
mask-image: linear-gradient(#222 48%, transparent);
}
Чтобы увидеть градиентную прозрачность, стилизуем и анимируем круг на заднем плане
.shape {
-webkit-animation: move 3s ease-in-out infinite alternate;
animation: move 3s ease-in-out infinite alternate;
--size: 600px;
position: absolute;
width: var(--size);
height: var(--size);
border: 8px solid #e03616;
border-radius: 50%;
top: 50%;
left: 50%;
opacity: 0.64;
transform: translateY(-50%) translateX(-50%);
}
@-webkit-keyframes move {
0% {
opacity: 0.64;
transform: translateY(-50%) translateX(-50%) scale(0.9);
}
100% {
opacity: 0.8;
transform: translateY(-50%) translateX(-50%) scale(1);
}
}
@keyframes move {
0% {
opacity: 0.64;
transform: translateY(-50%) translateX(-50%) scale(0.9);
}
100% {
opacity: 0.8;
transform: translateY(-50%) translateX(-50%) scale(1);
}
}
Чтобы убрать курсор при наведении на карточку используем cursor: none;
Добавим полупрозрачный круг через псевдоэлемент :before
, назначим ему свойства left
и top
со значениями CSS переменных --x
и --y
, которые он будет брать от родительского элемента (динамику напишем на JavaScript чуть ниже). Начальный размер псевдоэлемента будет равен 0px
, а при наведении на карточку увеличиваем размер до 300px
. Для плавного изменения размера используем transition: width 0.48s ease, height 0.48s ease;
. Чтобы центр круга совпадал с координатами курсора назначаем transform: translate(-50%, -50%);
.card:before {
--size: 0px;
left: var(--x);
top: var(--y);
width: var(--size);
height: var(--size);
content: '';
position: absolute;
transform: translate(-50%, -50%);
transition: width 0.48s ease, height 0.48s ease;
z-index: 1;
border-radius: 50%;
background: rgba(255,0,0,0.24);
}
Полный CSS код примера
body {
font-family: 'Teko', sans-serif;
background: #fff;
position: relative;
background: #000;
display: grid;
}
.section {
background: #222;
overflow: hidden;
}
.section__grid {
z-index: 1;
display: grid;
place-items: center;
min-height: 100vh;
grid-template-columns: 1fr 1fr;
grid-gap: 32px;
gap: 32px;
padding: 64px 0;
}
.container {
max-width: 640px;
margin: 0 auto;
padding: 0 16px;
z-index: 1;
position: relative;
}
.card {
box-shadow: 0 4px 8px #111;
background: rgba(0,0,255,0.48);
padding: 32px;
border-radius: 32px;
width: 100%;
min-height: 400px;
display: flex;
align-items: flex-end;
color: #fff;
overflow: hidden;
position: relative;
cursor: none;
transition: background 0.48s ease, box-shadow 0.48s ease;
border: 4px solid #111;
}
.card:before {
--size: 0px;
left: var(--x);
top: var(--y);
width: var(--size);
height: var(--size);
content: '';
position: absolute;
transform: translate(-50%, -50%);
transition: width 0.48s ease, height 0.48s ease;
z-index: 1;
border-radius: 50%;
background: rgba(255,0,0,0.24);
}
.card:hover {
box-shadow: 0 8px 32px #111;
}
.card:hover:before {
--size: 300px;
}
.card__image {
position: absolute;
z-index: 0;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 100%;
height: 100%;
-webkit-mask-image: linear-gradient(#222 48%, transparent);
mask-image: linear-gradient(#222 48%, transparent);
}
.card__image img {
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
display: block;
}
.card__title {
z-index: 1;
pointer-events: none;
font-size: 24px;
text-align: right;
width: 100%;
color: rgba(255,255,255,0.48);
}
.card__title b {
font-size: 32px;
margin-left: 8px;
color: #fff;
}
.shape {
-webkit-animation: move 3s ease-in-out infinite alternate;
animation: move 3s ease-in-out infinite alternate;
--size: 600px;
position: absolute;
width: var(--size);
height: var(--size);
border: 8px solid #e03616;
border-radius: 50%;
top: 50%;
left: 50%;
opacity: 0.64;
transform: translateY(-50%) translateX(-50%);
}
@media (max-width: 639.98px) {
.section__grid {
grid-template-columns: 1fr;
}
}
@-webkit-keyframes move {
0% {
opacity: 0.64;
transform: translateY(-50%) translateX(-50%) scale(0.9);
}
100% {
opacity: 0.8;
transform: translateY(-50%) translateX(-50%) scale(1);
}
}
@keyframes move {
0% {
opacity: 0.64;
transform: translateY(-50%) translateX(-50%) scale(0.9);
}
100% {
opacity: 0.8;
transform: translateY(-50%) translateX(-50%) scale(1);
}
}
JavaScript код
Возьмем идею следования за курсором с крутого ресурса - https://www.30secondsofcode.org/css/s/mouse-cursor-gradient-tracking
Немного преобразуем код для нашей задачи
Логика следующая - при наведении на карточку вычисляем координаты курсора и назначаем эти значения в соответствующие CSS переменные. Элемент, который будет заменять курсор (в нашем случае это полупрозрачный круг) получает значения этих CSS переменных от родительского элемента (то есть от карточки) и динамически меняет свое положение в зависимости от них
Подробнее про по getBoundingClientRect()
- https://learn.javascript.ru/coordinates
Код с комментариями
document.addEventListener('DOMContentLoaded', () => { // структура документа загружена и готова к взаимодействию
let cards = document.querySelectorAll('.card'); // получаем все карточки
cards.forEach(card => { // для каждой карточки
card.addEventListener('mousemove', e => { // добавляем событие передвижения курсора
let rect = e.target.getBoundingClientRect(); // определяем координаты курсора
let x = e.clientX - rect.left; // вычисляем координату x
let y = e.clientY - rect.top; // вычисляем координату y
card.style.setProperty('--x', x + 'px'); // назначаем значение CSS переменной --x
card.style.setProperty('--y', y + 'px'); // назначаем значение CSS переменной --y
});
})
});
Получаем следующий результат
Архив с примером можно скачать по ссылке
Буду рад, если статья оказалась полезной
Спасибо за ваше внимание и уделённое время!