-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfixed-block-with-mask.html
More file actions
179 lines (152 loc) · 11.6 KB
/
fixed-block-with-mask.html
File metadata and controls
179 lines (152 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
Фиксированный блок с динамической маской (для Тильды)
<!-- ********************************************************************** -->
<!-- Фиксированный блок с динамической маской -->
<!-- ********************************************************************** -->
<!-- Закрепляет первый экран (класс uc-first-screen) и создает эффект -->
<!-- «ухода под» остальные блоки при скролле через белую маску. -->
<!-- Поддерживает lazy loading Тильды и адаптивность. -->
<!-- ********************************************************************** -->
<script>
(function() {
// Основные переменные для работы скрипта
let mask; // DOM-элемент белой маски, которая будет скрывать фиксированный блок
let fixedBlock; // DOM-элемент блока, который нужно зафиксировать
let firstSiblingTop; // Позиция первого блока после фиксированного (в пикселях от верха страницы)
// Настройки скрипта - все параметры собраны в одном месте для удобства изменения
const CONFIG = {
fixedBlockClass: 'uc-first-screen', // CSS-класс блока, который нужно зафиксировать
maskClass: 'uc-dynamic-mask', // CSS-класс для создаваемой маски
siblingClass: 't-rec', // CSS-класс блоков-соседей (стандартный класс блоков Тильды)
maskBackground: '#ffffff', // Цвет фона маски (белый)
transitionSpeed: '0.1s' // Скорость анимации движения маски
};
/**
* Главная функция инициализации
* Находит нужный блок, создает маску и настраивает все элементы
*/
function initializeMask() {
// Ищем блок с классом uc-first-screen
fixedBlock = document.querySelector(`.${CONFIG.fixedBlockClass}`);
// Если блок еще не загружен (lazy loading), ждем еще 100мс
if (!fixedBlock) {
setTimeout(initializeMask, 100);
return;
}
// Проверяем, что блок с таким классом только один (для избежания конфликтов)
const allFixedBlocks = document.querySelectorAll(`.${CONFIG.fixedBlockClass}`);
if (allFixedBlocks.length > 1) {
console.warn(`Warning: Found ${allFixedBlocks.length} blocks with class "${CONFIG.fixedBlockClass}". Using the first one.`);
}
// Получаем высоту блока, который будем фиксировать
const fixedBlockHeight = fixedBlock.offsetHeight;
// Применяем CSS-стили для фиксации блока в верхней части экрана
fixedBlock.style.cssText += `
position: fixed !important; /* Фиксируем блок относительно окна браузера */
top: 0 !important; /* Прижимаем к верху */
left: 0 !important; /* Прижимаем к левому краю */
width: 100% !important; /* Растягиваем на всю ширину */
z-index: 1 !important; /* Низкий z-index, чтобы другие блоки были поверх */
`;
// Создаем белую маску, которая будет скрывать фиксированный блок
mask = document.createElement('div');
mask.className = CONFIG.maskClass;
// Применяем стили к маске
mask.style.cssText = `
position: fixed !important; /* Фиксируем маску */
top: 100vh !important; /* Изначально размещаем за нижним краем экрана */
left: 0 !important; /* Прижимаем к левому краю */
width: 100% !important; /* Растягиваем на всю ширину */
height: 100vh !important; /* Высота равна высоте экрана */
background: ${CONFIG.maskBackground} !important; /* Белый фон */
z-index: 50 !important; /* Средний z-index (выше фиксированного блока, но ниже контента) */
pointer-events: none !important; /* Маска не должна блокировать клики */
transition: transform ${CONFIG.transitionSpeed} ease-out !important; /* Плавная анимация движения */
`;
// Добавляем маску в DOM
document.body.appendChild(mask);
// Настраиваем все блоки, которые идут после фиксированного
const firstSibling = fixedBlock.nextElementSibling;
if (firstSibling) {
let currentSibling = firstSibling; // Текущий обрабатываемый блок
let isFirst = true; // Флаг для определения первого блока после фиксированного
// Проходим по всем блокам-соседям
while (currentSibling) {
// Проверяем, что это блок Тильды (имеет класс t-rec)
if (currentSibling.classList.contains(CONFIG.siblingClass)) {
// Применяем стили к блоку-соседу
currentSibling.style.cssText += `
position: relative !important; /* Относительное позиционирование */
z-index: 100 !important; /* Высокий z-index (поверх маски и фиксированного блока) */
background: ${CONFIG.maskBackground} !important; /* Белый фон для полного перекрытия */
`;
// Для первого блока после фиксированного добавляем отступ сверху
if (isFirst) {
// Отступ равен высоте фиксированного блока, чтобы контент не наезжал
currentSibling.style.marginTop = fixedBlockHeight + 'px';
// Запоминаем позицию первого блока для расчета движения маски
firstSiblingTop = currentSibling.getBoundingClientRect().top + window.scrollY;
isFirst = false;
}
}
// Переходим к следующему блоку
currentSibling = currentSibling.nextElementSibling;
}
}
// Разрешаем overflow для корневого контейнера Тильды
// (по умолчанию Тильда ставит overflow: hidden)
document.getElementById('allrecords').style.overflow = 'visible !important';
// Подключаем обработчики событий
window.addEventListener('scroll', updateMask); // Обновление маски при скролле
window.addEventListener('resize', recalculatePositions); // Пересчет позиций при изменении размера окна
// Выполняем первоначальное обновление маски
updateMask();
}
/**
* Функция обновления позиции маски при скролле
* Маска поднимается снизу и постепенно закрывает фиксированный блок
*/
function updateMask() {
// Проверяем, что маска создана и позиция первого блока определена
if (!mask || !firstSiblingTop) return;
const scrollY = window.scrollY; // Текущая позиция скролла
const windowHeight = window.innerHeight; // Высота окна браузера
// Вычисляем, насколько пользователь проскроллил относительно начала первого блока-соседа
// Формула: текущий скролл - (позиция первого блока - высота окна)
// Это означает, что маска начнет подниматься, когда первый блок появится в нижней части экрана
const scrollProgress = scrollY - (firstSiblingTop - windowHeight);
if (scrollProgress > 0) {
// Если пользователь проскроллил до области, где должна работать маска
// Вычисляем, на сколько пикселей поднять маску
// Маска не может подняться выше, чем на высоту окна
const maskOffset = Math.min(scrollProgress, windowHeight);
// Применяем трансформацию - поднимаем маску снизу
mask.style.transform = `translateY(-${maskOffset}px)`;
} else {
// Если еще не дошли до нужной области - маска остается внизу (не видна)
mask.style.transform = 'translateY(0)';
}
}
/**
* Функция пересчета позиций при изменении размера окна
* Нужна для корректной работы на мобильных устройствах при повороте экрана
*/
function recalculatePositions() {
if (!fixedBlock) return;
// Находим первый блок после фиксированного
const firstSibling = fixedBlock.nextElementSibling;
if (firstSibling && firstSibling.classList.contains(CONFIG.siblingClass)) {
// Пересчитываем его позицию
firstSiblingTop = firstSibling.getBoundingClientRect().top + window.scrollY;
}
}
// Запуск инициализации
// Проверяем, загрузился ли уже DOM
if (document.readyState === 'loading') {
// Если DOM еще загружается - ждем события DOMContentLoaded
document.addEventListener('DOMContentLoaded', initializeMask);
} else {
// Если DOM уже загружен - запускаем сразу
initializeMask();
}
})();
</script>