Эффект "фонарика" на календаре как в Win10
В Win10 в календаре есть эффект с плавным изменением цвета границ ячеек календаря, при движении мышкой получается как-будто "фонарик" подсвечивает ячейки. Скрины:
Мне стало интересно реализовать это на css/js, но с наскоку как-то не получилось) Как можно это сделать?
Вот заготовка:
const cellTemplate = document.querySelector('#cell-template').content.querySelector('.cell');
const list = document.querySelector('.list');
for (let i = 0; i < 30; i++) {
const cell = cellTemplate.cloneNode(true);
cell.querySelector('.cell-number').textContent = `${i + 1}`;
list.append(cell);
}
*,
*::after,
*::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
}
.list {
display: grid;
grid-template-columns: repeat(7, auto);
gap: 3px;
}
.cell {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
aspect-ratio: 1.0;
border: 2px solid transparent;
color: #eaeaea;
list-style: none;
user-select: none;
}
.cell:hover {
border-color: #777;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<ul class="list"></ul>
<template id="cell-template">
<li class="cell">
<span class="cell-number"></span>
</li>
</template>
<script src="script.js"></script>
</body>
</html>
Ответы (1 шт):
В общем немного заморочился и придумал такое решение:
const cellTemplate = document.querySelector('#cell-template').content.querySelector('.cell');
const subcellTemplate = document.querySelector('#subcell-template').content.querySelector('.subcell');
const container = document.querySelector('.container');
const sublist = document.querySelector('.list-subcells');
const list = document.querySelector('.list-cells');
const shadow = document.querySelector('.shadow');
function calcMouseCrd ({ x, y }) {
return {
x: x - container.offsetLeft - 0.5 * shadow.offsetWidth,
y: y - container.offsetTop - 0.5 * shadow.offsetHeight
};
}
function setShadowCrd ({ x, y }) {
shadow.style.left = `${x}px`;
shadow.style.top = `${y}px`;
}
(function () {
for (let i = 0; i < 30; i++) {
const cell = cellTemplate.cloneNode(true);
const subcell = subcellTemplate.cloneNode(true);
cell.querySelector('.cell-number').textContent = `${i + 1}`;
list.append(cell);
sublist.append(subcell);
}
setShadowCrd(calcMouseCrd({x: 0, y: 0}));
document.addEventListener('mousemove', (evt) => {
const { x, y } = calcMouseCrd({ x: evt.clientX, y: evt.clientY });
setShadowCrd({ x, y });
});
})();
*,
*::after,
*::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
}
.container {
position: relative;
display: grid;
overflow: hidden;
}
.list {
grid-row: 1/2;
grid-column: 1/2;
display: grid;
grid-template-columns: repeat(7, auto);
gap: 3px;
z-index: 1;
}
.list-subcells {
z-index: 0;
}
.shadow {
position: absolute;
width: 200vw;
aspect-ratio: 1.0;
background: radial-gradient(rgba(34, 34, 34, 0), #222 100px);
}
.cell {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
aspect-ratio: 1.0;
border: 2px solid transparent;
color: #eaeaea;
list-style: none;
user-select: none;
}
.cell:hover {
border-color: #999;
}
.subcell {
border-color: #666;
pointer-events: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<ul class="list list-subcells"></ul>
<div class="shadow"></div>
<ul class="list list-cells"></ul>
</div>
<template id="cell-template">
<li class="cell">
<span class="cell-number"></span>
</li>
</template>
<template id="subcell-template">
<li class="cell subcell"></li>
</template>
<script src="script.js"></script>
</body>
</html>
Решение основывается на том, что под список с ячейками календаря добавляется такой же список с пустыми ячейками subcell
, для которых задан постоянный цвет границы, отличающийся от фона. Оба списка помещаются в grid
-контейнер и накладываются друг на друга, а между ними помещается пустой div
shadow
с радиальным градиентом, цвет в градиенте не меняется, меняется только прозрачность - она становится максимальной в центре. Далее этот shadow
"привязывается" своим центром к курсору.
Может кому то пригодится.
А вообще было бы интересно посмотреть и другие подходы к реализации. Я ничего другого придумать не смог.