Corp/docs/completed/FOUC_FIX.md
Игорь Надеин ee6e840252 Реорганизация документации и скриптов проекта
- Создана структура docs/ с категориями: completed, guides, architecture, diagnostic, in-progress, reports
- Перемещено 47+ MD файлов из корня проекта в docs/
- Удалено 6 устаревших/дублирующихся файлов
- Создана структура backend/scripts/ для тестов и утилит
- Перемещено 35 Python скриптов в backend/scripts/
- Создана структура backend/docs/ для технической документации
- Перемещено 12 MD файлов backend в backend/docs/
- Перемещены LDAP тестовые данные в backend/tests/fixtures/
- Добавлены README файлы для навигации
- Добавлены правила в .github/copilot-instructions.md для размещения документации

Результат:
- Корень проекта: только README.md
- Корень backend/: только manage.py и Django приложения
- Вся документация организована в структурированные папки
2025-12-26 13:49:51 +03:00

246 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Устранение FOUC (Flash of Unstyled Content)
## Проблема
При переходе между страницами происходило **мигание белой темы**, даже если пользователь выбрал тёмную тему.
### Ошибочное предположение
❌ "Стили не кэшируются" - **НЕверно!**
- Статические файлы (CSS/JS) **всегда** кэшируются браузером
- Nginx выдаёт их с `Cache-Control: public, max-age=31536000`
- Проблема была НЕ в кэше!
### Настоящая причина
✅ **Неправильный порядок выполнения скриптов**:
```
1. HTML загружается с data-bs-theme="auto"
2. CSS загружается и применяется (тема = auto = светлая)
3. 🔥 МИГАНИЕ БЕЛОЙ ТЕМЫ 🔥
4. JavaScript выполняется и меняет тему на тёмную
```
## Решение
### До (неправильно)
```html
<html data-bs-theme="auto">
<head>
<link rel="stylesheet" href="bootstrap.css">
<!-- Стили применяются с auto = светлая тема -->
</head>
<body>
<script defer>
// Слишком поздно! Уже видели белую тему
document.documentElement.setAttribute('data-bs-theme', 'dark');
</script>
</body>
</html>
```
### После (правильно)
```html
<html>
<head>
<!-- 1. СРАЗУ применяем тему ДО загрузки CSS -->
<script src="themeInitializer.js"></script>
<!-- 2. Preload критичных стилей -->
<link rel="preload" href="bootstrap.css" as="style">
<link rel="preload" href="variables.css" as="style">
<!-- 3. Теперь загружаем CSS - тема уже установлена! -->
<link rel="stylesheet" href="bootstrap.css">
<link rel="stylesheet" href="variables.css">
</head>
<body>
<!-- Никакого мигания! -->
</body>
</html>
```
## Как работает themeInitializer.js
### Синхронное выполнение (НЕ defer, НЕ async, НЕ module)
```javascript
(function() {
'use strict';
// 1. Читаем сохранённую тему из localStorage
const savedTheme = localStorage.getItem('theme') || 'auto';
// 2. Определяем эффективную тему
let effectiveTheme = savedTheme;
if (savedTheme === 'auto') {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
effectiveTheme = prefersDark.matches ? 'dark' : 'light';
}
// 3. НЕМЕДЛЕННО устанавливаем атрибут
document.documentElement.setAttribute('data-bs-theme', effectiveTheme);
// Всё это происходит ДО парсинга <body> и ДО загрузки CSS!
})();
```
### Почему это работает
- ✅ Скрипт выполняется **синхронно** в `<head>`
- ✅ Браузер **блокируется** до выполнения скрипта
- ✅ Атрибут `data-bs-theme` устанавливается **ДО** применения CSS
- ✅ CSS применяется сразу с правильной темой
- ✅ Никакого мигания!
## Preload критичных стилей
### Зачем нужен preload?
```html
<link rel="preload" href="bootstrap.css" as="style">
<link rel="stylesheet" href="bootstrap.css">
```
**Без preload**:
1. Браузер парсит HTML
2. Доходит до `<link rel="stylesheet">`
3. Начинает загрузку CSS (задержка!)
4. Парсит CSS
5. Применяет стили
**С preload**:
1. Браузер парсит HTML
2. Видит `<link rel="preload">` → начинает загрузку **параллельно**
3. Доходит до `<link rel="stylesheet">` → CSS уже загружен!
4. Сразу применяет стили
**Результат**: ускорение на 100-300ms
## Кэширование и FOUC
### Важно понимать!
**Кэш НЕ решает проблему FOUC**:
```
С кэшем (неправильный порядок):
1. HTML из disk cache (0ms)
2. CSS из disk cache (0ms) ← быстро!
3. 🔥 Но всё равно мигание! 🔥
4. JS меняет тему (слишком поздно)
С кэшем (правильный порядок):
1. HTML из disk cache (0ms)
2. themeInitializer.js СИНХРОННО (0ms)
3. data-bs-theme установлен ДО парсинга CSS
4. CSS из disk cache (0ms) применяется с правильной темой
5. ✅ Никакого мигания!
```
**Вывод**:
- Кэш **ускоряет** загрузку
- Правильный порядок **устраняет** FOUC
- Нужны **оба** решения!
## Тестирование
### Как проверить, что FOUC устранён
1. **Выберите тёмную тему** на сайте
2. **Hard refresh** (Ctrl+Shift+R) для сброса кэша
3. **Быстро переходите** между страницами
4. **Результат**: НЕ должно быть белых вспышек
### Проверка в DevTools
```javascript
// Откройте Console
// Проверьте, что атрибут установлен ДО DOMContentLoaded
console.log('Theme on parse:', document.documentElement.getAttribute('data-bs-theme'));
// Должно вывести 'dark' или 'light', НЕ 'auto'
```
### Проверка порядка загрузки
Network tab → фильтр "CSS":
1. ✅ `themeInitializer.js` - загружен первым
2. ✅ `bootstrap.css` (preload)
3. ✅ `variables.css` (preload)
4. ✅ Остальные стили
## Частые ошибки
### ❌ Использование defer/async
```html
<!-- НЕПРАВИЛЬНО: defer выполнится ПОСЛЕ парсинга -->
<script src="themeInitializer.js" defer></script>
<!-- ПРАВИЛЬНО: синхронное выполнение -->
<script src="themeInitializer.js"></script>
```
### ❌ Использование type="module"
```html
<!-- НЕПРАВИЛЬНО: модули выполняются с defer -->
<script type="module" src="themeInitializer.js"></script>
<!-- ПРАВИЛЬНО: обычный скрипт -->
<script src="themeInitializer.js"></script>
```
### ❌ Установка темы в DOMContentLoaded
```javascript
// НЕПРАВИЛЬНО: слишком поздно!
document.addEventListener('DOMContentLoaded', () => {
document.documentElement.setAttribute('data-bs-theme', 'dark');
});
// ПРАВИЛЬНО: немедленно
document.documentElement.setAttribute('data-bs-theme', 'dark');
```
### ❌ data-bs-theme="auto" в HTML
```html
<!-- НЕПРАВИЛЬНО: браузер применит auto ДО JS -->
<html data-bs-theme="auto">
<!-- ПРАВИЛЬНО: без атрибута, JS установит сразу -->
<html>
<head>
<script>/* устанавливаем тему */</script>
```
## Совместимость с кэшированием
### Статика кэшируется правильно
```
themeInitializer.js:
- Cache-Control: public, max-age=31536000
- Loaded: (disk cache)
bootstrap.css:
- Cache-Control: public, max-age=31536000
- Loaded: (disk cache)
```
### HTML кэшируется с правильным порядком
```
base.html:
- Cache-Control: private, max-age=60
- Loaded: (disk cache)
- Порядок скриптов сохранён!
```
**Результат**:
- ✅ Мгновенная загрузка из кэша
- ✅ Без мигания темы
- ✅ Идеальный UX!
## Резюме
| Проблема | Решение | Результат |
|----------|---------|-----------|
| Мигание белой темы | Синхронный скрипт в `<head>` | ✅ Нет FOUC |
| Медленная загрузка CSS | Preload критичных стилей | ✅ +100-300ms |
| "Стили не кэшируются" | Это было заблуждение | ✅ Всегда кэшировались |
| data-bs-theme="auto" | Убрали из HTML | ✅ JS устанавливает сразу |
**Главный вывод**: Проблема была НЕ в кэшировании, а в **порядке выполнения**! 🎯