CSS is about styling boxes. In fact, the whole web is made of boxes, from the browser viewport to elements on a page. But every once in a while a new feature comes along that makes us rethink our design approach.
Article Continues Below
Round displays, for example, make it fun to play with circular clip areas. Mobile screen notches and virtual keyboards offer challenges to best organize content that stays clear of them. And dual screen or foldable devices make us rethink how to best use available space in a number of different device postures.
These recent evolutions of the web platform made it both more challenging and more interesting to design products. They’re great opportunities for us to break out of our rectangular boxes.
I’d like to talk about a new feature similar to the above: the Window Controls Overlay for Progressive Web Apps (PWAs).
Progressive Web Apps are blurring the lines between apps and websites. They combine the best of both worlds. On one hand, they’re stable, linkable, searchable, and responsive just like websites. On the other hand, they provide additional powerful capabilities, work offline, and read files just like native apps.
As a design surface, PWAs are really interesting because they challenge us to think about what mixing web and device-native user interfaces can be. On desktop devices in particular, we have more than 40 years of history telling us what applications should look like, and it can be hard to break out of this mental model.
At the end of the day though, PWAs on desktop are constrained to the window they appear in: a rectangle with a title bar at the top.
Here’s what a typical desktop PWA app looks like:
Sure, as the author of a PWA, you get to choose the color of the title bar (using the Web Application Manifest theme_color property), but that’s about it.
What if we could think outside this box, and reclaim the real estate of the app’s entire window? Doing so would give us a chance to make our apps more beautiful and feel more integrated in the operating system.
This is exactly what the Window Controls Overlay offers. This new PWA functionality makes it possible to take advantage of the full surface area of the app, including where the title bar normally appears.
About the title bar and window controls#section2
Let’s start with an explanation of what the title bar and window controls are.
The title bar is the area displayed at the top of an app window, which usually contains the app’s name. Window controls are the affordances, or buttons, that make it possible to minimize, maximize, or close the app’s window, and are also displayed at the top.
Window Controls Overlay removes the physical constraint of the title bar and window controls areas. It frees up the full height of the app window, enabling the title bar and window control buttons to be overlaid on top of the application’s web content.
If you are reading this article on a desktop computer, take a quick look at other apps. Chances are they’re already doing something similar to this. In fact, the very web browser you are using to read this uses the top area to display tabs.
Spotify displays album artwork all the way to the top edge of the application window.
Microsoft Word uses the available title bar space to display the auto-save and search functionalities, and more.
The whole point of this feature is to allow you to make use of this space with your own content while providing a way to account for the window control buttons. And it enables you to offer this modified experience on a range of platforms while not adversely affecting the experience on browsers or devices that don’t support Window Controls Overlay. After all, PWAs are all about progressive enhancement, so this feature is a chance to enhance your app to use this extra space when it’s available.
Let’s use the feature#section3
For the rest of this article, we’ll be working on a demo app to learn more about using the feature.
The demo app is called 1DIV. It’s a simple CSS playground where users can create designs using CSS and a single HTML element.
The app has two pages. The first lists the existing CSS designs you’ve created:
The second page enables you to create and edit CSS designs:
Since I’ve added a simple web manifest and service worker, we can install the app as a PWA on desktop. Here is what it looks like on macOS:
And on Windows:
Our app is looking good, but the white title bar in the first page is wasted space. In the second page, it would be really nice if the design area went all the way to the top of the app window.
Let’s use the Window Controls Overlay feature to improve this.
Enabling Window Controls Overlay#section4
The feature is still experimental at the moment. To try it, you need to enable it in one of the supported browsers.
As of now, it has been implemented in Chromium, as a collaboration between Microsoft and Google. We can therefore use it in Chrome or Edge by going to the internal about://flags page, and enabling the Desktop PWA Window Controls Overlay flag.
Using Window Controls Overlay#section5
To use the feature, we need to add the following display_override member to our web app’s manifest file:
"name": "1DIV", "description": "1DIV is a mini CSS playground", "lang": "en-US", "start_url": "/", "theme_color": "#ffffff", "background_color": "#ffffff", "display_override": [ "window-controls-overlay" ], "icons": [ ... ]
On the surface, the feature is really simple to use. This manifest change is the only thing we need to make the title bar disappear and turn the window controls into an overlay.
Here is what the app looks like now:
The title bar is gone, which is what we wanted, but our logo, search field, and NEW button are partially covered by the window controls because now our layout starts at the top of the window.
It’s similar on Windows, with the difference that the close, maximize, and minimize buttons appear on the right side, grouped together with the PWA control buttons:
Using CSS to keep clear of the window controls#section6
Along with the feature, new CSS environment variables have been introduced:
You use these variables with the CSS env() function to position your content where the title bar would have been while ensuring it won’t overlap with the window controls. In our case, we’ll use two of the variables to position our header, which contains the logo, search bar, and NEW button.
header position: absolute; left: env(titlebar-area-x, 0); width: env(titlebar-area-width, 100%); height: var(--toolbar-height);
titlebar-area-x variable gives us the distance from the left of the viewport to where the title bar would appear, and
titlebar-area-width is its width. (Remember, this is not equivalent to the width of the entire viewport, just the title bar portion, which as noted earlier, doesn’t include the window controls.)
By doing this, we make sure our content remains fully visible. We’re also defining fallback values (the second parameter in the
env() function) for when the variables are not defined (such as on non-supporting browsers, or when the Windows Control Overlay feature is disabled).
Now our header adapts to its surroundings, and it doesn’t feel like the window control buttons have been added as an afterthought. The app looks a lot more like a native app.
Changing the window controls background color so it blends in#section7
Now let’s take a closer look at our second page: the CSS playground editor.
Not great. Our CSS demo area does go all the way to the top, which is what we wanted, but the way the window controls appear as white rectangles on top of it is quite jarring.
We can fix this by changing the app’s theme color. There are a couple of ways to define it:
- PWAs can define a theme color in the web app manifest file using the theme_color manifest member. This color is then used by the OS in different ways. On desktop platforms, it is used to provide a background color to the title bar and window controls.
- Websites can use the theme-color meta tag as well. It’s used by browsers to customize the color of the UI around the web page. For PWAs, this color can override the manifest
In our case, we can set the manifest
theme_color to white to provide the right default color for our app. The OS will read this color value when the app is installed and use it to make the window controls background color white. This color works great for our main page with the list of demos.
Here is the function we’ll use:
function themeWindow(bgColor) document.querySelector("meta[name=theme-color]").setAttribute('content', bgColor);
With this in place, we can imagine how using color and CSS transitions can produce a smooth change from the list page to the demo page, and enable the window control buttons to blend in with the rest of the app’s interface.
Dragging the window#section8
Now, getting rid of the title bar entirely does have an important accessibility consequence: it’s much more difficult to move the application window around.
The title bar provides a sizable area for users to click and drag, but by using the Window Controls Overlay feature, this area becomes limited to where the control buttons are, and users have to very precisely aim between these buttons to move the window.
Fortunately, this can be fixed using CSS with the
app-region property. This property is, for now, only supported in Chromium-based browsers and needs the
-webkit- vendor prefix.
To make any element of the app become a dragging target for the window, we can use the following:
It is also possible to explicitly make an element non-draggable:
These options can be useful for us. We can make the entire header a dragging target, but make the search field and NEW button within it non-draggable so they can still be used as normal.
However, because the editor page doesn’t display the header, users wouldn’t be able to drag the window while editing code. So let’s use a different approach. We’ll create another element before our header, also absolutely positioned, and dedicated to dragging the window.
<div class="drag"></div> <header>...</header>
.drag position: absolute; top: 0; width: 100%; height: env(titlebar-area-height, 0); -webkit-app-region: drag;
With the above code, we’re making the draggable area span the entire viewport width, and using the
titlebar-area-height variable to make it as tall as what the title bar would have been. This way, our draggable area is aligned with the window control buttons as shown below.
And, now, to make sure our search field and button remain usable:
header .search, header .new -webkit-app-region: no-drag;
With the above code, users can click and drag where the title bar used to be. It is an area that users expect to be able to use to move windows on desktop, and we’re not breaking this expectation, which is good.
Adapting to window resize#section9
It may be useful for an app to know both whether the window controls overlay is visible and when its size changes. In our case, if the user made the window very narrow, there wouldn’t be enough space for the search field, logo, and button to fit, so we’d want to push them down a bit.
The API provides three interesting things:
navigator.windowControlsOverlay.visiblelets us know whether the overlay is visible.
navigator.windowControlsOverlay.getBoundingClientRect()lets us know the position and size of the title bar area.
navigator.windowControlsOverlay.ongeometrychangelets us know when the size or visibility changes.
Let’s use this to be aware of the size of the title bar area and move the header down if it’s too narrow.
if (navigator.windowControlsOverlay) navigator.windowControlsOverlay.addEventListener('geometrychange', () => const width = navigator.windowControlsOverlay.getBoundingClientRect(); document.body.classList.toggle('narrow', width < 250); );
In the example above, we set the
narrow class on the
body of the app if the title bar area is narrower than 250px. We could do something similar with a media query, but using the
windowControlsOverlay API has two advantages for our use case:
- It’s only fired when the feature is supported and used; we don’t want to adapt the design otherwise.
- We get the size of the title bar area across operating systems, which is great because the size of the window controls is different on Mac and Windows. Using a media query wouldn’t make it possible for us to know exactly how much space remains.
.narrow header top: env(titlebar-area-height, 0); left: 0; width: 100%;
Using the above CSS code, we can move our header down to stay clear of the window control buttons when the window is too narrow, and move the thumbnails down accordingly.
Thirty pixels of exciting design opportunities#section10
Using the Window Controls Overlay feature, we were able to take our simple demo app and turn it into something that feels so much more integrated on desktop devices. Something that reaches out of the usual window constraints and provides a custom experience for its users.
In reality, this feature only gives us about 30 pixels of extra room and comes with challenges on how to deal with the window controls. And yet, this extra room and those challenges can be turned into exciting design opportunities.
More devices of all shapes and forms get invented all the time, and the web keeps on evolving to adapt to them. New features get added to the web platform to allow us, web authors, to integrate more and more deeply with those devices. From watches or foldable devices to desktop computers, we need to evolve our design approach for the web. Building for the web now lets us think outside the rectangular box.
So let’s embrace this. Let’s use the standard technologies already at our disposal, and experiment with new ideas to provide tailored experiences for all devices, all from a single codebase!
If you get a chance to try the Window Controls Overlay feature and have feedback about it, you can open issues on the spec’s repository. It’s still early in the development of this feature, and you can help make it even better. Or, you can take a look at the feature’s existing documentation, or this demo app and its source code.