Как сделать страницу, которая будет отображаться по умолчанию при входе на сайт без интернета?

1,00
р.
Если отключить интернет и зайти на YouTube через Chrome, можно увидеть такую страницу (при условии, что ранее сайт хотя бы один раз загружался в этом браузере):

Попробовал через Mozilla, Opera – нет такого.
Как это работает?

Ответ
Для этой цели вам нужно использовать ServiceWorker. Также вам необходимо предоставлять ваш сайт по протоколу HTTPS – Service Worker требует это по соображениям безопасности.
Ниже привожу пример кода с комментариями, который ранее я написал для одного из проектов:
// наименование для нашего хранилища кэша const CACHE_NAME = 'app_serviceworker_v_1', // ссылки на кэшируемые файлы и страницы cacheUrls = [ '/ru', '/en', '/csstyle.css', '/jscript.js' ]
// период обновления кэша - минута const MAX_AGE = 60
self.addEventListener('install', (event) => { // задержим обработку события // если произойдёт ошибка, serviceWorker не установится event.waitUntil( // находим в глобальном хранилище Cache-объект с нашим именем // если такого не существует, то он будет создан caches.open(CACHE_NAME).then((cache) => { // загружаем в наш cache необходимые файлы return cache.addAll(cacheUrls) }) ) })
self.addEventListener('fetch', (event) => { event.respondWith( // ищем запрошенный ресурс среди закэшированных caches.match(event.request).then((cachedResponse) => { let lastModified, fetchRequest // если ресурс есть в кэше if (cachedResponse) { // получаем дату последнего обновления lastModified = new Date(cachedResponse.headers.get('last-modified')) // и если мы считаем ресурс устаревшим if (lastModified && (Date.now() - lastModified.getTime()) > MAX_AGE) { fetchRequest = event.request.clone() // создаём новый запрос return fetch(fetchRequest).then((response) => { const responseClone = response.clone() // при неудаче всегда можно выдать ресурс из кэша if (!response || response.status !== 200) { return cachedResponse } else { // обновляем кэш caches.open(CACHE_NAME).then((cache) => { cache.put(event.request, responseClone) }) // возвращаем свежий ресурс return response } }).catch(() => cachedResponse) } return cachedResponse } // запрашиваем из сети как обычно return fetch(event.request) }) ) })