diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7773828 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +dist/ \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..cabf75e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "root": true, + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"] +} diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml new file mode 100644 index 0000000..e6be61c --- /dev/null +++ b/.github/workflows/build_test.yml @@ -0,0 +1,45 @@ +name: Build & Test + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize] + +jobs: + build: + runs-on: ubuntu-latest + env: + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + WPT_MANIFEST: ${{ github.workspace }}/wpt/MANIFEST.json + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '16' + - uses: actions/setup-python@v3 + with: + python-version: '3.x' + - uses: actions/checkout@v3 + with: + repository: devknoll/wpt + path: wpt + ref: x-polyfill-all-tests + + - name: Build + run: | + npm install + npm run build:wpt + + - name: Setup WPT + run: | + cd wpt + pip install virtualenv + ./wpt make-hosts-file | sudo tee -a /etc/hosts + - name: Run Tests + run: | + npm run serve & + ./wpt/wpt manifest + ./wpt/wpt serve --inject-script=${{ github.workspace }}/dist/src/cqfill.modern.js & + npm test diff --git a/.gitignore b/.gitignore index 7ba7abe..db4c6d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -cqfill.js -cqfill.min.js -cqfill.iife.min.js +dist node_modules \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..7773828 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +dist/ \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..993c327 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "bracketSpacing": false, + "singleQuote": true, + "trailingComma": "es5", + "arrowParens": "avoid" +} diff --git a/README.md b/README.md index 07c98d0..469b283 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,125 @@ # Container Query Polyfill -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]. +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: -## Usage +- Discrete queries (`width: 300` and `min-width: 300px`) +- Range queries (`200px < width < 400px` and `width < 400px`) +- Container relative length units (`cqw`, `cqh`, `cqi`, `cqb`, `cqmin`, and `cqmax`) in properties and keyframes -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: +## Getting Started + +To use the polyfill, add this script tag to the head of your document: : ```js -const supportsContainerQueries = "container" in document.documentElement.style; -if (!supportsContainerQueries) { - import("container-query-polyfill"); -} + ``` -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 ` +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: + +```css +@supports not (container-type: inline-size) { + .container, + footer { + display: none; + } + + .loader { + display: flex; + } +} ``` -## Browser support +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. -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+. +> **Note** +> 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. -## Feature support & limitations +## Limitations -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. +- **CSS first**: The polyfill currently only supports ` +