Иногда странице мало того прямоугольника, который ей выделил браузер: видеоплеер хочет занять все видимое пространство устройства, игра на canvas просит максимум пикселей, презентация выглядит лучше без панели вкладок и адресной строки. Для таких случаев существует Fullscreen API — набор методов и событий, который умеет развернуть произвольный элемент на весь экран и аккуратно вернуть всё назад.
Разберём API по жизненному циклу: как войти в режим, как подстроить под него стили, как отследить смену состояния, как выйти и какие грабли лежат по дороге.
Где это реально пригождается
API не относится к самым популярным, и зря: у него есть пара ниш, где он закрывает задачу одной строкой.
- Кастомные видеоплееры, в которых нужна своя кнопка «на весь экран» рядом со своими элементами управления.
- Игры и интерактивные демо на <canvas> или <video> — чтобы сцена занимала максимум видимой области.
- Презентации и слайдшоу прямо в браузере, без выгрузки в PDF.
- Режим чтения для длинных лонгридов и редакторских превью.
- Киоск-режим и публичные информационные стенды на встроенном Chromium.
Запуск полноэкранного режима
Главный метод API — Element.requestFullscreen(). Он вызывается у того элемента, который должен растянуться на экран. Самый частый кейс — на весь документ:
const goFullscreen = () => {
document.documentElement.requestFullscreen();
};
document.querySelector('#go-fs').addEventListener('click', goFullscreen);
Но никто не заставляет брать корневой <html>. Если на странице есть видеоплеер или контейнер с игрой, в режим уходит именно он, а остальная вёрстка остаётся за кадром:
const player = document.querySelector('.player');
document.querySelector('#go-fs').addEventListener('click', () => {
player.requestFullscreen();
});
Два важных момента, которые в туториалах часто опускают.
Во-первых, requestFullscreen() возвращает Promise. Промис резолвится, когда переход в режим действительно состоялся, и отклоняется, если браузер отказался — например, метод вызвали не в ответ на пользовательское действие. Полезно ловить ошибку:
document.querySelector('.player')
.requestFullscreen()
.then(() => console.log('окей, мы в полном экране'))
.catch((err) => console.warn('браузер не пустил:', err.message));
Во-вторых, метод срабатывает только из обработчика реального user-gesture — клика, тапа, нажатия клавиши. Попытка дёрнуть его из setTimeout, ответа сервера или просто при загрузке страницы будет молча отклонена. Это защита от страниц, которые без спроса забирают весь экран.
Стили под полный экран: псевдокласс :fullscreen и медиа-запрос display-mode
Когда контент занимает 27″ вместо колонки в 800 px, шрифты внезапно кажутся маленькими, отступы — жидкими, а кнопки — неловкими. Под этот сценарий в браузере есть два инструмента: CSS-псевдокласс :fullscreen и медиа-запрос @media (display-mode: fullscreen). Их часто путают.
Псевдокласс :fullscreen точечный — он матчит только тот элемент, который в данный момент развёрнут на экран (и всех его предков). Это удобно, когда в режим уходит конкретный контейнер, а не вся страница:
.player:fullscreen {
background: #000;
padding: 0;
}
.player:fullscreen .controls {
font-size: 1.4rem;
}
Медиа-запрос display-mode: fullscreen работает шире. Он срабатывает, когда страница отображается в полноэкранном режиме целиком — неважно, через Fullscreen API, через PWA-манифест с "display": "fullscreen" или клавишей F11. Подходит для общих правок layout-а:
@media (display-mode: fullscreen) {
body {
background: #111;
color: #f4f4f4;
}
.site-header,
.site-footer {
display: none;
}
}
Правило простое: если в режим уходит конкретный блок — :fullscreen. Если плющится вся страница — display-mode: fullscreen.
Слежение за сменой режима
Часто нужно среагировать на сам факт переключения: перерисовать сцену в <canvas>, заменить иконку на кнопке, поменять плеер в стиле «на сцене». Для этого есть событие fullscreenchange — оно стреляет и при входе, и при выходе из режима:
document.addEventListener('fullscreenchange', () => {
if (document.fullscreenElement) {
console.log('вошли, активный элемент:', document.fullscreenElement);
} else {
console.log('вышли');
}
});
Свойство document.fullscreenElement возвращает тот самый элемент, который сейчас на экране, или null, если режим выключен. Это самый надёжный способ узнать текущее состояние — и в обработчиках событий, и в любой произвольной точке кода.
Когда что-то идёт не так — пользователь отказал в разрешении, элемент уже находится в полноэкране у соседней вкладки, родительский iframe не разрешает фуллскрин — стреляет fullscreenerror:
document.addEventListener('fullscreenerror', (event) => {
console.warn('не получилось:', event);
});
В старых туториалах для перерисовки canvas-сцены часто слушают window.resize. Это рабочий, но грубоватый способ: resize сработает на любое изменение размеров окна, включая обычный drag за угол. Точнее цеплять перерисовку именно за fullscreenchange, а ресайз окна обрабатывать отдельно, если он вообще влияет на сцену:
const stage = document.querySelector('#stage');
const ctx = stage.getContext('2d');
const redraw = () => {
stage.width = stage.clientWidth;
stage.height = stage.clientHeight;
// здесь — полный repaint сцены под новый размер
};
document.addEventListener('fullscreenchange', redraw);
Подробнее про работу с пользовательскими и системными событиями есть отдельный материал в кратком гиде по событиям объекта window.
Выход из режима
По умолчанию пользователь и так умеет выходить из полноэкрана клавишей Esc, и для большинства интерфейсов этого достаточно. Chrome дополнительно показывает плашку-подсказку при входе. Программно выход выглядит так:
if (document.fullscreenElement) {
document.exitFullscreen();
}
Важно: метод вызывается у document, а не у элемента, который раньше уходил в режим. Это симметрично спецификации: за состояние полноэкрана отвечает документ.
Метод тоже возвращает Promise, который резолвится, когда страница уже вернулась к нормальному виду. Удобно для последовательных сценариев:
await document.exitFullscreen();
showFinalScreen();
Toggle-кнопка и SVG-иконка
Реальный сценарий — одна кнопка, которая и заходит в режим, и выходит из него, и попутно меняет иконку. Слегка переписанная toggle-функция выглядит так:
const toggleFs = () => {
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
document.documentElement.requestFullscreen();
}
};
document.querySelector('#fs-toggle').addEventListener('click', toggleFs);
Иконку проще всего собрать из двух SVG-<path>: один рисует уголки «развернуть», другой — «свернуть». В разметке оба лежат рядом, видимостью управляем через CSS, а синхронизируем не с кликом, а с тем самым fullscreenchange — так состояние не разъедется, даже если пользователь вышел через Esc:
<button id="fs-toggle" type="button" aria-label="Развернуть на весь экран">
<svg width="28" height="28" viewBox="0 0 28 28">
<path class="ico-expand"
d="M3 9 V3 H9 M19 3 H25 V9 M25 19 V25 H19 M9 25 H3 V19"
fill="none" stroke="currentColor" stroke-width="2" />
<path class="ico-collapse"
d="M9 3 V9 H3 M19 9 H25 V3 M25 19 H19 V25 M3 19 H9 V25"
fill="none" stroke="currentColor" stroke-width="2" />
</svg>
</button>
#fs-toggle .ico-collapse { display: none; }
:root:fullscreen #fs-toggle .ico-expand { display: none; }
:root:fullscreen #fs-toggle .ico-collapse { display: block; }
Никакого JS-кода для смены иконки не нужно — :fullscreen решает всю задачу одним правилом. Если по какой-то причине проще управлять видимостью через JS, привязка должна идти именно к fullscreenchange, а не к клику.
Подводные камни
API простой, но у него хватает граничных условий, на которые имеет смысл взглянуть до того, как они вылезут на проде.
- User-gesture обязателен. requestFullscreen() вызывается только из обработчика click, touchend, keydown и тому подобных пользовательских событий. Любая отложенная попытка (таймер, ответ fetch, DOMContentLoaded) будет отбита.
- Iframe требует разрешения. Если страница встроена через <iframe>, родительский документ должен явно дать ей право: <iframe src="..." allow="fullscreen">. Без атрибута requestFullscreen() внутри iframe тихо завалится с fullscreenerror.
- Safari исторически жил с префиксом. До 16.4 в WebKit нужно было звать webkitRequestFullscreen() и слушать webkitfullscreenchange. Если у вашей аудитории много старых iPhone/Mac, имеет смысл написать тонкий полифилл, который проверяет наличие unprefixed-метода и подсовывает префиксный.
- Не всякий элемент пустят в режим. Браузер вправе отказать, если у элемента подозрительный tabindex, он не в DOM, или у вкладки уже есть другой fullscreen-владелец.
- HTTPS желателен. Часть мобильных браузеров требует secure context: в HTTP-страницах метод просто не сработает. Локально http://localhost считается безопасным, удалённый http:// — нет.
- Esc обрабатывается браузером. Перехватить keydown на Esc, чтобы помешать выходу, нельзя — событие в режиме фуллскрина зарезервировано.
В этих сценариях полезно ловить отказ через Promise.catch или fullscreenerror и показывать пользователю осмысленное сообщение.
Шпаргалка
Если выжать API до одного экрана памяти, получится так:
- element.requestFullscreen() — войти в режим, возвращает Promise.
- document.exitFullscreen() — выйти, тоже Promise.
- document.fullscreenElement — текущий элемент или null.
- fullscreenchange и fullscreenerror — события на document.
- CSS: :fullscreen для конкретного элемента, @media (display-mode: fullscreen) для всей страницы.
- Вызывать только в ответ на действие пользователя, в безопасном контексте, с разрешением для iframe.
Этого достаточно для типичных задач: видеоплеер, презентация, демо на canvas, чтение лонгрида без хедера. Всё, что сверху — уже про конкретный сценарий и его UX.
Комментарии (0)