Настройте наложение элементов управления окнами на строку заголовка вашего PWA.

Используйте область заголовка рядом с элементами управления окнами, чтобы PWA больше походило на приложение.

Если вы помните мою статью «Сделайте ваше PWA более похожим на приложение» , вы, возможно, помните, как я упоминал настройку строки заголовка вашего приложения как стратегию создания более похожего на приложение опыта. Вот пример того, как это может выглядеть в приложении macOS Podcasts.

Строка заголовка приложения «Подкасты» для macOS, показывающая кнопки управления мультимедиа и метаданные о воспроизводимом в данный момент подкасте.
Настраиваемая строка заголовка делает ваше PWA больше похожим на приложение для конкретной платформы.

Теперь у вас может возникнуть соблазн возразить, сказав, что «Подкасты» — это приложение для macOS, специфичное для платформы, которое не запускается в браузере и, следовательно, может делать все, что хочет, без необходимости играть по правилам браузера. Это правда, но хорошая новость заключается в том, что функция Window Controls Overlay, которая является темой этой самой статьи, вскоре позволит вам создавать аналогичные пользовательские интерфейсы для вашего PWA.

Компоненты наложения оконных элементов управления

Наложение элементов управления окном состоит из четырех подфункций:

  1. Значение "window-controls-overlay" для поля "display_override" в манифесте веб-приложения.
  2. Переменные среды CSS titlebar-area-x , titlebar-area-y , titlebar-area-width и titlebar-area-height .
  3. Стандартизация ранее проприетарного свойства CSS -webkit-app-region как свойства app-region для определения перетаскиваемых областей в веб-контенте.
  4. Механизм запроса и работы с областью элементов управления окнами через элемент windowControlsOverlay в window.navigator .

Что такое наложение элементов управления окнами

Область заголовка — это пространство слева или справа от элементов управления окном (то есть кнопок свертывания, развертывания, закрытия и т. д.) и часто содержит заголовок приложения. Наложение элементов управления окнами позволяет прогрессивным веб-приложениям (PWA) создавать ощущение, более похожее на приложение, заменяя существующую полноразмерную строку заголовка небольшим наложением, содержащим элементы управления окнами. Это позволяет разработчикам размещать пользовательский контент в том месте, где раньше находилась область заголовка, контролируемая браузером.

Текущее состояние

Шаг Положение дел
1. Создайте объяснитель Полный
2. Создайте первоначальный проект спецификации. Полный
3. Соберите отзывы и доработайте дизайн В ходе выполнения
4. Пробная версия происхождения Полный
5. Запуск Полный (в Chromium 104)

Как использовать наложение элементов управления окнами

window-controls-overlay в манифест веб-приложения

Прогрессивное веб-приложение может включить наложение элементов управления окнами, добавив "window-controls-overlay" в качестве основного элемента "display_override" в манифесте веб-приложения:

{
  "display_override": ["window-controls-overlay"]
}

Наложение элементов управления окном будет видно только при выполнении всех следующих условий:

  1. Приложение открывается не в браузере, а в отдельном окне PWA.
  2. Манифест включает "display_override": ["window-controls-overlay"] . (После этого допускаются другие значения.)
  3. PWA работает в операционной системе настольного компьютера.
  4. Текущий источник соответствует источнику, для которого был установлен PWA.

Результатом этого является пустая область заголовка с обычными элементами управления окна слева или справа, в зависимости от операционной системы.

Окно приложения с пустой строкой заголовка и элементами управления слева.
Пустая строка заголовка, готовая для пользовательского контента.

Перемещение контента в строку заголовка

Теперь, когда в строке заголовка есть место, вы можете что-то туда переместить. Для этой статьи я создал PWA избранного контента Wikimedia. Полезной функцией этого приложения может стать поиск слов в заголовках статей. HTML-код функции поиска выглядит следующим образом:

<div class="search">
  <img src="logo.svg" alt="Wikimedia logo." width="32" height="32" />
  <label>
    <input type="search" />
    Search for words in articles
  </label>
</div>

Чтобы переместить этот div вверх в строку заголовка, потребуется некоторый CSS:

.search {
  /* Make sure the `div` stays there, even when scrolling. */
  position: fixed;
  /**
   * Gradient, because why not. Endless opportunities.
   * The gradient ends in `#36c`, which happens to be the app's
   * `<meta name="theme-color" content="#36c">`.
   */
  background-image: linear-gradient(90deg, #36c, #131313, 33%, #36c);
  /* Use the environment variable for the left anchoring with a fallback. */
  left: env(titlebar-area-x, 0);
  /* Use the environment variable for the top anchoring with a fallback. */
  top: env(titlebar-area-y, 0);
  /* Use the environment variable for setting the width with a fallback. */
  width: env(titlebar-area-width, 100%);
  /* Use the environment variable for setting the height with a fallback. */
  height: env(titlebar-area-height, 33px);
}

Вы можете увидеть эффект этого кода на скриншоте ниже. Строка заголовка полностью адаптивна. Когда вы изменяете размер окна PWA, строка заголовка реагирует так, как если бы она состояла из обычного HTML-содержимого, что на самом деле и есть.

Окно приложения со строкой поиска в заголовке.
Новая строка заголовка активна и отзывчива.

Определение того, какие части строки заголовка можно перетаскивать

Хотя скриншот выше показывает, что вы закончили, вы еще не закончили. Окно PWA больше нельзя перетаскивать (за исключением очень маленькой области), поскольку кнопки управления окном не являются областями перетаскивания, а остальная часть строки заголовка состоит из виджета поиска. Исправьте это, используя CSS-свойство app-region со значением drag . В конкретном случае можно сделать все, кроме элемента input , перетаскиваемым.

/* The entire search `div` is draggable… */
.search {
  -webkit-app-region: drag;
  app-region: drag;
}

/* …except for the `input`. */
input {
  -webkit-app-region: no-drag;
  app-region: no-drag;
}

Имея этот CSS, пользователь может перетаскивать окно приложения, как обычно, перетаскивая div , img или label . Только элемент input является интерактивным, поэтому можно ввести поисковый запрос.

Обнаружение функций

Поддержку наложения элементов управления окнами можно обнаружить, проверив наличие windowControlsOverlay :

if ('windowControlsOverlay' in navigator) {
  // Window Controls Overlay is supported.
}

Запрос области элементов управления окнами с помощью windowControlsOverlay

В коде пока есть одна проблема: на некоторых платформах элементы управления окнами расположены справа, на других — слева. Что еще хуже, меню Chrome «три точки» также будет менять положение в зависимости от платформы. Это означает, что фоновое изображение с линейным градиентом необходимо динамически адаптировать для работы с #131313maroon или maroon#131313maroon , чтобы оно гармонировало с maroon цветом фона строки заголовка, который определяется <meta name="theme-color" content="maroon"> . Этого можно добиться, запросив API getTitlebarAreaRect() для свойства navigator.windowControlsOverlay .

if ('windowControlsOverlay' in navigator) {
  const { x } = navigator.windowControlsOverlay.getTitlebarAreaRect();
  // Window controls are on the right (like on Windows).
  // Chrome menu is left of the window controls.
  // [ windowControlsOverlay___________________ […] [_] [■] [X] ]
  if (x === 0) {
    div.classList.add('search-controls-right');
  }
  // Window controls are on the left (like on macOS).
  // Chrome menu is right of the window controls overlay.
  // [ [X] [_] [■] ___________________windowControlsOverlay [⋮] ]
  else {
    div.classList.add('search-controls-left');
  }
} else {
  // When running in a non-supporting browser tab.
  div.classList.add('search-controls-right');
}

Вместо того, чтобы напрямую включать фоновое изображение в правила CSS класса .search (как раньше), измененный код теперь использует два класса, которые код выше устанавливает динамически.

/* For macOS: */
.search-controls-left {
  background-image: linear-gradient(90deg, #36c, 45%, #131313, 90%, #36c);
}

/* For Windows: */
.search-controls-right {
  background-image: linear-gradient(90deg, #36c, #131313, 33%, #36c);
}

Определение того, видно ли наложение элементов управления окнами

Наложение элементов управления окном не будет видно в области строки заголовка ни при каких обстоятельствах. Хотя его, естественно, не будет в браузерах, которые не поддерживают функцию наложения элементов управления окнами, его также не будет, когда рассматриваемый PWA запускается на вкладке. Чтобы обнаружить эту ситуацию, вы можете запросить visible свойство windowControlsOverlay :

if (navigator.windowControlsOverlay.visible) {
  // The window controls overlay is visible in the title bar area.
}

Альтернативно вы также можете использовать медиа display-mode в JavaScript и/или CSS:

// Create the query list.
const mediaQueryList = window.matchMedia('(display-mode: window-controls-overlay)');

// Define a callback function for the event listener.
function handleDisplayModeChange(mql) {
  // React on display mode changes.
}

// Run the display mode change handler once.
handleDisplayChange(mediaQueryList);

// Add the callback function as a listener to the query list.
mediaQueryList.addEventListener('change', handleDisplayModeChange);
@media (display-mode: window-controls-overlay) { 
  /* React on display mode changes. */ 
}

Получение уведомлений об изменениях геометрии

Запроса области наложения элементов управления окна с помощью getTitlebarAreaRect() может быть достаточно для одноразовых задач, таких как установка правильного фонового изображения в зависимости от того, где находятся элементы управления окнами, но в других случаях необходим более детальный контроль. Например, возможным вариантом использования может быть адаптация наложения элементов управления окнами в зависимости от доступного пространства и добавление шутки прямо в наложение элементов управления окном, когда места достаточно.

Область наложения оконных элементов управления в узком окне с сокращенным текстом.
Элементы управления в строке заголовка адаптированы к узкому окну.

Вы можете получать уведомления об изменениях геометрии, подписавшись на navigator.windowControlsOverlay.ongeometrychange или настроив прослушиватель событий для события geometrychange . Это событие будет срабатывать только тогда, когда наложение элементов управления окном видимо, то есть когда navigator.windowControlsOverlay.visible имеет true .

const debounce = (func, wait) => {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};

if ('windowControlsOverlay' in navigator) {
  navigator.windowControlsOverlay.ongeometrychange = debounce((e) => {
    span.hidden = e.titlebarAreaRect.width < 800;
  }, 250);
}

Вместо назначения функции ongeometrychange вы также можете добавить прослушиватель событий в windowControlsOverlay , как показано ниже. Вы можете прочитать о разнице между ними на MDN .

navigator.windowControlsOverlay.addEventListener(
  'geometrychange',
  debounce((e) => {
    span.hidden = e.titlebarAreaRect.width < 800;
  }, 250),
);

Совместимость при работе во вкладке и в неподдерживающих браузерах.

Можно рассмотреть два возможных случая:

  • Случай, когда приложение запускается в браузере, который поддерживает наложение элементов управления окнами, но приложение используется на вкладке браузера.
  • Случай, когда приложение работает в браузере, который не поддерживает наложение элементов управления окнами.

В обоих случаях по умолчанию HTML, созданный для наложения элементов управления окном, будет отображаться встроенным, как обычный HTML-контент, а резервные значения переменных env() будут использоваться для позиционирования. В поддерживающих браузерах вы также можете решить не отображать HTML, предназначенный для наложения элементов управления окном, проверив свойствоvisible visible и, если оно сообщает false , скрыв это HTML-содержимое.

PWA, работающее на вкладке браузера, с наложением элементов управления окном, отображаемым в теле.
Элементы управления, предназначенные для строки заголовка, можно легко отобразить в теле в старых браузерах.

Напоминаем, что не поддерживающие браузеры либо вообще не учитывают свойство манифеста веб-приложения "display_override" , либо не распознают "window-controls-overlay" и, таким образом, используют следующее возможное значение в соответствии с резервной цепочкой, например: "standalone" .

PWA, работающее в автономном режиме, с наложением оконных элементов управления, отображаемым в теле.
Элементы управления, предназначенные для строки заголовка, можно легко отобразить в теле в старых браузерах.

Рекомендации по пользовательскому интерфейсу

Хотя это может показаться заманчивым, создавать классическое раскрывающееся меню в области «Наложение элементов управления окном» не рекомендуется. Это нарушит рекомендации по дизайну в macOS , платформе, на которой пользователи ожидают, что строки меню (как системные, так и пользовательские) будут располагаться в верхней части экрана.

Если ваше приложение обеспечивает полноэкранный режим, внимательно подумайте, имеет ли смысл делать наложение элементов управления окном частью полноэкранного режима. Потенциально вы можете изменить расположение макета при срабатывании события onfullscreenchange .

Демо

Я создал демо-версию , с которой вы можете играть в разных поддерживающих и не поддерживающих браузерах, а также в установленном и неустановленном состоянии. Чтобы воспользоваться функцией наложения элементов управления окнами, вам необходимо установить приложение. Ниже вы можете увидеть два скриншота того, чего ожидать. Исходный код приложения доступен на Glitch.

Демонстрационное приложение «Избранный контент Викимедиа» с наложением оконных элементов управления.
Демо-приложение доступно для экспериментов.

Функция поиска в наложении элементов управления окнами полностью функциональна:

Демо-приложение «Рекомендуемый контент Викимедиа» с наложением оконных элементов управления и активным поиском по слову «клеопа…» с выделением одной из статей с совпадающим термином «Клеопатра».
Функция поиска с использованием наложения элементов управления окнами.

Соображения безопасности

Команда Chromium разработала и реализовала API-интерфейс Window Controls Overlay, используя основные принципы, определенные в разделе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономику.

Подмена

Предоставление сайтам частичного контроля над строкой заголовка дает разработчикам возможность подделывать контент в том регионе, который ранее был доверенным и контролируемым браузером. В настоящее время в браузерах Chromium автономный режим включает строку заголовка, которая при первом запуске отображает заголовок веб-страницы слева и начало страницы справа (за которой следует кнопка «Настройки и многое другое» и элементы управления окном). . Через несколько секунд исходный текст исчезает. Если в браузере настроен язык с письмом справа налево (RTL), этот макет переворачивается так, что исходный текст находится слева. При этом откроется наложение элементов управления окна для подмены начала координат, если между началом координат и правым краем наложения недостаточно заполнения. Например, к источнику «evil.ltd» можно добавить доверенный сайт «google.com», что заставит пользователей поверить в то, что источник заслуживает доверия. Планируется сохранить исходный текст, чтобы пользователи знали происхождение приложения и могли убедиться, что оно соответствует их ожиданиям. Для браузеров с настройкой RTL справа от исходного текста должно быть достаточно полей, чтобы вредоносный веб-сайт не мог добавить небезопасный источник к доверенному источнику.

Отпечатки пальцев

Включение наложения элементов управления окнами и перетаскиваемых областей не вызывает серьезных проблем конфиденциальности, кроме обнаружения функций. Однако из-за разных размеров и расположения кнопок управления окнами в разных операционных системах navigator. windowControlsOverlay. getTitlebarAreaRect() Метод navigator. windowControlsOverlay. getTitlebarAreaRect() возвращает DOMRect , положение и размеры которого раскрывают информацию об операционной системе, в которой работает браузер. В настоящее время разработчики уже могут определять ОС по строке пользовательского агента, но из-за проблем с отпечатками пальцев ведется дискуссия о заморозке строки UA и унификации версий ОС. Сообщество браузеров постоянно пытается понять, как часто размер наложения оконных элементов управления меняется на разных платформах, поскольку в настоящее время предполагается, что они достаточно стабильны в разных версиях ОС и, следовательно, не будут полезны для наблюдения за второстепенными версиями ОС. Хотя это потенциальная проблема с отпечатками пальцев, она применима только к установленным PWA, которые используют функцию настраиваемой строки заголовка, и не относится к общему использованию браузера. Плюс navigator. windowControlsOverlay API navigator. windowControlsOverlay не будет доступен для iframe, встроенного в PWA.

Переход к другому источнику внутри PWA приведет к тому, что он вернется к обычной автономной строке заголовка, даже если он соответствует вышеуказанным критериям и запускается с наложением элементов управления окном. Это сделано для того, чтобы разместить черную полосу, которая появляется при переходе к другому источнику. После возврата к исходному источнику наложение элементов управления окном будет использоваться снова.

Черная строка URL-адреса для навигации вне исходного кода.
Черная полоса отображается, когда пользователь переходит к другому источнику.

Обратная связь

Команда Chromium хочет услышать о вашем опыте использования API наложения элементов управления окнами.

Расскажите нам о дизайне API

Что-то в API работает не так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности? Сообщите о проблеме спецификации в соответствующем репозитории GitHub или добавьте свои мысли к существующей проблеме.

Сообщить о проблеме с реализацией

Вы нашли ошибку в реализации Chromium? Или реализация отличается от спецификации? Сообщите об ошибке на сайте new.crbug.com . Обязательно включите как можно больше подробностей, простые инструкции по воспроизведению и введите UI>Browser>WebAppInstalls в поле «Компоненты» . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку API

Планируете ли вы использовать API наложения элементов управления окнами? Ваша публичная поддержка помогает команде Chromium расставлять приоритеты в функциях и показывает другим поставщикам браузеров, насколько важно их поддерживать.

Отправьте твит @ChromiumDev с хэштегом #WindowControlsOverlay и сообщите нам, где и как вы его используете.

Полезные ссылки

Благодарности

Наложение элементов управления окнами было реализовано и определено Амандой Бейкер из команды Microsoft Edge. Эту статью рецензировали Джо Медли и Кеннет Род Кристиансен . Изображение героя, созданное Зигмундом на Unsplash .