CSS Foldable Display polyfill
This is a polyfill for the proposed CSS Foldable Display extensions.
Web developers targeting foldable devices want to be able to effectively lay out the content in a window that spans multiple displays. CSS Foldable Display
extensions provides a mean to do that using stylesheets.
The 'screen-spanning' CSS media feature
The screen-spanning
CSS media feature can be used to test whether the browser window is spanning across multiple diplays.
Syntax
The screen-spanning
media feature value can be one of the following keywords:
This value matches when the layout viewport is spanning a single fold (two screens) and the fold posture is vertical.
This value matches when the layout viewport is spanning a single fold (two screens) and the fold posture is horizontal.
This value describes the state of when the browser window is not in spanning mode.
Example
A map application that presents a map on one window segment and search results on another
@media (screen-spanning: single-fold-vertical) {
body {
flex-direction: row;
}
.map {
flex: 1 1 env(fold-left)
}
.locations-list {
flex: 1;
}
}
Device fold CSS environment variables
There are 4 pre-defined CSS environment variables, which can be used to calculate each screen segment size at both landscape and portrait orientations.
- fold-top
- fold-left
- fold-width
- fold-height
While the spanning media query guarantees there is only a single hinge and two screen segments, developers must not take a dependency that each screen segment is 50% of the viewport height or width, as that may not always be the case.
The values of these variables are CSS pixels, and are relative to the layout viewport (i.e. are in the client coordinates, as defined by CSSOM Views).
When evaluated while not in one of the spanning states, these values will be treated as if they don't exist, and use the fallback value as passed to the env()
function.
How to use the polyfill
This polyfill is packaged as a JavaScript module. It is available on NPM over here.
To install the polyfill just run:
npm install --save spanning-css-polyfill
Then you can include it in your project:
<script type="module" src="/path/to/modules/spanning-css-polyfill.js"></script>
or in your JavaScript source file
import "/path/to/modules/spanning-css-polyfill/spanning-css-polyfill.js";
and start using the new CSS features.
- That's it. See the
demo/
directory for examples.
In order to change the display configuration, you can use the polyfill together with an emulator or you can change the settings manually. The settings are stored across sessions.
Manually changing the display configuration
You can update values such as screenSpanning
, foldSize
and browserShellSize
by importing the FoldablesFeature
object. You can also subscribe to the 'change' event
to be notified whenever the 'screenSpanning'
media query feature or the environment variables change. That can happen due to window resizes or because the configuration values were changed programmatically.
import { FoldablesFeature } from '/path/to/modules/spanning-css-polyfill/spanning-css-polyfill.js';
const foldablesFeat = new FoldablesFeature;
foldablesFeat.onchange = () => console.log("change");
foldablesFeat.addEventListener('change', () => console.log("change"));
foldablesFeat.foldSize = 20;
Object.assign(foldablesFeat, { foldSize: 50, screenSpanning: "none"});
(function() { foldablesFeat.foldSize = 100; foldablesFeat = "single-fold-horizontal" })();
Special note on web components and lit-element
In order for the polyfill to work with web components and lit-element, a bit of extra work is needed. There are a couple of examples in the demo/
directory.
The polyfill provides two methods, one to register and one to observe and adjust to updates.
import { adjustCSS, observe } from "spanning-css-polyfill/spanning-css-polyfill.js";
In the constructor of your web component make sure to pre-process and make the CSS browser valid by calling the adjustCSS
method:
let sheet = shadowRoot.querySelector("style");
sheet.innerText = adjustCSS(sheet.innerText, "test-element");
Now to make sure the style is updated whenever the configuration changes you need to add in your component class:
connectedCallback() {
observe(this);
}
Please note that if connectedCallback() exists on the parent, don't forget to call super.connectedCallback()
.
For lit-element, a bit of extra work is needed if you're styling your element with the css
template literal (which is the recommended way).
import { html, css as litCSS, LitElement } from 'https://cdn.pika.dev/lit-element@^2.2.1';
import { adjustCSS, observe } from "spanning-css-polyfill/spanning-css-polyfill.js";
const css = (strings, ...values) => {
const string = adjustCSS(strings[0], "test-element");
return litCSS([string], ...values);
};
The observe
method is also needed (see above).
Special note for handling of stylesheets manually constructed from CSS rules
If you build your CSS style sheets in JavaScript, the polyfill can't automatically convert your style sheets. However you can do something like this:
import { adjustCSS, observe } from "spanning-css-polyfill/spanning-css-polyfill.js";
const css = sheets => {
const rule = adjustCSS(sheets[0]);
return rule ? rule : "* {}";
}
sheet.insertRule(css`@media (screen-spanning: single-fold-vertical) {
.div {
flex: 0 0 env(fold-left);
margin-right: env(fold-width);
background-color: steelblue;
}
}`, sheet.cssRules.length);
Documentation
Located here.
Demos
Head over here.
Test suite
There are unfortunately no web-platform-tests available yet.
Known issues
Check GitHub here.
Learn more
- Explainer - a document explaining how this feature was designed and how it fits together with other APIs.