Передача данных между CSS и JavaScript с помощью CSS-переменных

Одно из самых серьёзных противостояний в мире веб-разработки — CSS против JavaScript. У обоих есть свои достоинства, собственный синтаксис и идеи, иногда понять их может быть непросто. Но есть способы заставить их общаться и использовать достоинства каждого.

С позиции JavaScript для установки различных CSS-свойств HTML-элементу, требуется найти его в DOM и получить доступ к нему. После добавления стилей, у этого элемента появляется атрибут style, который вы не стали бы, наверное, писать вручную.

Ещё один способ доступа к CSS-свойствам из JavaScript — использовать настраиваемые CSS-свойства, они также известны, как «CSS-переменные» (CSS variables), которые можно определять с помощью синтаксиса --. Так:

:root {
  --pagebackground: powderblue;
}
body {
  background: var(--pagebackground);
}

Это «переменные», поэтому их можно неоднократно использовать в таблице стилей.

Получить к ним доступ и управлять значениями этих переменных можно с помощью JavaScript. В этом примере настраиваемое CSS-свойство устанавливается для корневого элемента документа. Его можно прочитать так:

let bg = getComputedStyle(document.documentElement).
  getPropertyValue('--pagebackground');

И его можно установить с помощью JavaScript, получив доступ к стилю корневого элемента (или вообще любого другого элемента с настраиваемыми свойствами), так:

document.documentElement.style.setProperty('--pagebackground', 'firebrick');

See this code Testing CSS Custom properties interaction on x.xhtml.ru.

Но самое выдающееся во всей этой истории то, что используя возможности JavaScript, можно предоставить CSS то, к чему он не может получить доступ. Например, CSS не может прочитать координаты курсора мыши, а JavaScript может.

Для начала, в CSS надо определить пару свойств --mouse-x и --mouse-y, а также установить им начальные значения — 0:

:root {
  --mouse-x: 0;
  --mouse-y: 0;
}

Затем, в JavaScript следует добавить документу обработчик mousemove. Тогда при движении курсора можно получать его координаты и управлять этими двумя CSS-свойствами с помощью JavaScript:

let root =  document.documentElement
document.addEventListener('mousemove', e => {
  root.style.setProperty('--mouse-x', e.x);
  root.style.setProperty('--mouse-y', e.y);
});

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

HTML:

<div id="ball"></div>

CSS

:root {
  --mouse-x: 0;
  --mouse-y: 0;
}
#ball {
 width: 20px;
 height: 20px;
 background: white;
 border-radius: 100%; 
 transform: translate(
   calc(calc(var(--mouse-x) - 10) * 1px), 
   calc(calc(var(--mouse-y) - 10) * 1px)
 );
}

Здесь некоторые пояснения к CSS:

  • ширина и высота DIV установлены равными 20 пикселей, а фон — белый
  • добавление border-radius: 100% гарантирует, что из квадрата получится круг.
  • затем используется transform: translate, чтобы позиционировать круг на экране. Это может быть что-то вроде transform: translate (200px, 300px), чтобы расположить наш шар на 200 пикселей по горизонтали и 300 пикселей по вертикали относительно левого верхнего угла.
  • поскольку JavaScript возвращает для настраиваемого CSS-свойства числовое значение, его необходимо преобразовать в пиксели, умножив на 1px.
  • так как размер шара составляет 20 пикселей, то чтобы поместить его центр в точки --mouse-x и --mouse-y, нужно вычесть из координат 10.

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

See this code Mouse position as custom CSS property on x.xhtml.ru.