Modern Web Weekly #63
The modern web, tested and explained in plain English
CMA designates Apple as having Strategic Market Status
The Open Web Advocacy (OWA) reports that the UK’s Competition and Markets Authority (CMA) has officially designated Apple as having Strategic Market Status (SMS).
SMS means that Apple “has substantial and entrenched market power and a position of strategic significance”. It means that Apple’s iOS platform is so dominant and powerful that the CMA can impose a code of conduct on the company.
For example, Apple obliges other browsers on iOS to use the WebKit engine, which means that these browsers are technically nothing more than a skin around the WebKit engine that powers Safari.
Since this engine has limited support for web apps, all browsers on iOS have limited support, and since iOS is so dominant, the entire web platform is held back as a result.
The most important outcomes of this decision are that Apple can be compelled to:
allow third-party browsers on iOS to use their own engines.
provide equivalent access to functionality for browsers using their own browser engines.
let third-party browsers install and manage web apps using their own engines.
to remove barriers to web app adoption, such as implementing a web app equivalent to smart banners or install prompts in iOS Safari.
This is an important decision because while it’s technically already possible for browser vendors to build browsers with their own engines for iOS, the financial, technical, and contractual barriers that Apple has put in place remain insurmountable.
Read the full article on the OWA website.
Better tooltips with the interestfor attribute
In addition to the command and commandfor attributes, Chrome 142 now supports the interestfor attribute.
Just like command and commandfor, the interestfor attribute can be added to <button>, <a>, and <area>. While command specifies an action to invoke when the element is clicked, interestfor specifies an element that will be shown when the user expresses interest.
This can be done on desktop by focusing or hovering over the element with the interestfor attribute or long-pressing the element on touch devices.
Good examples are quick action menus, tooltips, and social networks, where, when you hover over a profile name, a card is shown with more information about that profile:
The syntax is the same as command and popovertarget; the value of interestfor is the id of the element that is shown:
<button interestfor=”hovercard”>Profile</button>
<div id="hovercard" popover="hint">...</div>When the button is hovered or focused on desktop or long-pressed on a touch device, the popover will be shown.
Mouse and keyboard delays
It’s important to be able to delay the showing and hiding of the element that is the target of interestfor. A user might just be moving the mouse over the page without pausing to show interest. It would be confusing if these elements were already shown when the user is just moving around.
The shown element should also not be hidden immediately when the source element is no longer hovered or focused. Often, a user will want to copy information from the shown element, and there is usually also some space between the source and target, which would mean that the user would not be able to do this.
The delays for showing and hiding the target element are specified with interest-delay-start and interest-delay-end:
[interestfor] {
/* delay before interest is shown */
interest-delay-start: 0.5s;
/* delay before interest is hidden */
interest-delay-end: 200ms;
}Styling the source and target elements
The source and target elements can be styled with the pseudo-elements :interest-source and :interest-target. The first will match the source element, and the second will match the target element when interest is shown.
This enables you to, for example, style a <button> when interest is shown and to distinguish popovers that are shown as a result of interestfor from those that are shown as a result of popoveraction:
/* targets the button when interest is shown */
:interest-source {
background-color: lightgreen;
}
/* targets the popover when interest is shown */
[popover]:interest-target {
background-color: orange;
}Events
The API also introduces the InterestEvent, which is dispatched on the element that is the target of interestfor. When interest is shown (the target element is displayed), the event is of type “interest” and when it’s hidden, the event is of type “loseinterest”. In both cases, the source property of the event points to the element that has the interestfor attribute:
const hovercard = document.querySelector(’#hovercard’);
hovercard.addEventListener(’interest’, e => {
console.log(’interest’, e);
});
hovercard.addEventListener(’loseinterest’, e => {
console.log(’loseinterest’, e);
});Check this codepen in Chrome 142+ for a demo.
When you hover, focus, or long-press the button, the tooltip will show. Clicking the button will open a modal and close the tooltip.
I noticed that when the modal is closed with the ESC button, the tooltip appears again, even when the button is no longer hovered or focused. I assume this is a bug.
Range syntax in style queries
Chrome 142 now also supports range syntax in @style queries. These queries are a special kind of @container query where you can style an element based on the computed style of the parent element.
Currently, @style queries only work with custom properties, and until now, you could only use comparison syntax:
@container style(--theme-color: #ff0000) {
/* CSS rules */
}In Chrome 142, you can now use range syntax:
@container style(--main-width > 24rem) {
/* CSS rules */
}
/* compare literal values */
@container style(1em < 20px) {
/* CSS rules */
}I used this to simplify my demo of a slider with changing background color that I explained in Modern Web Weekly #61.
This demo uses a custom CSS function (—-is-equal) to change the background color of the slider based on its actual value.
With the range syntax, I can now get rid of this custom function to make the CSS simpler. Check the new demo.
Chrome on Android edge-to-edge bug
Starting with version 135, Chrome on Android can now display web apps edge-to-edge, which means that the web app will take up the entire screen, including the status bar area at the top where certain phones have the camera notch. You can compare this feature to setting the apple-mobile-web-app-status-bar-style meta tag to “black-translucent” which enables PWAs on iOS to display content under the status bar:
<meta name=”apple-mobile-web-app-status-bar-style” content=”black-translucent”>When configured to use swipe gestures, Android will no longer show the button bar with three buttons to minimize or view open apps, but it will show the so-called “chin” which indicates you can swipe up to go to the app switcher:
Depending on your Android version, you can configure your device to use buttons or swipe gestures in the Navigation Bar option under the Display menu.
To make your PWA display edge-to-edge, you need to set display: “fullscreen” in manifest.json and include the viewport meta tag in <head> with viewport-fit=cover:
<meta name=”viewport” content=”width=device-width, initial-scale=1, viewport-fit=cover” />At the moment, content is not displayed under the status bar at the top of the screen and a bug has been filed. Of course, you will read it here when there is any update on this. In the meantime, you can find all the details on Chrome edge-to-edge on Android in this article by Bramus van Damme.
How to handle target=”_blank” in your PWA
While conducting an audit for a PWA of a client, I came across an interesting issue that I hadn’t run into before, but that’s probably more widespread than I realized.
When testing the installed PWA of this client, I noticed that certain pages in the app would open in the in-app browser on Android and iOS. I was surprised at first, but quickly realized that the cause was actually very simple: the links to the page had target=”_blank” so they open in a new tab in a browser and in the in-app browser in an installed PWA.
There are often perfectly valid reasons to open a page in a new tab in a web app. When a link is clicked that points to another web app, it’s often good to open it in a new tab so the user can interact with both web apps and doesn’t lose any context. When a link to another web app is clicked inside an installed PWA it will open in the in-app browser by default.
But sometimes it can also be desirable to open other pages of the web app itself in a new tab, for example, some detail page. But when the web app is installed it often doesn’t make sense anymore to open that page in a new tab and that was exactly the case for this client. The pages needed to open in a new tab in the regular web app but not in the installed PWA.
Luckily, this can easily be fixed with a bit of JavaScript.
You can use matchMedia to detect if the app’s display-mode matches a certain value. Assuming your PWA is installed with “display”: “standalone” in its manifest.json file, you can check if the app is installed like this:
// will return “true” if the app is installed
const standalone = matchMedia(’(display-mode: standalone)’).matches;You can then use the value of standalone and a click event handler to prevent links from opening in a new tab when the app is installed:
// determine if the app is installed
const standalone = matchMedia(’(display-mode: standalone)’).matches
// get all links with target=”_blank”
const links = document.querySelectorAll(’a[target=”_blank”]’);
links.forEach(link => {
// add event listeners
link.addEventListener(’click’, (e) => {
// if installed, prevent the default action which is
// opening the link in a new tab
if (standalone) {
e.preventDefault();
// set the url of the page to the href of the
// link so it opens in the same page
location.href = link.href;
}
});
});Another, perhaps more simple solution is to remove the target attribute of all links:
// determine if the app is installed
const standalone = matchMedia(’(display-mode: standalone)’).matches
// get all links with target=”_blank”
const links = document.querySelectorAll(’a[target=”_blank”]’);
// remove the “target” attribute
links.forEach(link => {
link.removeAttribute(’target’);
});PWA Audit: on your way to a great PWA
Do you already have a PWA but are you running into issues with performance, security, or functionality? Or are you not sure how to make your PWA better?
I can help you by running an audit of your PWA
I will evaluate it on more than 35 criteria and provide you with clear and actionableinstructions on how to improve it. No generic stuff that you can get anywhere but an in-depth quality checkup to get you on your way to a great PWA.
Some of the criteria I will evaluate it on are:
Installability
Cross-device and cross-platform compatibility
Offline support
Usability
Effective use of modern web APIs
Performance
Security
Your investment in the improvement of your PWA through the audit is $499 excluding VAT (where applicable).
If you want to request an audit or first would like to know more, you can
fill out the form or book a call with me.




