не работает должным образом кастомный курсор

На одном из видео нашел очень простую реализацию кастомного курсора с помощью css + js.

css:

.cursor {
  position: fixed;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--black);
  transition: 0.1s;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 200000;
  mix-blend-mode: difference;
}

a:hover~.cursor {
  transform: scale(6);
  -moz-transform: scale(6);
}

js:

const cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', (e) => {
  cursor.style.left = e.clientX + 'px';
  cursor.style.top = e.clientY + 'px';
})

Реализация должна состоять в следующем: мы имеем курсор (точку) черного цвета с шириной и высотой по 15 px. При наведении на ссылки, курсор должен изменять свой масштаб (transform: scale(6)). И т.к. ссылки на сайте черного цвета, при наведении курсора на ссылку, цвет ссылки должен стать белым с помощью свойства mix-blend-mode: difference. Но mix-blend-mode не срабатывает вообще (также пробовал с префиксами).

Если вместо тэга a поставить здесь a:hover ~ .cursor, например, тэг header, то transform:scale() срабатывает. Но mix-blend-mode: difference не меняет цвет ссылки на белый.

Как сделать так, чтобы transform: scale() срабатывал именно на ссылки при наведении? И как правильно реализовать изменение цвета ссылки, когда курсор будет наведен на нее (возможно есть варианты, подобные mix-blend-mode)?


Ответы (1 шт):

Автор решения: UModeL

Как задействовать все ссылки на странице?

  • Следующее правило (селектор ~ - указывает на любой соседний нижележащий элемент с классом cursor):

    a:hover~.cursor {
      transform: scale(6);
      -moz-transform: scale(6);
    }
    

    требует, чтобы блок .cursor имел общий родительский элемент со ссылкой (ссылками) и, при этом, стоял после ссылки (ссылок). Таким образом, блоки .cursor должны стоять везде, где есть ссылки. Такой подход неправильный, затратный и не обладает какой бы то ни было гибкостью. Хотя, если эффект нужен не по всей странице, а в пределах, например, блока навигации, то ваш вариант может сработать.

Решение здесь простое - задействовать JS, для отслеживания курсора на ссылках и на элементах внутри них.

Почему не работают свойства смешивания?

  • Часто, при использовании фильтров и свойств смешивания (mix-blend-mode и background-blend-mode), забывают про то, что большинство элементов имеют значение фонового цвета по умолчанию none или transparent. То же справедливо для тегов <html> и <body>. Из-за этого некоторые эффекты не работают должным образом - как можно смешивать цвет с "ничем" или с абсолютной прозрачностью? Поэтому рекомендуется явно задавать цвет.
  • Также желательно указывать размеры (высоту) <html> и <body> - во многих источниках оговаривается, что несоблюдение этого условия может сказаться на эффектах смешивания (хотя прямой ссылки на баг я не нашёл).

Думаю, что код ниже понятен без дополнительных комментариев:

const cursor = document.querySelector('.cursor');

document.addEventListener('mousemove', (ev) => {
  cursor.style.left = `${ev.pageX}px`;
  cursor.style.top = `${ev.pageY}px`;
});
document.addEventListener('mouseover', (ev) => {
  let target = ev.target.closest('a');
  cursor.classList.toggle('hover', target);
});
html {
  height: 100%;
  background-color: #fff;
}

body {
  margin: 0;
  min-height: 100vh;
  overflow: hidden;
  background-color: #fff;
  cursor: none;
}

.cursor {
  position: absolute;
  height: 15px; width: 15px;
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(1);
  background-color: #fff;
  pointer-events: none;
  mix-blend-mode: difference;
  transition: transform 0.2s;
}
.cursor.hover { transform: translate(-50%, -50%) scale(6); }

a { color: black; /* cursor: none; */ }
<nav>
  <a href="#">Первый</a>
  <a href="#"><i>Второй</i></a>
  <a href="#"><b>Третий</b></a>
</nav>
<hr>
<ul>
  <li><a href="#">Четвёртый</a></li>
  <li><a href="#"><em>Пятый</em></a></li>
  <li><a href="#"><strong>Шестой</strong></a></li>
</ul>
<h1><a href="#"><span>Седьмой</span></a></h1>

<div class="cursor"></div>

→ Ссылка