Skip to content

Commit 9511677

Browse files
committed
Commit new version
1 parent faf2600 commit 9511677

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+21998
-4971
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/

.eslintrc.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"root": true,
3+
"env": {
4+
"browser": true,
5+
"es6": true,
6+
"node": true
7+
},
8+
"parser": "@typescript-eslint/parser",
9+
"plugins": ["@typescript-eslint"],
10+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
11+
}

.github/workflows/build_test.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Build & Test
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
types: [opened, synchronize]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
env:
13+
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
14+
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
15+
WPT_MANIFEST: ${{ github.workspace }}/wpt/MANIFEST.json
16+
steps:
17+
- uses: actions/checkout@v3
18+
- uses: actions/setup-node@v3
19+
with:
20+
node-version: '16'
21+
- uses: actions/setup-python@v3
22+
with:
23+
python-version: '3.x'
24+
- uses: actions/checkout@v3
25+
with:
26+
repository: devknoll/wpt
27+
path: wpt
28+
ref: x-polyfill-all-tests
29+
30+
- name: Build
31+
run: |
32+
npm install
33+
npm run build:wpt
34+
35+
- name: Setup WPT
36+
run: |
37+
cd wpt
38+
pip install virtualenv
39+
./wpt make-hosts-file | sudo tee -a /etc/hosts
40+
- name: Run Tests
41+
run: |
42+
npm run serve &
43+
./wpt/wpt manifest
44+
./wpt/wpt serve --inject-script=${{ github.workspace }}/dist/src/cqfill.modern.js &
45+
npm test

.gitignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
cqfill.js
2-
cqfill.min.js
3-
cqfill.iife.min.js
1+
dist
42
node_modules

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/

.prettierrc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"bracketSpacing": false,
3+
"singleQuote": true,
4+
"trailingComma": "es5",
5+
"arrowParens": "avoid"
6+
}

README.md

Lines changed: 95 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,120 @@
11
# Container Query Polyfill
2+
A small (9 kB compressed) polyfill for CSS Container Queries using [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) and [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) supporting the full [`@container`](https://drafts.csswg.org/css-contain-3/) query syntax:
23

3-
A tiny polyfill for [CSS Container Queries][mdn], weighing about 1.6kB brotli’d. It transpiles CSS code on the client-side and implements Container Query functionality using [ResizeObserver] and [MutationObserver].
4+
* Discrete queries (`width: 300` and `min-width: 300px`)
5+
* Range queries (`200px < width < 400px` and `width < 400px`)
6+
* Container relative length units (`cqw`, `cqh`, `cqi`, `cqb`, `cqmin`, and `cqmax`) in properties and keyframes
47

5-
## Usage
6-
7-
Ideally, the polyfill is only loaded if the browser doesn’t support Container Queries natively. In a modern setup with a bundler that uses ES modules, the following snippet should work:
8+
## Getting Started
9+
To use the polyfill, add this script tag to the head of your document: :
810

911
```js
10-
const supportsContainerQueries = "container" in document.documentElement.style;
11-
if (!supportsContainerQueries) {
12-
import("container-query-polyfill");
13-
}
12+
<script type="module">
13+
if (!("container" in document.documentElement.style)) {
14+
import("https://unpkg.com/container-query-polyfill/cqfill.modern.js");
15+
}
16+
</script>
1417
```
1518

16-
If you are in a legacy setup (or just want to prototype quickly), there’s also an IIFE version that you can include using a `<script>` tag:
19+
You may also wish to use a service to conditionally deliver the polyfill based on `User-Agent`, or self-host it on your own origin.
20+
21+
> **Note**
22+
> All browsers have support for container queries released or on their roadmap, so it's recommended that you avoid bundling the polyfill with your other code.
1723
18-
```html
19-
<script src="https://unpkg.com/container-query-polyfill/cqfill.iife.min.js"></script>
24+
For the best user experience, it's recommended that you initially only use the polyfill for content below-the-fold and use `@supports` queries to temporarily replace it with a loading indicator until the polyfill is ready to display it:
25+
26+
```css
27+
@supports not (container-type: inline-size) {
28+
.container, footer {
29+
display: none;
30+
}
31+
32+
.loader {
33+
display: flex;
34+
}
35+
}
2036
```
2137

22-
## Browser support
38+
You can view a more complete demo [here](https://codesandbox.io/s/smoosh-glitter-m2ub4w?file=/index.html). On sufficiently fast networks and devices, or devices that natively support Container Queries, this loading indicator will never be displayed.
2339

24-
The polyfill relies on [ResizeObserver], [MutationObserver] and [`:is()`][is selector]. Therefore, it should work in all modern browsers, specifically Chrome/Edge 88+, Firefox 78+ and Safari 14+.
40+
> **Note**
41+
> Keep in mind that this technique effectively trades off LCP for less jank during initial load, so you may see regressions in the former as a result, particularly on low end devices.
2542
26-
## Feature support & limitations
43+
## Limitations
2744

28-
My aim is to make the polyfill work correctly for the _majority_ of use-cases, but cut corners where possible to keep the polyfill simple(-ish), small and efficient. The limitations arising from these tradeoffs are listed below.
45+
* **CSS first**: The polyfill currently only supports `<style>` and `<link>` elements. Inline styles via the `style` attribute or CSSOM methods are not polyfilled. Likewise, JavaScript APIs like `CSSContainerRule` are not polyfilled, and APIs like `CSS.supports()` are not monkey-patched.
46+
* **Best effort**: Style changes that do not lead to observable DOM or layout mutations (e.g. `font-size` in a container without content) may not be detected, or may be detected a frame late on some browsers.
47+
* Currently, there is no support for Shadow DOM, or functions like `calc(...)` in container conditions. Your contribution would be welcome!
2948

30-
(These decisions _can_ be revisited if they pose a significant hurdle and there is a good way to implement them. Please open an issue!)
49+
## Supporting browsers without `:where()`
3150

32-
- Both the old CQ syntax as well as the new syntax are supported:
51+
The polyfill uses the CSS [`:where()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) pseudo-class to avoid changing the specificity of your rules. This pseudo-class is relatively new, however. To support older browsers, you will need to append the dummy `:not(container-query-polyfill)` pseudo-class to the originating element of every selector under a `@container` block:
52+
53+
<table>
54+
<tr>
55+
<td> Before </td> <td> After </td>
56+
</tr>
57+
<tr>
58+
<td>
3359

3460
```css
35-
/* These are all equivalent */
3661
@container (min-width: 200px) {
37-
/* ... */
38-
}
39-
@container (width >= 200px) {
40-
/* ... */
41-
}
42-
@container size(width >= 200px) {
43-
/* ... */
62+
#foo {
63+
/* ... */
64+
}
65+
66+
.bar {
67+
/* ... */
68+
}
69+
70+
#foo,
71+
.bar {
72+
/* ... */
73+
}
74+
75+
ul > li {
76+
/* ... */
77+
}
78+
79+
::before {
80+
/* ... */
81+
}
4482
}
4583
```
4684

47-
- Boolean operations (`and`, `or` and `not`) are supported.
48-
- The polyfill does _not_ support style queries (e.g. `@container style(--color: red)`), as there is no way to get notified of computed style changes.
49-
- The polyfill does _not_ support pseudo elements (::before & ::after), as they don’t have a real DOM handle and can't be observed with `ResizeObserver`.
50-
- Container Queries will not work when nested inside a Media Query. For now, the polyfill only supports top-level CQs.
51-
- Container Query thresholds can only be specified using pixels.
52-
- Due to the nature of CORS, the polyfill only attempts to handle same-origin and inline stylesheets. Cross-origin stylesheets are not processed, regardless of CORS headers.
53-
- CQs inside ShadowDOM are not supported yet.
54-
- Don’t do weird interspersed comments, okay? Like `@container /* here’s a comment! */ (min-width: 1px) { ... }`. Just don’t.
55-
56-
## Building & Testing
57-
58-
This project uses [esbuild] to bundle the project, which is automatically installed via npm. To build the polyfill, run:
59-
60-
```
61-
npm run build
62-
```
63-
64-
To run the tests, run
65-
66-
```
67-
npm run serve
85+
</td>
86+
<td>
87+
88+
```css
89+
@container (min-width: 200px) {
90+
#foo:not(.container-query-polyfill) {
91+
/* ... */
92+
}
93+
94+
.bar:not(.container-query-polyfill) {
95+
/* ... */
96+
}
97+
98+
#foo:not(.container-query-polyfill),
99+
.bar:not(.container-query-polyfill) {
100+
/* ... */
101+
}
102+
103+
ul > li:not(.container-query-polyfill) {
104+
/* ... */
105+
}
106+
107+
:not(.container-query-polyfill)::before {
108+
/* ... */
109+
}
110+
}
68111
```
112+
</td>
113+
</tr>
114+
</table>
69115

70-
and open your browser at `http://127.0.0.1:8081/tests`.
71-
72-
---
116+
This is to ensure the specificity of your rules never changes (e.g. while the polyfill is loading, or on browsers with native support for container queries). On browsers without `:where()` supports, rules without the dummy will be ignored.
73117

74-
License Apache-2.0
118+
## ResizeObserver Loop Errors
75119

76-
[mdn]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
77-
[resizeobserver]: https://caniuse.com/resizeobserver
78-
[mutationobserver]: https://caniuse.com/mutationobserver
79-
[esbuild]: https://esbuild.github.io/
80-
[is selector]: https://caniuse.com/css-matches-pseudo
120+
When using the polyfill, you may observe reports of errors like `ResizeObserver loop completed with undelivered notifications` or `ResizeObserver loop limit exceeded`. These are expected, and may safely be ignored.

0 commit comments

Comments
 (0)