JavaScript в CSS

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

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
	<style>
	:root {
		--script: alert("Hello from CSS");
	}
</style>
</head>
<body>
<script>
// получаем стили документа
const style = getComputedStyle(document.documentElement);
// получаем значение свойства --script
const script = style.getPropertyValue("--script");
// Выполняем код в свойстве --script
new Function(script)();

// альтернативный вариант выполнения
// eval(script);
</script>
</body>
</html>

Здесь свойство или переменная CSS --script хранит js-код, который выводит на консоль браузера сообщение.

Чтобы выполнить этот код, сначала получаем стили документа:

const style = getComputedStyle(document.documentElement);

Затем получаем среди этих стилей определение свойства --script:

const script = style.getPropertyValue("--script");

Далее выполняем код:

new Function(script)();

В качестве альтернативы для выполнения кода можно вызвать функцию eval():

eval(script);

В итоге на консоль браузера будет выведено соответствующее сообщение:

В качестве хранимого кода могут применяться более сложные выражения JavaScript. Например, используем конструкцию if:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <style>
  :root { --script: if (x == 5) document.body.style.background = "blue"; }
 </style>
</head>
<body>
<script>
let x = 10;

const style = getComputedStyle(document.documentElement);
const script = style.getPropertyValue("--script");
if (confirm("Присвоить х=5?")) x=5;
eval(script);
</script>

</body>
</html>

Здесь если значение переменной x больше 5, то окрашиваем пространство элемента body в синий цвет.

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

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
	<style>
	:root{
		--log: localStorage["minwidth"] = 0;
	}
	@media (min-width:500px) {
		:root{
			--log: localStorage["minwidth"] = 500;
		}
	}
	@media (min-width:800px) {
		:root{
			--log: localStorage["minwidth"] = 800;
		}
	}
	@media (min-width:1200px) {
		:root{
			--log: localStorage["minwidth"] = 1200;
		}
	}
	</style>
</head>
<body>
<script>
window.onload = window.onresize =()=>{
    const log = getComputedStyle(document.documentElement).getPropertyValue("--log");
	eval(log);
};
</script>
</body>
</html>

Здесь в localStorage записываем элемент с ключом "minwidth", значение которого зависит от значений media-query. А в коде javascript определяем обработчик событий window.onresize и window.onload, чтобы при загрузке страницы, а также при изменении ширины окна браузера значение в localStorage перезаписывалось.