├── .nvmrc
├── src
├── _data
│ ├── layout.yaml
│ ├── redirects.yaml
│ ├── github.yaml
│ ├── feed.yaml
│ ├── refs.yaml
│ └── status.yaml
├── rwd
│ ├── rwd.11tydata.yaml
│ ├── grids
│ │ ├── grids.11tydata.yaml
│ │ └── index.md
│ ├── interpolation
│ │ ├── interpolation.11tydata.yaml
│ │ └── index.md
│ ├── query
│ │ ├── query.11tydata.yaml
│ │ ├── index.md
│ │ ├── resources.md
│ │ ├── contain.md
│ │ ├── syntax.md
│ │ ├── switch.md
│ │ ├── switch-query.md
│ │ └── containers.md
│ ├── style
│ │ ├── style.11tydata.yaml
│ │ ├── index.md
│ │ └── style-cases.md
│ └── index.md
├── sass
│ ├── sass.11tydata.yaml
│ ├── color-spaces
│ │ ├── color-spaces.11tydata.yaml
│ │ ├── index.md
│ │ ├── proposal.11tydata.yaml
│ │ └── resources.md
│ └── index.md
├── logical
│ ├── logical.11tydata.yaml
│ ├── index.md
│ ├── research.md
│ └── properties.md
├── overflow
│ ├── overflow.11tydata.yaml
│ └── index.md
├── elsewhere
│ ├── elsewhere.11tydata.yaml
│ ├── index.md
│ └── 21-brooklyn.md
├── favicon.ico
├── layers
│ ├── layers.11tydata.yaml
│ ├── link-supports.md
│ ├── index.md
│ ├── resources.md
│ ├── link-layer.md
│ └── placement.md
├── feed.njk
├── scope
│ ├── scope.11tydata.yaml
│ ├── resources.md
│ ├── index.md
│ ├── prior-art.md
│ ├── parent-selector.md
│ ├── syntax.md
│ └── nesting.md
├── styles
│ ├── patterns
│ │ ├── _index.scss
│ │ ├── _base.scss
│ │ ├── _media.scss
│ │ ├── _alert.scss
│ │ ├── _buttons.scss
│ │ ├── _links.scss
│ │ ├── _colors.scss
│ │ ├── _layout.scss
│ │ └── _type.scss
│ └── style.scss
├── sasslike
│ ├── sasslike.11tydata.yaml
│ └── index.md
├── toggles
│ ├── index.md
│ └── toggles.11tydata.yaml
├── redirects.md
├── _layouts
│ ├── content.njk
│ ├── base.njk
│ └── feed.njk
├── _includes
│ ├── base
│ │ ├── footer.njk
│ │ ├── changes.njk
│ │ ├── nav.njk
│ │ ├── alerts.njk
│ │ ├── links.njk
│ │ ├── support.njk
│ │ └── list.macros.njk
│ ├── alert.njk
│ ├── utility.njk
│ └── embed.njk
├── 404.md
├── changelog
│ ├── detail.njk
│ └── index.njk
├── index.md
├── favicon.svg
└── resources.md
├── .gitignore
├── README.md
├── filters
├── time.js
├── get.js
└── type.js
├── package.json
└── .eleventy.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | 16.13
2 |
--------------------------------------------------------------------------------
/src/_data/layout.yaml:
--------------------------------------------------------------------------------
1 | content.njk
2 |
--------------------------------------------------------------------------------
/src/rwd/rwd.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: rwd
2 | tags: [rwd]
3 |
--------------------------------------------------------------------------------
/src/sass/sass.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: sass
2 | tags: [sass]
3 |
--------------------------------------------------------------------------------
/src/logical/logical.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: logical
2 | tags: [logical]
3 |
--------------------------------------------------------------------------------
/src/overflow/overflow.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: overflow
2 | tags: [overflow]
3 |
--------------------------------------------------------------------------------
/src/rwd/grids/grids.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: grids
2 | tags:
3 | - grids
4 |
--------------------------------------------------------------------------------
/src/elsewhere/elsewhere.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: elsewhere
2 | tags: [elsewhere]
3 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oddbird/css-sandbox/HEAD/src/favicon.ico
--------------------------------------------------------------------------------
/src/layers/layers.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: shipped
2 | parent: layers
3 | tags:
4 | - layers
5 |
--------------------------------------------------------------------------------
/src/_data/redirects.yaml:
--------------------------------------------------------------------------------
1 | - from: /layers/guide/
2 | to: https://css-tricks.com/css-cascade-layers/
3 |
--------------------------------------------------------------------------------
/src/rwd/interpolation/interpolation.11tydata.yaml:
--------------------------------------------------------------------------------
1 | parent: interpolation
2 | tags:
3 | - interpolation
4 |
--------------------------------------------------------------------------------
/src/feed.njk:
--------------------------------------------------------------------------------
1 | ---
2 | layout: feed.njk
3 | permalink: feed.xml
4 | eleventyExcludeFromCollections: true
5 | ---
6 |
--------------------------------------------------------------------------------
/src/rwd/query/query.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: shipped
2 | parent: container-queries
3 | tags:
4 | - container-queries
5 |
--------------------------------------------------------------------------------
/src/scope/scope.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: moved
2 | moved: >
3 | [the latest specification](https://www.w3.org/TR/css-cascade-6/)
4 | parent: scope
5 | tags:
6 | - scope
7 |
--------------------------------------------------------------------------------
/src/styles/patterns/_index.scss:
--------------------------------------------------------------------------------
1 | @use 'base';
2 | @use 'colors';
3 | @use 'links';
4 | @use 'buttons';
5 | @use 'type';
6 | @use 'layout';
7 | @use 'media';
8 | @use 'alert';
9 |
--------------------------------------------------------------------------------
/src/styles/style.scss:
--------------------------------------------------------------------------------
1 | @use '../../node_modules/cssremedy/css/remedy.css';
2 | @use '../../node_modules/prism-themes/themes/prism-a11y-dark.css';
3 |
4 | @use 'patterns';
5 |
--------------------------------------------------------------------------------
/src/rwd/style/style.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: moved
2 | moved: >
3 | [the published specification](https://www.w3.org/TR/css-contain-3/)
4 | parent: style-queries
5 | tags:
6 | - style-queries
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies installed by npm
2 | node_modules
3 |
4 | # build artefacts
5 | public
6 | css
7 |
8 | # secrets and errors
9 | .env
10 | .log
11 |
12 | # macOS related files
13 | .DS_Store
14 |
15 |
--------------------------------------------------------------------------------
/src/sasslike/sasslike.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: moved
2 | moved: >
3 | [the latest specification](https://www.w3.org/TR/css-mixins-1/)
4 | (currently only defines functions)
5 | parent: sasslike
6 | tags: [sasslike]
7 |
--------------------------------------------------------------------------------
/src/sass/color-spaces/color-spaces.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: moved
2 | moved: >
3 | [the Sass blog post](https://sass-lang.com/blog/wide-gamut-colors-in-sass/)
4 | parent: sass-color-spaces
5 | tags:
6 | - sass-color-spaces
7 |
--------------------------------------------------------------------------------
/src/_data/github.yaml:
--------------------------------------------------------------------------------
1 | repo: https://github.com/oddbird/css-sandbox/
2 | files: https://github.com/oddbird/css-sandbox/blob/main/
3 | history: https://github.com/oddbird/css-sandbox/commits/main/
4 | issues: https://github.com/oddbird/css-sandbox/issues
5 |
--------------------------------------------------------------------------------
/src/_data/feed.yaml:
--------------------------------------------------------------------------------
1 | title: OddBird CSS Notebook
2 | subtitle: Notes towards the future of CSS, from Miriam Suzanne & OddBird
3 | url: https://css.oddbird.net/
4 | feedUrl: https://css.oddbird.net/feed.xml
5 | author:
6 | name: OddBird
7 | email: birds@oddbird.net
8 |
--------------------------------------------------------------------------------
/src/toggles/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Declarative Toggles
3 | created: 2021-05-28
4 | index: toggles
5 | ---
6 |
7 | There are many use-cases
8 | that require "toggling" the state of one element
9 | by interacting with a different element.
10 | Many of these could be described
11 | in terms of _show/hide_ states specifically.
12 |
--------------------------------------------------------------------------------
/src/redirects.md:
--------------------------------------------------------------------------------
1 | ---
2 | eleventyExcludeFromCollections: true
3 | title: Redirecting
4 | pagination:
5 | data: redirects
6 | size: 1
7 | alias: redirect
8 | permalink: '{{ redirect.from }}'
9 | ---
10 |
11 | Redirecting you to
12 | [{{ redirect.to }}]({{ redirect.to }}).
13 | If you are not redirected shortly, follow the link.
14 |
--------------------------------------------------------------------------------
/src/_layouts/content.njk:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base.njk
3 | ---
4 |
5 | {% include "base/alerts.njk" %}
6 |
7 | {{ content | safe }}
8 |
9 | {% include "base/links.njk" %}
10 |
11 | {% set related = collections[index] | noSelf(page) if index else [] %}
12 | {% if related | length > 0 %}
13 | {% import "base/list.macros.njk" as list %}
14 |
15 |
Related Notes
16 | {{ list.all(related, collections) }}
17 | {% endif %}
18 |
--------------------------------------------------------------------------------
/src/_includes/base/footer.njk:
--------------------------------------------------------------------------------
1 |
2 | {% md %}
3 | Maintained by [OddBird](https://oddbird.net/) ([change log](/changelog/))
4 |
5 | Subscribe to the
6 | [newsletter](https://www.oddbird.net/oddnews/) or
7 | [RSS feed](/feed.xml)
8 | for updates.
9 |
10 | [Edit this page]({{ [github.files, page.inputPath] | join }}),
11 | [view page history]({{ [github.history, page.inputPath] | join }}),
12 | or
13 | [file an issue]({{ github.issues }})
14 | on GitHub.
15 | {% endmd %}
16 |
--------------------------------------------------------------------------------
/src/rwd/style/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Style Queries
3 | created: 2022-10-25
4 | index: style-queries
5 | links:
6 | spec: css-contain-3
7 | project: 18
8 | caniuse: css-container-queries-style
9 | tag: 787
10 | wpt: css-contain/container-queries?q=style
11 | ---
12 |
13 | Style queries are a subset of 'container queries',
14 | but rather than querying conditions of the _container size_,
15 | we can query the _computed value_
16 | of any CSS properties on the container.
17 |
--------------------------------------------------------------------------------
/src/_includes/base/changes.njk:
--------------------------------------------------------------------------------
1 | {% if changes and not (is_log) %}
2 |
3 | Change history for this page
4 | {% for change in changes %}
5 |
6 |
7 |
8 | {{ change.time | date('DATETIME_FULL') }}
9 | »
10 |
11 | {{ change.log | md | safe }}
12 |
13 | {% endfor %}
14 |
15 | {% endif %}
16 |
--------------------------------------------------------------------------------
/src/styles/patterns/_base.scss:
--------------------------------------------------------------------------------
1 | html {
2 | --system-fonts: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
3 | --body-fonts: Palatino,Palatino Linotype,Palatino LT STD,Book Antiqua,Georgia,serif;
4 | --code-fonts: monaco,Consolas,'Lucida Console',monospace;
5 |
6 | background-color: #f9f9f9;
7 | font-family: var(--body-fonts);
8 | font-size: 1.15em;
9 | font-size: calc(1em + 0.4vw);
10 | height: 100%;
11 | line-height: 1.4;
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/_includes/alert.njk:
--------------------------------------------------------------------------------
1 |
2 | {% macro note(description, label='Note', close=false) %}
3 |
4 | {{ label }}:
5 | {{ description | md | safe }}
6 |
7 | {% endmacro %}
8 |
9 | {% macro warn(description, label='Warning', close=false) %}
10 |
11 | {{ label }}:
12 | {{ description | md | safe }}
13 |
14 | {% endmacro %}
15 |
--------------------------------------------------------------------------------
/src/404.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Page Not Found (404)
3 | permalink: /404.html
4 | eleventyExcludeFromCollections: true
5 | ---
6 |
7 | **Sorry**!
8 | It seems like we sent you
9 | to the wrong page.
10 | Since this is a sandbox,
11 | things move around sometimes.
12 | Try the [home page](/),
13 | or one of these options?
14 |
15 | {% import "base/list.macros.njk" as list %}
16 |
17 | ## Explainers
18 |
19 | {{ list.all(collections.explainer, collections) }}
20 |
21 | ## More Topics
22 |
23 | {{ list.all(collections.index, collections) }}
24 |
--------------------------------------------------------------------------------
/src/changelog/detail.njk:
--------------------------------------------------------------------------------
1 | ---
2 | pagination:
3 | data: collections.changes
4 | size: 1
5 | alias: change
6 | permalink: '{{ change.url }}'
7 | eleventyComputed:
8 | title: 'Changes to _{{ change.post.data.title or "Needs Title" }}_ on {{ change.date | date("short") }}'
9 | eleventyExcludeFromCollections: true
10 | ---
11 |
12 |
13 | {{ change.log | md | safe }}
14 |
15 |
16 |
17 |
18 | {{ change.post.data.title or "Needs Title" }} »
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/_includes/base/nav.njk:
--------------------------------------------------------------------------------
1 |
2 | Home
3 |
4 | {% if parent and not (parent == index) %}
5 | {% set parentIndex = collections[parent] | getIndex(parent) %}
6 | /
7 |
8 | {{ parentIndex.data.title }}
9 |
10 | {% endif %}
11 |
12 |
13 |
14 | Light
15 | Dark
16 |
17 |
--------------------------------------------------------------------------------
/src/_includes/base/alerts.njk:
--------------------------------------------------------------------------------
1 | {% import "alert.njk" as alert %}
2 |
3 | {% if draft %}
4 | {{ alert.warn(
5 | 'This document is still under active development, and likely incomplete',
6 | 'Rough Draft'
7 | ) }}
8 | {% elif archive %}
9 | {% set details %}
10 | {{ status.archive[archive] or archive }}
11 | {% if moved %}See {{ moved }} for details.{% endif %}
12 | {% endset %}
13 |
14 | {{ alert.warn(
15 | details,
16 | 'Archived'
17 | ) }}
18 | {% endif %}
19 |
20 | {{ alert.note(note) if note else none }}
21 | {{ alert.warn(warn) if warn else none }}
22 |
--------------------------------------------------------------------------------
/src/elsewhere/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: External Ideas & Proposals
3 | created: 2021-10-05
4 | index: elsewhere
5 | ---
6 |
7 | Some old notes & proposals
8 | ([written in collaboration with Fantasai](/elsewhere/21-brooklyn/))
9 | are documented on the [CSSWG Wiki](https://wiki.csswg.org/ideas):
10 |
11 | - [Margin Collapse Controls](https://wiki.csswg.org/ideas/margin-collapsing)
12 | - [Timelines and Interpolation](https://wiki.csswg.org/ideas/timelines)
13 | - [Column and Row Gaps and Rules](https://wiki.csswg.org/ideas/gutter-styling)
14 | - [Logical (Flow-relative) Syntax](https://wiki.csswg.org/ideas/logical-syntax)
15 |
--------------------------------------------------------------------------------
/src/rwd/query/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Container Queries
3 | created: 2020-11-14
4 | index: container-queries
5 | links:
6 | spec: css-contain-3
7 | project: 18
8 | mdn: CSS_Container_Queries
9 | caniuse: css-container-queries
10 | tag: 592
11 | wpt: css-contain/container-queries
12 | ---
13 |
14 | While media queries provide a method
15 | to query aspects of the user agent or device environment
16 | that a document is being displayed in
17 | (such as viewport dimensions or user preferences),
18 | container queries allow testing aspects
19 | of elements within the document
20 | (such as box dimensions or computed styles).
21 |
--------------------------------------------------------------------------------
/src/sasslike/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2023-06-22
3 | title: Sass Features in CSS
4 | ---
5 |
6 | Over the last decade,
7 | several features have made the move
8 | from Sass (and other pre-processors) to CSS --
9 | most notably 'variables'
10 | (as custom properties),
11 | and now 'nesting'.
12 |
13 | Here we consider
14 | some of the other Sass structures,
15 | and what advantages we would see
16 | from moving them into CSS.
17 |
18 | As a useful reference-point,
19 | the HTTP Archive
20 | has done some
21 | [basic tracking of Sass usage](https://github.com/w3c/csswg-drafts/issues/5798)
22 | across sites that provide
23 | public Sass sourcemaps.
24 |
--------------------------------------------------------------------------------
/src/overflow/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2023-04-17
3 | title: CSS Overflow Extensions
4 | index: overflow
5 | ---
6 |
7 | Managing content 'overflow' effectively on the web
8 | requires a careful balance
9 | of semantics, presentation,
10 | and interactions.
11 | While existing scroll/snapping
12 | and disclosure widgets
13 | provide a partial solution,
14 | authors often have to cobble together
15 | tabs, carousels, and accordions
16 | from an incomplete set of tools.
17 |
18 | Rather than developing a proposal
19 | to handle one of these patterns,
20 | I'm interested in what tools are needed
21 | to make the existing patterns easier to build
22 | effectively and accessibly.
23 |
--------------------------------------------------------------------------------
/src/changelog/index.njk:
--------------------------------------------------------------------------------
1 | ---
2 | eleventyExcludeFromCollections: true
3 | title: Full Site Changelog
4 | created: 2021-10-20
5 | is_log: true
6 | ---
7 |
8 |
9 | {% for date, changes in collections.changes | groupby('date_group') %}
10 |
{{ date }}
11 |
12 | {% for change in changes %}
13 |
14 |
17 |
18 |
19 | {{ change.log | md | safe }}
20 |
21 |
22 |
23 |
24 | {% endfor %}
25 | {% endfor %}
26 |
27 |
--------------------------------------------------------------------------------
/src/styles/patterns/_media.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:math';
2 |
3 | figure {
4 | margin: 1.5em 0;
5 | }
6 |
7 | img {
8 | width: 100%;
9 | }
10 |
11 | [style*="--ratio"],
12 | [data-ratio] {
13 | > :first-child {
14 | width: 100%;
15 | }
16 |
17 | > img {
18 | height: auto;
19 | }
20 |
21 | @supports (--custom:property) {
22 | display: grid;
23 | grid-template: 'media' auto / 100%;
24 |
25 | &::before {
26 | content: "";
27 | display: block;
28 | grid-area: media;
29 | padding-bottom: calc(100% / var(--ratio));
30 | }
31 |
32 | > :first-child {
33 | grid-area: media;
34 | height: 100%;
35 | }
36 | }
37 | }
38 |
39 | [data-ratio] {
40 | --ratio: #{(math.div(16, 9))};
41 | }
42 |
--------------------------------------------------------------------------------
/src/rwd/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Responsive Components
3 | created: 2020-11-09
4 | index: rwd
5 | ---
6 |
7 | Currently `@media` queries give us a way to adjust a design
8 | based on device features, user-preferences, and viewport size.
9 | But modern web development relies heavily on modular
10 | "blocks" and "components"
11 | that can be moved around.
12 |
13 | Authors want a way to style these components
14 | based on more immediate context --
15 | like the width of a parent container --
16 | which might not match cleanly to viewport media.
17 |
18 | Grid and flexbox both provide some tools
19 | for managing available space,
20 | so in addition to "container query" solutions,
21 | I also want to think about if/where they can also be improved
22 | for responsive design.
23 |
--------------------------------------------------------------------------------
/src/_includes/base/links.njk:
--------------------------------------------------------------------------------
1 | {% if links %}
2 | Important Links
3 |
28 | {% endif %}
29 |
--------------------------------------------------------------------------------
/src/_data/refs.yaml:
--------------------------------------------------------------------------------
1 | draft:
2 | name: Editor's Draft
3 | url: https://drafts.csswg.org/%s/
4 | spec:
5 | name: Published Specification
6 | url: https://www.w3.org/TR/%s/
7 | mdn:
8 | name: MDN Documentation
9 | url: https://developer.mozilla.org/en-US/docs/Web/CSS/%s
10 | caniuse:
11 | name: CanIUse
12 | url: https://caniuse.com/%s
13 | issue:
14 | name: Github Issue
15 | url: https://github.com/w3c/csswg-drafts/issues/%s
16 | label:
17 | name: Github Issues
18 | url: https://github.com/w3c/csswg-drafts/labels/%s
19 | project:
20 | name: Github Project
21 | url: https://github.com/w3c/csswg-drafts/projects/%s
22 | tag:
23 | name: TAG Review
24 | url: https://github.com/w3ctag/design-reviews/issues/%s
25 | wpt:
26 | name: Web Platform Tests
27 | url: https://wpt.fyi/results/css/%s
28 |
--------------------------------------------------------------------------------
/src/styles/patterns/_alert.scss:
--------------------------------------------------------------------------------
1 | [data-alert] {
2 | --alert: var(--neutral);
3 | --alert-contrast: var(--bg);
4 | background: var(--callout);
5 | border: medium solid var(--alert);
6 | color: var(--text);
7 | display: grid;
8 | grid: 'title' auto 'content' auto / auto;
9 | font-family: var(--system-fonts);
10 | margin: 1em 0;
11 | }
12 |
13 | [data-alert] summary {
14 | background-color: var(--alert);
15 | color: var(--alert-contrast, inherit);
16 | font-size: max(16px, 0.5em);
17 | font-weight: bold;
18 | grid-area: title;
19 | padding: 0.25em 0.5em;
20 | }
21 |
22 | [data-alert] > div {
23 | font-size: max(16px, 0.8em);
24 | grid-area: content;
25 | padding: 0 0.5em;
26 | }
27 |
28 | [data-alert='warn'] {
29 | --alert: var(--mark);
30 | --alert-contrast: var(--text);
31 | }
32 |
--------------------------------------------------------------------------------
/src/scope/resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Scope Resources
3 | created: 2021-10-05
4 | tags:
5 | - resources
6 | ---
7 |
8 | ## Talks & Podcasts
9 |
10 | - [CSSWG Proposals](https://slides.oddbird.net/csswg/)
11 | - [Styling the Intrinsic Web](https://www.oddbird.net/talks/intrinsic-web/)
12 | ([slides](https://slides.oddbird.net/css-next/))
13 | - [Front End Nerdery](https://www.oddbird.net/2021/08/15/fe-nerdery-10/)
14 | - [Container Queries & The Future of CSS](https://www.oddbird.net/talks/responsive-components/)
15 | ([slides](https://slides.oddbird.net/css-next/))
16 | - [Syntax.fm](https://www.oddbird.net/2021/06/16/syntaxfm-362/)
17 | - [Word Wrap Show](https://www.oddbird.net/2021/05/17/word-wrap-11/)
18 | - [The F-Word](https://www.oddbird.net/2021/05/06/f-word-11/)
19 | - [Smashing Podcast](https://www.oddbird.net/2021/05/04/smashing-36/)
20 |
--------------------------------------------------------------------------------
/src/toggles/toggles.11tydata.yaml:
--------------------------------------------------------------------------------
1 | archive: abandoned
2 | parent: toggles
3 | tags:
4 | - toggles
5 | warn: |
6 | I'm convinced this doesn't belong in CSS:
7 |
8 | - The style part of the problem --
9 | responding to state --
10 | is conditional CSS
11 | that can be handled with
12 | [container style queries](https://www.w3.org/TR/css-conditional-5/#style-container).
13 | - The issue of creating toggles
14 | should be addressed
15 | in other parts of the platform
16 | with features like
17 | [invoker commands](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API).
18 |
19 | In retrospect,
20 | I'm afraid this exploration
21 | acted as a distraction
22 | from more viable solutions --
23 | while requiring extra effort from accessibility experts
24 | to document all the issues with our approach.
25 |
--------------------------------------------------------------------------------
/src/styles/patterns/_buttons.scss:
--------------------------------------------------------------------------------
1 | button {
2 | background: var(--bg);
3 | color: var(--text);
4 | cursor: pointer;
5 | border: 2px solid var(--neutral);
6 | border-radius: 0.25em;
7 | font: inherit;
8 | font-size: 0.75rem;
9 | font-style: italic;
10 | padding: 0.125em 0.5em;
11 |
12 | &:hover,
13 | &:focus {
14 | background: var(--action);
15 | border-color: var(--action);
16 | color: var(--bg);
17 | }
18 |
19 | &:active {
20 | background: var(--focus);
21 | border-color: var(--focus);
22 | }
23 | }
24 |
25 | [data-toggle] {
26 | display: flex;
27 |
28 | button {
29 | flex: auto;
30 | border-radius: 0;
31 | }
32 |
33 | button + button {
34 | margin-inline-start: -2px;
35 | }
36 | }
37 |
38 | [aria-pressed=true] {
39 | border-color: var(--action);
40 | position: relative;
41 | z-index: 2;
42 | }
43 |
--------------------------------------------------------------------------------
/src/_includes/base/support.njk:
--------------------------------------------------------------------------------
1 |
2 | {% md %}
3 | ## Help us improve CSS
4 |
5 | As an _Invited Expert_
6 | in the CSS Working Group,
7 | I'm one of few independent contributors
8 | not representing a major company.
9 | If you appreciate the work I'm doing,
10 | please consider supporting
11 | me directly through the
12 | [OddBird Open Source fund](https://opencollective.com/oddbird-open-source/).
13 |
14 | I'm currently working on…
15 |
16 | - [Logical shorthand properties](/logical/)
17 | (_read the [blog post](https://www.oddbird.net/2025/03/20/logical-shorthand/)_)
18 | - [CSS Mixins & Functions](/sasslike/mixins-functions/)
19 | (_prototypes available in Chrome Canary_)
20 | - Finalizing **the `@scope` rule**
21 | (_part of [Interop 2025](https://wpt.fyi/interop-2025)!_)
22 | - Continued improvements to **Cascade Layers** and **Container Queries**
23 | {% endmd %}
24 |
25 |
--------------------------------------------------------------------------------
/src/styles/patterns/_links.scss:
--------------------------------------------------------------------------------
1 | a {
2 | &:link,
3 | &:visited {
4 | color: var(--link, var(--action));
5 | }
6 |
7 | &:hover,
8 | &:focus,
9 | &:active {
10 | color: var(--focus);
11 | }
12 |
13 | &[href*='://']::after {
14 | font-family: var(--system-fonts);
15 | content: ' ↗';
16 | }
17 | }
18 |
19 | .header-anchor {
20 | &:link,
21 | &:visited {
22 | --link: var(--neutral);
23 | --scale: 0.75;
24 | --x: 0;
25 | display: inline-block;
26 | font-weight: normal;
27 | text-decoration: none;
28 | transition: transform 300ms ease-out;
29 | transform: scale(var(--scale)) translateX(var(--x));
30 |
31 | @media (min-width: 48em) {
32 | --scale: 0.6;
33 | --x: -25%;
34 | position: absolute;
35 | right: 100%;
36 | }
37 | }
38 |
39 | &:hover,
40 | &:focus,
41 | &:active {
42 | --scale: 0.8;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/_includes/utility.njk:
--------------------------------------------------------------------------------
1 | {% macro attr_if(
2 | attr,
3 | value=none
4 | ) %}
5 | {%- if (value and (value | string | lower == 'true')) or (value == '') -%}
6 | {{ attr }}
7 | {%- elif value -%}
8 | {{ attr }}="{{ value }}"
9 | {%- endif -%}
10 | {% endmacro %}
11 |
12 | {% macro show_attrs(
13 | attrs
14 | ) %}
15 | {%- for attr, value in attrs %} {{ attr_if(attr, value) }}{%- endfor -%}
16 | {% endmacro %}
17 |
18 | {% macro link_if(
19 | content,
20 | url=none,
21 | class=none,
22 | attrs={}
23 | ) -%}
24 | {%- set content = content if (content != none) else caller() -%}
25 | {%- if url -%}
26 | {{
27 | content | safe
28 | }}
29 | {%- else -%}
30 | {{
31 | content | safe
32 | }}
33 | {%- endif -%}
34 | {%- endmacro %}
35 |
--------------------------------------------------------------------------------
/src/sass/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sass Core Features
3 | created: 2021-12-06
4 | index: sass
5 | ---
6 |
7 | In addition to our work on CSS specifications,
8 | we're also working on new feature proposals and specs
9 | for the [Sass](https://sass-lang.com/) preprocessor.
10 |
11 | The priorities right now are:
12 |
13 | - Tools for managing new color syntax and multiple color-spaces
14 | - Try/catch syntax, for error handling
15 | - First-class css function calls
16 | - Expanding internal utilities (lists & strings etc)
17 | - URL handling & package management
18 |
19 | From a broader perspective,
20 | we believe that Sass can be a foundational tool
21 | for the future of design systems tooling --
22 | and there are many more features to consider along those lines.
23 | For example: importing & exporting JSON data,
24 | such as [design token files][].
25 |
26 | [design token files]: https://github.com/design-tokens/community-group
27 |
--------------------------------------------------------------------------------
/src/_data/status.yaml:
--------------------------------------------------------------------------------
1 | progress:
2 | draft:
3 | icon: 📝
4 | description: research stage, or unofficial draft proposal
5 | adopted:
6 | icon: 👍
7 | description: proceeding on a standards track
8 | specified:
9 | icon: 🚀
10 | description: implementation underway, beginning to ship
11 | implemented:
12 | icon: ✅
13 | description: implemented, shipped, and complete
14 | abandoned:
15 | icon: ❌
16 | description: rejected or abandoned
17 | archive:
18 | abandoned: >
19 | ❌
20 | This feature has been abandoned.
21 | Our notes are likely out-of-date.
22 | shipped: >
23 | ✅
24 | This feature has shipped in browsers.
25 | Our notes are likely out-of-date.
26 | moved: >
27 | 🚚
28 | This content
29 | is being maintained elsewhere.
30 | Our notes are likely out-of-date.
31 | inactive: >
32 | 🤷🏻♀️
33 | Not much active in here at the moment…
34 |
--------------------------------------------------------------------------------
/src/_includes/base/list.macros.njk:
--------------------------------------------------------------------------------
1 | {%- macro all(pages, collections) -%}
2 | {%- if pages | length > 0 -%}
3 |
4 | {%- for page in pages | byDate -%}
5 |
6 | {%- if page.data.draft -%}
7 | [draft]
8 | {%- elif page.data.progress -%}
9 | {% set progress = page.data.status.progress[page.data.progress] %}
10 | {{ progress.icon or page.data.progress }}
11 | {%- endif -%}
12 |
13 |
14 | {{- page.data.title -}}
15 |
16 |
17 | {%- set date = collections[page.data.index] | latest
18 | if page.data.index
19 | else page | getDate
20 | -%}
21 |
22 | – updated
23 | {{ date.toLocaleString('en-US', {'dateStyle': 'medium'}) }}
24 |
25 |
26 | {%- endfor -%}
27 |
28 | {%- endif -%}
29 | {%- endmacro -%}
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Miriam's CSS Sandbox
2 |
3 | This is a scratch site for
4 | [Miriam Suzanne](https://oddbird.net/authors/miriam/)
5 | to take notes & document ideas
6 | related to the
7 | [CSS Working Group](https://github.com/w3c/csswg-drafts/)
8 | and CSS Specifications.
9 |
10 | I like to work in the open,
11 | and make my notes available --
12 | you are welcome to explore,
13 | and even [open issues or pull-requests][gh] --
14 | but **this is my own personal notebook,
15 | and not a replacement for CSSWG issue threads**.
16 |
17 | ## Development Scripts
18 |
19 | This static site is built using
20 | [Eleventy](https://11ty.dev/),
21 | based on a [skeleton template](https://11ty.rocks/)
22 | developed by [@5t3ph](https://twitter.com/5t3ph).
23 |
24 | **`npm install`**
25 |
26 | > Install everything needed to build/start the static site
27 |
28 | **`npm start`**
29 |
30 | > Run 11ty with hot reload at localhost:8080, including reload based on Sass changes
31 |
32 | **`npm run build`**
33 |
34 | > Production build includes minified, autoprefixed CSS
35 |
--------------------------------------------------------------------------------
/src/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OddBird CSS Sandbox
3 | created: 2020-11-09
4 | ---
5 |
6 | This is a sandbox for
7 | [Miriam Suzanne](https://oddbird.net/authors/miriam/)
8 | and [OddBird](https://oddbird.net/)
9 | to document our notes
10 | related to
11 | [CSS Working Group](https://github.com/w3c/csswg-drafts/),
12 | [Sass language](https://sass-lang.com/),
13 | and related web platform features.
14 | Everything here is un-official and incomplete,
15 | as we do our thinking in public.
16 |
17 | [gh]: https://github.com/oddbird/css-sandbox
18 | [drafts]: https://github.com/w3c/csswg-drafts/issues
19 |
20 | [Links & Resources »](/resources/)
21 |
22 | {% import "base/list.macros.njk" as list %}
23 |
24 | ## Proposals & Explainers
25 |
26 | {{ list.all(collections.explainer, collections) }}
27 |
28 | {% note 'progress emoji' %}
29 | {% for name, stage in status.progress -%}
30 | - {{ stage.icon }} ({{ name }}): {{ stage.description }}
31 | {% endfor %}
32 | {% endnote %}
33 |
34 | ## Research Topics
35 |
36 | {{ list.all(collections.index, collections) }}
37 |
--------------------------------------------------------------------------------
/src/_includes/embed.njk:
--------------------------------------------------------------------------------
1 | {% import "utility.njk" as utility %}
2 |
3 | {% macro codepen(
4 | id,
5 | title,
6 | edit=true,
7 | user='miriamsuzanne',
8 | tab='result',
9 | height=500,
10 | theme='39098',
11 | preview=none,
12 | attrs=none
13 | ) %}
14 | {%- set base_attrs = {
15 | 'class': 'codepen',
16 | 'data-editable': edit,
17 | 'data-height': height,
18 | 'data-theme-id': theme,
19 | 'data-user': user,
20 | 'data-slug-hash': id,
21 | 'data-default-tab': tab,
22 | 'data-embed-version': "2",
23 | "data-preview": preview
24 | } -%}
25 | {%- set attrs = base_attrs | merge(attrs) if attrs else base_attrs -%}
26 | See the Pen {{ utility.link_if(
27 | content=title,
28 | url=('http://codepen.io/' + user + '/pen/' + id)
29 | ) }} by {{ utility.link_if(
30 | content='@' + user,
31 | url='http://codepen.io/' + user
32 | ) }} on {{ utility.link_if(
33 | content='CodePen',
34 | url='http://codepen.io'
35 | ) }}.
36 | {% endmacro %}
37 |
--------------------------------------------------------------------------------
/src/layers/link-supports.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Import Conditions in the HTML Link Tag
3 | progress: draft
4 | tags:
5 | - explainer
6 | draft: 2024-06-17
7 | archive: false
8 | ---
9 |
10 | ## Authors
11 |
12 | Miriam Suzanne
13 |
14 | ## Participate
15 |
16 | There are discussion threads
17 | on both the WHATWG and CSSWG
18 | github repos
19 | that relate to this proposal:
20 |
21 | - (WHATWG #7540)
22 | [Allow authors to apply new css features (like cascade layers) while linking stylesheets](https://github.com/whatwg/html/issues/7540)
23 | - (CSSWG #5853)
24 | [Provide an attribute for assigning a ` ` to a cascade layer](https://github.com/w3c/csswg-drafts/issues/5853)
25 |
26 | ## Introduction
27 |
28 |
29 |
30 | ## Goals
31 |
32 |
33 | ## Non-goals
34 |
35 |
36 | ## Proposed solution: the `conditions` attribute
37 |
38 |
39 | ## Key scenarios
40 |
41 |
42 | ## Detailed design discussion
43 |
44 | ### Similar attributes
45 |
46 | ### Support conditions
47 |
48 | ## Considered alternatives
49 |
50 |
51 |
52 | ## Stakeholder Feedback / Opposition
53 |
54 |
55 |
56 | ## References & acknowledgements
57 |
58 | Many thanks for valuable feedback and advice from:
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/layers/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Cascade Layers
3 | created: 2020-11-12
4 | index: layers
5 | links:
6 | spec: css-cascade-5
7 | project: 15
8 | mdn: '@layer'
9 | caniuse: css-cascade-layers
10 | tag: 597
11 | wpt: css-cascade/?q=layer
12 | changes:
13 | - time: 2021-09-16
14 | log: Article and tests for Cascade Layers
15 | - time: 2021-10-05T16:12:53-06:00
16 | log: Update Chrome feature flag
17 | ---
18 |
19 | While Cascade Origins help to balance styling concerns across stakeholders --
20 | layering browser defaults, user preferences, and document styles --
21 | it can be useful to have similar _layering of concerns_ within a single origin.
22 | Author styles often start with browser normalization or resets,
23 | then layer in default typography,
24 | broad patterns (sometimes from design systems or frameworks),
25 | and more specific component styles.
26 |
27 | Currently that layering has to be achieved with careful management of selector-specificity,
28 | or over-use of `!important` flags -- both resulting in unwanted side-effects.
29 | Cascade Layers would allow authors to define their own layering scheme
30 | and avoid specificity or source-order conflicts across concerns.
31 |
--------------------------------------------------------------------------------
/filters/time.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { DateTime } = require('luxon');
4 |
5 | const getDateObj = (date) => {
6 | if (!date) {
7 | return DateTime.now();
8 | }
9 |
10 | return typeof date === 'string'
11 | ? DateTime.fromISO(date, { zone: 'UTC' })
12 | : DateTime.fromJSDate(date, { zone: 'UTC' });
13 | };
14 |
15 | const date = (dateObj, format) => {
16 | const obj = getDateObj(dateObj);
17 |
18 | const formats = {
19 | short: DateTime.DATE_MED,
20 | long: DateTime.DATE_FULL,
21 | range: { month: 'long', year: 'numeric' },
22 | month: { month: 'long' },
23 | year: { year: 'numeric' },
24 | day: { day: 'numeric' },
25 | };
26 |
27 | const knownFormat = formats[format] || DateTime[format];
28 |
29 | if (format === 'rss') {
30 | return obj.toRFC2822();
31 | } else if (format === 'iso') {
32 | return obj.toISO();
33 | } else if (format && !knownFormat) {
34 | const custom = {
35 | url: "yyyy'/'MM'/'dd",
36 | 'no-month': "dd',' yyyy",
37 | };
38 | return obj.toFormat(custom[format] || format);
39 | }
40 |
41 | return obj.toLocaleString(knownFormat || DateTime.DATE_MED);
42 | };
43 |
44 | module.exports = {
45 | date,
46 | };
47 |
--------------------------------------------------------------------------------
/filters/get.js:
--------------------------------------------------------------------------------
1 | const getDate = (page) => page.data.changes
2 | ? page.data.changes.sort((a, b) => b.time - a.time).at(0).time
3 | : page.data.draft || page.data.created || page.date;
4 |
5 | const byDate = (collection) => collection
6 | .sort((a, b) => getDate(b) - getDate(a));
7 |
8 | const latest = (collection) => {
9 | return getDate(byDate(collection).at(0));
10 | };
11 |
12 | const noSelf = (collection, self) =>
13 | collection.filter((page) => page.url !== self.url);
14 |
15 | const getIndex = (collection, tag) =>
16 | collection.find((page) => page.data.index === tag);
17 |
18 | const getPage = (collection, page) =>
19 | collection.find((item) => item.url === page.url);
20 |
21 | module.exports = function (eleventyConfig) {
22 | eleventyConfig.addFilter('getDate', getDate);
23 | eleventyConfig.addFilter('byDate', byDate);
24 | eleventyConfig.addFilter('latest', latest);
25 | eleventyConfig.addFilter('noSelf', noSelf);
26 | eleventyConfig.addFilter('getIndex', getIndex);
27 | eleventyConfig.addFilter('getPage', getPage);
28 |
29 | eleventyConfig.addCollection("index", function(collectionApi) {
30 | const collect = collectionApi
31 | .getAll()
32 | .filter((page) => page.data.index);
33 |
34 | return byDate(collect);
35 | });
36 | };
37 |
--------------------------------------------------------------------------------
/src/scope/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Scope & Encapsulation
3 | created: 2020-11-10
4 | changes:
5 | - time: 2025-03-25T12:59:52-06:00
6 | log: >
7 | Scope is part of
8 | Interop 2025
9 | - time: 2021-09-11
10 | log: Scope spec draft moved to Cascade-6
11 | index: scope
12 | links:
13 | spec: css-cascade-6
14 | project: 21
15 | caniuse: css-cascade-scope
16 | tag: 593
17 | wpt: css-cascade?q=scope
18 | ---
19 |
20 | {% note 'progress' %}
21 | Scope is shipping
22 | as part of [Interop 2025](https://wpt.fyi/interop-2025).
23 | {% endnote %}
24 |
25 | Authors often complain that CSS is "globally scoped" --
26 | so that every selector is compared against every DOM element.
27 |
28 | There are several overlapping concerns here,
29 | based on a wide range of use-cases --
30 | and they can quickly become confused.
31 | That has lead to a wide array of proposals
32 | that are sometimes working towards different goals.
33 |
34 | Both shadow-DOM
35 | and the abandoned "scope" specification
36 | were focused around strong isolation.
37 | Shadow-DOM in particular creates persistent DOM-defined boundaries,
38 | that impact all style rules.
39 |
40 | Meanwhile,
41 | most of the user-land "scope" tools for CSS
42 | have a much lighter touch.
43 | I've been mainly interested in those low-isolation,
44 | namespacing problems.
45 |
--------------------------------------------------------------------------------
/src/sass/color-spaces/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sass Color Spaces
3 | created: 2021-12-06
4 | changes:
5 | - time: 2022-01-11T14:57:36-07:00
6 | log: More detail, with rough Sass suggestions
7 | - time: 2022-01-24T16:01:45-07:00
8 | log: Document css-color-4 functions and browser support
9 | index: sass-color-spaces
10 | parent: sass
11 | ---
12 |
13 | Historically
14 | CSS has been limited to a single color model (RGB)
15 | and gamut (`sRGB`).
16 | Authors have various formats to describe colors in that gamut --
17 | using cubic hex notation `#rgb`/`#rrggbb`/`#rrggbbaa`
18 | and functions `rgb()`/`rgba()`,
19 | or cylindrical/polar-angle functions `hsl()`/`hwb()`.
20 |
21 | Unfortunately, `sRGB` is a relatively narrow _color gamut_,
22 | and RGB isn't a _perceptually uniform_ model.
23 | Many monitors now support wider color gamuts
24 | (such as the popular `display-p3`),
25 | and there has also been significant progress
26 | in developing more perceptually uniform color spaces
27 | such as CIE `LAB`/`okLAB`.
28 |
29 | The CSS Colors level 4 specification
30 | describes how CSS authors can access these newer gamuts & formats --
31 | with `okLAB` as the default space for color-mixing.
32 | We want to provide support for this in Sass:
33 | with server-side tools to manage colors across spaces,
34 | and convert colors between spaces where appropriate.
35 |
--------------------------------------------------------------------------------
/src/layers/resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Cascade Layer Resources
3 | created: 2022-01-25T11:58:34-07:00
4 | tags:
5 | - resources
6 | ---
7 |
8 | - [OddBird Resources](https://www.oddbird.net/tags/cascade-layers/)
9 | - [A Complete Guide to Cascade Layers](https://css-tricks.com/css-cascade-layers/)
10 | - [Layers CodePen collection](https://codepen.io/collection/BNjmma)
11 |
12 | ## Talks & Podcasts
13 |
14 | - [CSSWG Proposals](https://slides.oddbird.net/csswg/)
15 | - [Styling the Intrinsic Web](https://www.oddbird.net/talks/intrinsic-web/)
16 | ([slides](https://slides.oddbird.net/css-next/))
17 | - [Front End Nerdery](https://www.oddbird.net/2021/08/15/fe-nerdery-10/)
18 | - [Container Queries & The Future of CSS](https://www.oddbird.net/talks/responsive-components/)
19 | ([slides](https://slides.oddbird.net/css-next/))
20 | - [Syntax.fm](https://www.oddbird.net/2021/06/16/syntaxfm-362/)
21 | - [Word Wrap Show](https://www.oddbird.net/2021/05/17/word-wrap-11/)
22 | - [The F-Word](https://www.oddbird.net/2021/05/06/f-word-11/)
23 | - [Smashing Podcast](https://www.oddbird.net/2021/05/04/smashing-36/)
24 |
25 | ## Articles & Demos
26 |
27 | - [The Future of CSS: Cascade Layers (CSS @layer)](https://www.bram.us/2021/09/15/the-future-of-css-cascade-layers-css-at-layer/)
28 | by **Bramus Van Damme**
29 | - [Getting Started With CSS Cascade Layers](https://www.smashingmagazine.com/2022/01/introduction-css-cascade-layers/)
30 | by **Stephanie Eckles**
31 |
--------------------------------------------------------------------------------
/src/styles/patterns/_colors.scss:
--------------------------------------------------------------------------------
1 | @use 'sass:color';
2 |
3 | @mixin light-mode {
4 | --bg: var(--contrast-light);
5 | --callout: var(--contrast-light-ish);
6 | --text: var(--contrast-dark);
7 | --neutral: var(--neutral-dark);
8 | --action: var(--prime-dark);
9 | --focus: var(--accent-dark);
10 | --mark: var(--accent-light);
11 | }
12 |
13 | @mixin dark-mode {
14 | --bg: var(--contrast-dark);
15 | --callout: var(--contrast-dark-ish);
16 | --text: var(--contrast-light);
17 | --neutral: var(--neutral-light);
18 | --action: var(--prime-light);
19 | --focus: var(--accent-light);
20 | --mark: var(--accent-dark);
21 | }
22 |
23 | html {
24 | color-scheme: var(--mode, var(--os-mode, light));
25 |
26 | // palette
27 | --contrast-light: snow;
28 | --contrast-light-ish: mistyrose;
29 | --contrast-dark: #{color.mix(darkslategray, black, 25%)};
30 | --contrast-dark-ish: #{color.mix(darkslategray, black, 50%)};
31 | --neutral-light: lightslategray;
32 | --neutral-dark: slategray;
33 | --prime-light: powderblue;
34 | --prime-dark: teal;
35 | --accent-light: hotpink;
36 | --accent-dark: #{color.mix(mediumvioletred, black, 75%)};
37 |
38 | @include light-mode;
39 |
40 | @media (prefers-color-scheme: dark) {
41 | @include dark-mode;
42 | --os-mode: dark;
43 | }
44 |
45 | background: var(--bg);
46 | color: var(--text);
47 | }
48 |
49 | [data-mode='light'] {
50 | @include light-mode;
51 | --mode: light;
52 | }
53 |
54 | [data-mode='dark'] {
55 | @include dark-mode;
56 | --mode: dark;
57 | }
58 |
--------------------------------------------------------------------------------
/filters/type.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const typogr = require('typogr');
4 | const ghSlug = require('github-slugger').slug;
5 |
6 | const mdown = require('markdown-it')({
7 | html: true,
8 | breaks: false,
9 | linkify: true,
10 | typographer: true,
11 | })
12 | .disable('code')
13 | .use(require('markdown-it-mark'))
14 | .use(require('markdown-it-footnote'))
15 | .use(require('markdown-it-anchor'), {
16 | slugify: ghSlug,
17 | permalink: true,
18 | });
19 |
20 | const amp = (s) => {
21 | const r = '& ';
22 | return s ? s.replace(/&/g, '&').replace(/&/g, r) : s;
23 | };
24 |
25 | const set = (content) => (content ? typogr.typogrify(content) : content);
26 | const render = (content, type = true) =>
27 | type ? set(mdown.render(content)) : mdown.render(content);
28 | const inline = (content, type = true) =>
29 | type ? set(mdown.renderInline(content)) : mdown.renderInline(content);
30 |
31 | const note = (content, label, close) => {
32 | return `
33 | ${label || 'Note'}:
34 | ${render(content.trim())}
35 | `;
36 | }
37 |
38 | const warn = (content, label, close) => {
39 | return `
40 | ${label || 'Warning'}:
41 | ${render(content.trim())}
42 | `;
43 | }
44 |
45 | module.exports = {
46 | mdown,
47 | amp,
48 | set,
49 | render,
50 | inline,
51 | warn,
52 | note,
53 | };
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "oddbird-css",
3 | "version": "1.1.0",
4 | "description": "A public scratch-pad for OddBird to work on CSS & Sass",
5 | "main": "index.html",
6 | "scripts": {
7 | "watch:sass": "sass --no-source-map --watch src/styles:public/css",
8 | "watch:eleventy": "eleventy --serve",
9 | "build:sass": "sass --no-source-map src/styles:public/css",
10 | "build:eleventy": "eleventy",
11 | "postbuild": "postcss public/css/*.css -u autoprefixer cssnano -r",
12 | "start": "npm-run-all build:sass --parallel watch:*",
13 | "build": "npm-run-all build:sass build:eleventy"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/oddbird/css-sandbox"
18 | },
19 | "author": "OddBird",
20 | "license": "ISC",
21 | "dependencies": {
22 | "autoprefixer": "^10.4.2",
23 | "cross-env": "^7.0.2",
24 | "cssnano": "^5.0.12",
25 | "cssremedy": "0.1.0-beta.2",
26 | "eleventy-plugin-toc": "^1.1.0",
27 | "github-slugger": "^1.3.0",
28 | "js-yaml": "^3.14.0",
29 | "markdown-it": "^12.0.2",
30 | "markdown-it-anchor": "^6.0.0",
31 | "markdown-it-footnote": "^3.0.2",
32 | "markdown-it-mark": "^3.0.0",
33 | "npm-run-all": "^4.1.5",
34 | "postcss-cli": "^8.1.0",
35 | "prism-themes": "^1.5.0"
36 | },
37 | "browserslist": [
38 | "last 2 versions"
39 | ],
40 | "devDependencies": {
41 | "@11ty/eleventy": "^2.0.0-beta.2",
42 | "@11ty/eleventy-navigation": "^0.3.2",
43 | "@11ty/eleventy-plugin-rss": "^1.1.2",
44 | "@11ty/eleventy-plugin-syntaxhighlight": "^4.0.0",
45 | "lodash": "^4.17.21",
46 | "luxon": "^3.2.1",
47 | "sass": "^1.50.1",
48 | "typogr": "^0.6.8"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: W3C & Browser Resources
3 | created: 2022-03-04
4 | tags:
5 | - resources
6 | ---
7 |
8 | ## Github Repos
9 |
10 | - [CSS Working Group](https://github.com/w3c/csswg-drafts/)
11 | - [W3C TAG Review](https://github.com/w3ctag/design-reviews/)
12 | - [WHATWG HTML Spec](https://github.com/whatwg/html/)
13 | - [Open UI](https://github.com/openui/open-ui/)
14 | - [Sass Language](https://github.com/sass/sass/)
15 |
16 | ## Web Platform Tests
17 |
18 | - [wpt info](https://wpt.fyi/)
19 | (includes yearly interop)
20 | - [live tests](https://wpt.live/)
21 |
22 | ## Browser Issues / Status
23 |
24 | Gecko:
25 | - [Firefox core issues](https://bugzilla.mozilla.org/buglist.cgi?product=Core&bug_status=__open__&list_id=16012662)
26 | - [Firefox experimental features](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Experimental_features)
27 | - [Firefox release notes](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases)
28 | - [Firefox release calendar](https://wiki.mozilla.org/Release_Management/Calendar)
29 | - [Mozilla standards positions](https://mozilla.github.io/standards-positions/)
30 |
31 | WebKit:
32 | - [WebKit CSS issues](https://bugs.webkit.org/buglist.cgi?bug_status=__open__&component=CSS&list_id=7970035&product=WebKit)
33 | - [WebKit release notes](https://webkit.org/blog/)
34 | - [Safari release notes](https://developer.apple.com/documentation/safari-release-notes)
35 | - [Safari standards positions](https://webkit.org/standards-positions/)
36 |
37 | Chromium/Blink:
38 | - [Blink CSS issues](https://bugs.chromium.org/p/chromium/issues/list?q=component:Blink%3ECSS)
39 | - [Chromium release notes](https://blog.chromium.org/)
40 | - [Chrome platform status](https://chromestatus.com/features)
41 | - [Chrome release schedule](https://chromiumdash.appspot.com/schedule)
42 | - [Chrome release notes](https://developer.chrome.com/)
43 | - [Edge release notes](https://docs.microsoft.com/en-us/deployedge/microsoft-edge-relnote-stable-channel)
44 |
--------------------------------------------------------------------------------
/src/styles/patterns/_layout.scss:
--------------------------------------------------------------------------------
1 | body {
2 | display: grid;
3 | grid-gap: 1em;
4 | grid-template:
5 | '. nav .' auto
6 | '. control .' auto
7 | '. header .' auto
8 | '. main .' 1fr
9 | / minmax(0, 1fr) minmax(0, 40em) minmax(0, 1fr)
10 | ;
11 | max-width: 100%;
12 | min-height: 100%;
13 | padding-block-start: 1em;
14 |
15 | @media (min-width: 50em) {
16 | --controls: end;
17 | grid-template:
18 | '. nav control' auto
19 | '. header .' auto
20 | '. main .' 1fr
21 | / minmax(auto, 1fr) minmax(0, 40em) minmax(auto, 1fr)
22 | ;
23 | }
24 |
25 | > * { grid-column: main; }
26 | }
27 |
28 | header,
29 | [id='toc-details'],
30 | footer {
31 | font-size: 0.8rem;
32 | }
33 |
34 | // header
35 | nav {
36 | grid-area: nav;
37 | }
38 |
39 | .controls {
40 | justify-self: var(--controls, start);
41 | grid-area: control;
42 | padding-right: 1em;
43 | }
44 |
45 | header {
46 | grid-area: header;
47 |
48 | [datetime] {
49 | display: block;
50 | font-style: italic;
51 | margin-top: 0.5rem;
52 | }
53 | }
54 |
55 | // toc
56 | #toc-details {
57 | margin-top: 0.5rem;
58 | }
59 |
60 | .toc-summary {
61 | font-style: italic;
62 | }
63 |
64 | // main
65 | main {
66 | grid-area: main;
67 | }
68 |
69 | // support
70 | #support {
71 | background-color: light-dark(white, black);
72 | border-block: thin solid var(--neutral);
73 | display: grid;
74 | grid-column: 1 / -1;
75 | grid-template-columns: inherit;
76 | padding-block: 2em;
77 |
78 | > h2 {
79 | border: unset;
80 | margin: unset;
81 | }
82 |
83 | > * { grid-column: 2; }
84 | + footer { border: unset; }
85 | }
86 |
87 | // footer
88 | footer {
89 | border-top: medium solid var(--neutral);
90 | padding: 1em;
91 |
92 | @media (min-width: 50em) {
93 | margin-inline: -1em;
94 | }
95 |
96 | p {
97 | margin-block: 0.25rem;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/styles/patterns/_type.scss:
--------------------------------------------------------------------------------
1 | :focus-visible {
2 | outline-offset: 0.25em;
3 | }
4 |
5 | time {
6 | font-style: italic;
7 | }
8 |
9 | // headings
10 |
11 | h1 {
12 | margin: 0.5em 0 0;
13 | }
14 |
15 | h1, h2, h3, h4, h5, h6 {
16 | font-family: var(--system-fonts);
17 | line-height: 1.2;
18 | position: relative;
19 | }
20 |
21 | h2 {
22 | border-top: medium dotted var(--neutral);
23 | margin: 2em 0 1em;
24 | padding-top: 0.25rem;
25 | }
26 |
27 | h3, h4 {
28 | margin: 1.5em 0 0.5em;
29 | }
30 |
31 | // lists
32 | :is(ol, ul) {
33 | &,
34 | & &,
35 | [data-alert] & {
36 | padding-left: 1.5em;
37 | }
38 |
39 | @media (min-width: 50em) {
40 | padding-left: 0;
41 | }
42 | }
43 |
44 | // quotes
45 |
46 | blockquote {
47 | border-inline-start: 0.5em solid var(--mark);
48 | font-style: italic;
49 | margin-inline: 0;
50 | padding-inline: 0.5em;
51 |
52 | @media (min-width: 50em) {
53 | margin-inline: -1.5em;
54 | padding-inline: 1em;
55 | }
56 |
57 | em, i {
58 | font-style: normal;
59 | }
60 | }
61 |
62 | // markers & code
63 |
64 | code,
65 | mark {
66 | background: var(--mark);
67 | color: var(--text);
68 | display: inline-block;
69 | padding: 0 0.25em;
70 | }
71 |
72 | code {
73 | background: var(--callout);
74 | font-family: var(--code-fonts);
75 | font-size: 0.8em;
76 |
77 | pre:not([class*="language-"]) & {
78 | display: block;
79 | padding: 1em;
80 | }
81 | }
82 |
83 | pre[class*="language-"] {
84 | @media (min-width: 50em) {
85 | margin-inline: -1em;
86 | }
87 |
88 | code {
89 | background: unset;
90 | color: unset;
91 | display: unset;
92 | padding: unset;
93 | }
94 | }
95 |
96 | // amp
97 |
98 | .amp {
99 | font-family: Garamond,Baskerville,Baskerville Old Face,Hoefler Text,Times New Roman,serif;
100 | font-style: italic;
101 | font-weight: normal;
102 | }
103 |
104 | // summary
105 | summary {
106 | cursor: pointer;
107 | }
108 |
109 | // tables
110 | table {
111 | border-collapse: collapse;
112 | display: block;
113 | max-width: 100%;
114 | width: max-content;
115 | overflow: auto;
116 | }
117 |
118 | td, th {
119 | border: thin solid var(--neutral);
120 | padding: 0 0.5em;
121 | text-align: left;
122 | }
123 |
--------------------------------------------------------------------------------
/src/logical/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Logical Shorthands
3 | created: 2025-03-25
4 | index: logical
5 | ---
6 |
7 | The CSS Working Group recently resolved
8 | to add a `size` shorthand
9 | for setting both the `width` and `height` of an element.
10 | Many people asked about using it to set the ‘logical’
11 | `inline-size` and `block-size` properties instead.
12 | But ‘logical shorthands’ have been
13 | stalled in the working group for years.
14 | _Can we get them unstuck?_
15 |
16 | [You can support our efforts](https://opencollective.com/oddbird-open-source/contribute/css-logical-shorthands-86141)
17 |
18 | ## Next steps
19 |
20 | 1. Research what properties would be impacted
21 | 2. Choose syntax for individual properties
22 | 3. Develop lexical toggle to allow default-logical styles
23 |
24 | ## CSS Working Group discussion
25 |
26 | - Specification: [CSS Logical Properties](https://www.w3.org/TR/css-logical/)
27 |
28 | Fantasai opened the original issue in 2017,
29 | when publishing the [First Public Working Draft](https://www.w3.org/TR/2017/WD-css-logical-1-20170518/)
30 | of CSS Logical Properties:
31 | [[css-logical] Flow-relative syntax for margin-like shorthands](https://github.com/w3c/csswg-drafts/issues/1282#issue-223656679).
32 | Here are some key comments:
33 |
34 | - [2021 proposed solution](https://github.com/w3c/csswg-drafts/issues/1282#issuecomment-952428897)
35 | by [Fantasai & Miriam & Jen Simmons](https://css.oddbird.net/elsewhere/21-brooklyn/)
36 | - [2022 TPAC discussion](https://github.com/w3c/csswg-drafts/issues/1282#issuecomment-1249685175)
37 | with [Internationalization Working Group](https://www.w3.org/groups/wg/i18n-core/) (I18n) --
38 | [Tab summarizes the decision to be made](https://github.com/w3c/csswg-drafts/issues/1282#issuecomment-1249822796),
39 | but the next step is
40 | _making a list of impacted properties_
41 | - [2023 update for I18n WG](https://github.com/w3c/csswg-drafts/issues/1282#issuecomment-1719113776) --
42 | _still waiting on the research_
43 | - [2024 update for I18n WG](https://github.com/w3c/csswg-drafts/issues/1282#issuecomment-2372647118) --
44 | _still waiting on research_
45 |
46 | ## Other resources
47 |
48 | - Jeremy Keith, 2022: [Let's get logical](https://adactio.com/journal/19457)
49 | - Miriam, 2022: [A long-term plan for logical shorthands?](https://www.miriamsuzanne.com/2022/09/16/tpac-logical/)
50 | - OddBird, 2025: [Support logical shorthands in CSS](https://www.oddbird.net/2025/03/20/logical-shorthand/)
51 |
--------------------------------------------------------------------------------
/src/logical/research.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Logical shorthand notes & side quests
3 | created: 2025-03-26
4 | ---
5 |
6 | ## Why `inline-size` but `padding-inline`?
7 |
8 | This is a question from
9 | [@johanwestling on Mastodon](https://mastodon.social/@johanwestling/114220721222033597):
10 |
11 | > But why the opposite property naming order?
12 | > I mean `padding`, `padding-block`, `padding-inline` for example.
13 |
14 | I wasn't in the CSS Working Group
15 | when this decision was made,
16 | but here's what I've found so far.
17 |
18 | - December 2010
19 | Writing Modes spec defines terms
20 | `length` (logical `height`)
21 | and `measure` (logical `width`)
22 | https://www.w3.org/TR/2010/WD-css3-writing-modes-20101202/#dimensions
23 | - March 2014
24 | Writing-Modes spec uses
25 | `extent` (block) & `measure` (inline):
26 | https://www.w3.org/TR/2014/CR-css-writing-modes-3-20140320/#abstract-dimensions
27 | - March 2014
28 | CSSWG resolves to use
29 | `inline-(something)` and `block-(something)` instead:
30 | https://lists.w3.org/Archives/Public/www-style/2014Mar/0255.html
31 | - March 2014 The discussion is mostly about
32 | what `(something)` should be,
33 | and agreeing that a hyphen makes
34 | `block-size` more clear than `block size`
35 | (the 2D size of a block?):
36 | https://lists.w3.org/Archives/Public/www-style/2014Mar/0479.html
37 | - July 2014 first commit to Logical Properties spec
38 | includes `length` and `measure` as the property names:
39 | https://github.com/w3c/csswg-drafts/blob/156b081188738ea7ecd1aa6a168e4347d339b19f/css-logical-props/Overview.bs
40 | - October 2014 the properties are updated to
41 | `inline-size` and `block-size`:
42 | https://github.com/w3c/csswg-drafts/commit/0a24110043cb3f3033fb22661297046a54465eda
43 | - December 2015
44 | Writing Modes spec uses `inline-size` and `block-size`: https://www.w3.org/TR/2015/CR-css-writing-modes-3-20151215/#abstract-axes
45 | - May 2017
46 | First Public Working Draft of Logical Properties:
47 | https://www.w3.org/TR/2017/WD-css-logical-1-20170518/
48 |
49 | [Github issues only go back to late 2015](https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue%20&page=377),
50 | after the names seem to be settled,
51 | so I can't find any discussion there.
52 |
53 | Many of the people participating in those conversations
54 | are still involved with the CSSWG today,
55 | so I can ask around for more information --
56 | but it seems to me that the likely answer is:
57 |
58 | - The logical `margin`, `padding`, and `border` properties
59 | were added as longhand versions of existing properties,
60 | with the well established `-` syntax.
61 | - At the time, `width` and `height` were not longhand properties
62 | with a shared shorthand base-property,
63 | and so the logical alternatives were not designed
64 | as longhand sub-properties.
65 | - `inline-size` and `block-size` already existed as conceptual terms,
66 | and they read better than the flipped `size-inline` and `size-block`.
67 | Without a shorthand property to base the names off,
68 | there's little reason to change them.
69 | - Now that we are adding a `size` shorthand,
70 | the pattern seems inconsistent --
71 | but it wasn't even a consideration previously.
72 |
--------------------------------------------------------------------------------
/src/sass/color-spaces/proposal.11tydata.yaml:
--------------------------------------------------------------------------------
1 | title: Sass Color Spaces Proposal
2 | created: 2022-03-11
3 | progress: implemented
4 | tags: [explainer]
5 | changes:
6 | - time: 2022-04-04T15:56:51-06:00
7 | log: Defining color terms, procedures, and functions
8 | - time: 2022-05-25T13:47:45-06:00
9 | log: |
10 | Define color parsing, missing/powerless components,
11 | and channel boundaries
12 | - time: 2022-06-01T13:35:32-06:00
13 | log: Define gamut-mapping, and allow spaces to represent gamuts
14 | - time: 2022-06-06T17:10:38-06:00
15 | log: |
16 | Improve parsing logic, and flesh out hwb() function
17 | based on [sample code](https://github.com/oddbird/sass-colors-sample)
18 | - time: 2022-06-28T17:34:49-06:00
19 | log: |
20 | Define hwb, (ok)lab, and (ok)lch functions,
21 | and update todo lists.
22 | - time: 2022-07-03T12:31:55-06:00
23 | log: Add support for color-spaces in color component parsing
24 | - time: 2022-07-08T18:13:39-06:00
25 | log: Parser support for color() syntax, and all new functions defined
26 | - time: 2022-08-09T17:10:33-06:00
27 | log: |
28 | - Finalize color interpolation logic, and `color.mix()` function
29 | - Note potential issues with missing (`none`) channels in conversion
30 | - Deprecate individual channel inspection functions in favor of
31 | `color.channel()`
32 | - Organize global and color-module function groups
33 | - Complete specification of global `hwb()` function,
34 | and deprecate `color.hwb()` functions
35 | - Specify updates to global `rgb()` functions
36 | - time: 2022-08-10T14:45:22-06:00
37 | log: |
38 | - Organize and document open issues
39 | - Define `hsl()`/`hsla()` functions
40 | - Remove any out-of-gamut channel clamping and adjustments
41 | - Ensure channels are returned as-specified when inspecting
42 | - time: 2022-08-19T17:59:57-06:00
43 | log: Define logic for `color.alpha()` and `color.change()`.
44 | - time: 2022-08-22T18:16:56-06:00
45 | log: |
46 | - Define color spaces and channels more clearly,
47 | and update to reflect latest spec.
48 | - Define 'channel normalization' in a reusable procedure,
49 | and include is as part of the color component parsing procedure.
50 | - Use channel normalization to simplify color function overloads.
51 | - Define logic for `color.adjust()` and `color.scale()`, treating
52 | the `none` keyword as a value of `0`.
53 | - time: 2022-08-24T17:44:03-06:00
54 | log: |
55 | This is a complete first draft of the color proposal, including all the
56 | proposed new & modified functions. However, there are still some
57 | questions to resolve in the editing & review process.
58 |
59 | - Draft logic for `color.complement()`, `color.invert()`, and
60 | `color.ie-hex-string()`.
61 | - Update logic for `color.mix()` and color interpolation to better
62 | match standards in CSS Colors 4 and 5.
63 | - time: 2022-09-05T16:58:31-06:00
64 | log: |
65 | Update this document to reflect
66 | the latest changes in the
67 | [Sass Pull Request](https://github.com/sass/sass/pull/2832),
68 | and add a deprecation notice.
69 | All future updates will be made
70 | in the Sass repository.
71 |
--------------------------------------------------------------------------------
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const nav = require('@11ty/eleventy-navigation');
2 | const hljs = require('@11ty/eleventy-plugin-syntaxhighlight');
3 | const pluginRss = require("@11ty/eleventy-plugin-rss");
4 | const toc = require('eleventy-plugin-toc');
5 | const yaml = require('js-yaml');
6 | const ghSlug = require('github-slugger').slug;
7 |
8 | const time = require('./filters/time');
9 | const type = require('./filters/type');
10 | const get = require('./filters/get');
11 |
12 | module.exports = function (eleventyConfig) {
13 | eleventyConfig.addPlugin(hljs);
14 | eleventyConfig.addPlugin(nav);
15 | eleventyConfig.addPlugin(toc);
16 | eleventyConfig.addPlugin(pluginRss);
17 |
18 | eleventyConfig.addPlugin(get);
19 |
20 | eleventyConfig.addWatchTarget('./src/styles/');
21 | eleventyConfig.addPassthroughCopy('./src/css');
22 | eleventyConfig.addPassthroughCopy("./src/**/*.svg");
23 |
24 | // filters
25 | eleventyConfig.addFilter('amp', type.amp);
26 | eleventyConfig.addFilter('typogr', type.set);
27 | eleventyConfig.addFilter('md', type.render);
28 | eleventyConfig.addFilter('mdInline', type.inline);
29 |
30 | eleventyConfig.addFilter('date', time.date);
31 |
32 | // Get the first `n` elements of a collection.
33 | eleventyConfig.addFilter('slice', (array, n) => {
34 | if (n < 0) {
35 | return array.slice(n);
36 | }
37 |
38 | return array.slice(0, n);
39 | });
40 |
41 | // config
42 | eleventyConfig.setLibrary('md', type.mdown);
43 | eleventyConfig.addDataExtension('yaml', yaml.safeLoad);
44 | eleventyConfig.setQuietMode(true);
45 | eleventyConfig.setDataDeepMerge(true);
46 |
47 | // shortcodes
48 | eleventyConfig.addPairedShortcode('md', type.render);
49 | eleventyConfig.addPairedShortcode('mdInline', type.inline);
50 | eleventyConfig.addPairedShortcode('typogr', type.set);
51 | eleventyConfig.addPairedShortcode('note', type.note);
52 | eleventyConfig.addPairedShortcode('warn', type.warn);
53 |
54 | eleventyConfig.addCollection("changes", function(collectionApi) {
55 | const all = collectionApi.getAll();
56 | const changes = [];
57 |
58 | all.forEach((post) => {
59 | if (post.data.changes) {
60 | post.data.changes
61 | .sort((a, b) => b.time - a.time)
62 | .forEach((change, i) => {
63 | const date = change.time;
64 | changes.push({
65 | post,
66 | date,
67 | url: post.url,
68 | log: change.log,
69 | latest: i === 0,
70 | });
71 | });
72 | }
73 |
74 | if (!post.data.draft) {
75 | const date = post.data.created || post.date;
76 | changes.push({
77 | post,
78 | date,
79 | log: 'New page added',
80 | latest: post.data.changes ? false : true,
81 | creation: true,
82 | });
83 | }
84 | });
85 |
86 | return changes.map((item) => {
87 | item.url = `/changelog${item.post.url}${ghSlug(time.date(item.date, 'iso'))}/`;
88 | item.date_group = time.date(item.date, 'long');
89 | return item;
90 | }).sort((a, b) => b.date - a.date);
91 | });
92 |
93 | return {
94 | markdownTemplateEngine: 'njk',
95 | dir: {
96 | input: 'src',
97 | output: 'public',
98 | layouts: '_layouts',
99 | },
100 | };
101 | };
102 |
--------------------------------------------------------------------------------
/src/_layouts/base.njk:
--------------------------------------------------------------------------------
1 | ---
2 | date: Last Modified
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{ title }}
11 |
12 |
13 |
14 | {% if redirect -%}
15 |
16 |
17 | {%- endif %}
18 |
19 |
20 | {% include "base/nav.njk" %}
21 |
22 |
23 | {{ title | mdInline | safe }}
24 |
25 | {% if tags %}
26 | {% set updated = collections[index] | latest
27 | if index
28 | else collections.all | getPage(page) | getDate
29 | %}
30 |
31 | Updated {{ updated.toLocaleString('en-US', {'dateStyle': 'medium'}) }}
32 |
33 | {% endif %}
34 |
35 | {% if content | toc %}
36 |
37 | Table of Contents
38 | {{ content | toc | safe }}
39 |
40 | {% endif %}
41 |
42 |
43 |
44 | {{ content | typogr | safe }}
45 |
46 |
47 | {% include "base/support.njk" %}
48 | {% include "base/changes.njk" %}
49 |
50 |
51 | {% include "base/footer.njk" %}
52 |
53 |
54 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/src/_layouts/feed.njk:
--------------------------------------------------------------------------------
1 | {%- set changes = collections.changes | slice(15) -%}
2 |
3 |
4 | {{ feed.title }}
5 | {{ feed.subtitle }}
6 | {{ feed.url }}
7 |
8 |
9 | {{ changes[0].date | dateToRfc3339 }}
10 | © {{ none | date('year') }} {{ feed.author.name }}
11 | {{ '/favicon.svg' | absoluteUrl(feed.url) }}
12 | Eleventy
13 |
14 | {{ feed.author.name }}
15 | {{ feed.author.email }}
16 |
17 | {%- for change in changes -%}
18 | {%- set absolutePostUrl = (change.post.url if change.creation else change.url) | absoluteUrl(feed.url) -%}
19 |
20 |
21 | {{ change.date | dateToRfc3339 }}
22 | {{ absolutePostUrl }}
23 |
24 | {%- if change.creation -%}
25 |
26 | New page: {{ change.post.data.title }}
27 |
28 | {%- else -%}
29 |
30 | Changes to: {{ change.post.data.title }}
31 |
32 | {%- endif -%}
33 |
34 | {%- set feedSummary -%}
35 |
36 | {{ change.log | md | safe }}
37 |
38 |
39 |
40 |
41 | {{ change.post.data.title or 'See latest' }} »
42 |
43 |
44 | {%- endset -%}
45 |
46 | {%- set feedContent -%}
47 | {%- if change.latest -%}
48 | {{- change.post.templateContent | safe -}}
49 | {%- else -%}
50 | This page has more recent changes available. For more details, see:
51 |
56 | {%- endif -%}
57 | {%- endset -%}
58 |
59 |
60 | {{- feedSummary | htmlToAbsoluteUrls(absolutePostUrl) -}}
61 |
62 |
63 |
64 | {{- feedSummary | htmlToAbsoluteUrls(absolutePostUrl) -}}
65 | {{ ' ' }}
66 | {{- feedContent | htmlToAbsoluteUrls(absolutePostUrl) -}}
67 |
68 |
69 | {%- endfor %}
70 |
71 |
72 | {#
73 |
74 | {%- for change in collections.changes %}
75 | {%- set post = change.post %}
76 | {% set absolutePostUrl %}{{ post.url | url | absoluteUrl(feed.url) }}{% endset %}
77 |
78 | {{ post.data.title }} | {{ change.log }}
79 |
80 | {{ change.date | dateToRfc3339 }}
81 | {{ absolutePostUrl }}
82 | {%- set feedContent -%}
83 | {%- if change.latest -%}
84 | {{ post.templateContent }}
85 | {%- else -%}
86 | This page has more recent changes available. For more details, see:
87 |
92 | {%- endif -%}
93 | {%- endset -%}
94 | {{ feedContent | htmlToAbsoluteUrls(absolutePostUrl) | safe }}
95 |
96 | {%- endfor %}
97 | #}
98 |
--------------------------------------------------------------------------------
/src/rwd/query/resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Container Query Resources
3 | created: 2021-05-12
4 | changes:
5 | - time: 2021-09-23T10:50:59-04:00
6 | log: Articles about container query units
7 | tags:
8 | - resources
9 | ---
10 |
11 | - WICG: [Use Cases and Requirements](https://wicg.github.io/cq-usecases/)
12 | - Chris Coyier: [Let's Not Forget About Container Queries](https://css-tricks.com/lets-not-forget-about-container-queries/)
13 | - Chris Coyier: [Container Query Discussion](https://css-tricks.com/container-query-discussion/)
14 | - Zach Leatherman: [The Origin Story of Container Queries](https://www.zachleat.com/web/origin-container-queries/)
15 |
16 | [_Who is Working on Container Queries_](http://whoisworkingoncontainerqueries.com/)
17 | contains a long list of existing JS plugins.
18 |
19 | There are also some interesting CSS custom-property solutions.
20 | These all work one-property-at-a-time,
21 | much like the [`switch()` proposal](switch/)…
22 |
23 | - Heydon Pickering: [Flexbox Holy Albatros](https://heydonworks.com/article/the-flexbox-holy-albatross/)
24 | - Xiao Zhuo Jia: [Unholy Albatross](http://www.miragecraft.com/articles/unholy_albatross.html)
25 | - Mathias Hülsbusch: [The Raven Technique](https://css-tricks.com/the-raven-technique-one-step-closer-to-container-queries/)
26 |
27 | ## Talks & Podcasts
28 |
29 | - [CSSWG Proposals](https://slides.oddbird.net/csswg/)
30 | - [Styling the Intrinsic Web](https://www.oddbird.net/talks/intrinsic-web/)
31 | ([slides](https://slides.oddbird.net/css-next/))
32 | - [Front End Nerdery](https://www.oddbird.net/2021/08/15/fe-nerdery-10/)
33 | - [Container Queries & The Future of CSS](https://www.oddbird.net/talks/responsive-components/)
34 | ([slides](https://slides.oddbird.net/css-next/))
35 | - [Syntax.fm](https://www.oddbird.net/2021/06/16/syntaxfm-362/)
36 | - [Word Wrap Show](https://www.oddbird.net/2021/05/17/word-wrap-11/)
37 | - [The F-Word](https://www.oddbird.net/2021/05/06/f-word-11/)
38 | - [Smashing Podcast](https://www.oddbird.net/2021/05/04/smashing-36/)
39 |
40 | ## Articles & Demos
41 |
42 | - [OddBird Resources](https://www.oddbird.net/tags/container-queries/)
43 | - [Container Queries: a Quick Start Guide](https://www.oddbird.net/2021/04/05/containerqueries/)
44 | by **David Herron**
45 | - [A Primer On CSS Container Queries](https://www.smashingmagazine.com/2021/05/complete-guide-css-container-queries/)
46 | by **Stephanie Eckles**
47 | - [Say Hello To CSS Container Queries](https://ishadeed.com/article/say-hello-to-css-container-queries/)
48 | by **Ahmad Shadeed**
49 | ([annotated on CSS Tricks](https://css-tricks.com/say-hello-to-css-container-queries/)
50 | by **Robin Rendle**)
51 | - [CSS Container Queries For Designers](https://ishadeed.com/article/container-queries-for-designers/)
52 | by **Ahmad Shadeed**
53 | - [Container Queries in Web Components](https://mxb.dev/blog/container-queries-web-components/)
54 | by **Max Böck**
55 | - [Container Queries are actually coming](https://piccalil.li/blog/container-queries-are-actually-coming)
56 | by **Andy Bell**
57 | - [CSS Container Queries: A First Look + Demo](https://www.bram.us/2021/03/28/css-container-queries-a-first-look-and-demo/)
58 | by **Bramus Van Damme**
59 | - [Next Gen CSS: @container](https://css-tricks.com/next-gen-css-container/)
60 | by **Una Kravets**
61 | - [CSS Container Queries: Use-Cases And Migration Strategies](https://www.smashingmagazine.com/2021/05/css-container-queries-use-cases-migration-strategies/)
62 | by **Adrian Bece**
63 | - [Twitch live-stream highlights](https://www.twitch.tv/collections/8k9OzUpxdxb9VA)
64 | & [summary](https://www.twitch.tv/videos/993981213?collection=8k9OzUpxdxb9VA)
65 | by **Stephanie Eckles**
66 | - [My CodePen collection of demos](https://codepen.io/collection/XQrgJo)
67 |
68 | Query Units:
69 |
70 | - [CSS Container Query Units](https://ishadeed.com/article/container-query-units/)
71 | by **Ahmad Shadeed**
72 | - [Container Units Should Be Pretty Handy](https://css-tricks.com/container-units-should-be-pretty-handy/)
73 | by **Chris Coyier**
74 |
75 | See Also:
76 |
77 | - [Awesome-Container-Queries](https://github.com/sturobson/Awesome-Container-Queries)
78 | by **Stuart Robson**
79 |
80 | ## Proposals
81 |
82 | - 2020 [`@container` proposal](https://github.com/dbaron/container-queries-implementability)
83 | by **David Baron**
84 | - 2020 [`switch()` proposal](https://bkardell.com/blog/AllThemSwitches.html)
85 | by **Brian Kardell**
86 |
--------------------------------------------------------------------------------
/src/rwd/interpolation/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS Interpolated Values
3 | index: interpolation
4 | created: 2020-11-13
5 | changes:
6 | - time: 2021-09-22T00:35:28-04:00
7 | log: Brief notes on @timeline and interpolation function
8 | - time: 2021-09-23T00:11:02-04:00
9 | log: Link to fantasai/mia proposal for interpolation & timelines
10 | ---
11 |
12 | Breakpoints only get you so far.
13 | In many cases it would be better to have units
14 | and values that can respond more fluidly to context.
15 | We can do some of that with relative units
16 | (several JS plugins provide container-relative units),
17 | but that approach comes with a number of limitations.
18 |
19 | [Scott Kellum](https://twitter.com/ScottKellum)
20 | has been doing interesting work in this area --
21 | what he calls "Intrinsic Typography" --
22 | applying animation/transition concepts
23 | like "easing" and "keyframes"
24 | to responsive type.
25 |
26 | ## Proposal
27 |
28 | Fantasai and I worked on a proposal to address & unify
29 | a number of related use-cases around interpolation & timelines:
30 |
31 | Timelines can be defined in relation to:
32 | - how far a scroll-container has scrolled
33 | - how long an element is "in-view" while being scrolled
34 | - media and container-query features that have a range value
35 |
36 | Some timelines can be used to control animations
37 | (aka scroll-linked animations),
38 | but we also propose some form of interpolation function
39 | (currently called `mix()`)
40 | that can apply a timeline and easing function
41 | to a single propery.
42 |
43 | There's more to the proposal.
44 | Check it out:
45 |
46 | https://wiki.csswg.org/ideas/timelines
47 |
48 | ## Resources
49 |
50 | From Scott:
51 | - [Typetura Docs](https://docs.typetura.com/)
52 | & [Demos](http://demos.Typetura.com)
53 | - [Intrinsic Typography, CSS Tricks Article](https://css-tricks.com/intrinsic-typography-is-the-future-of-styling-text-on-the-web/)
54 | - [Query Interpolation proposal](https://gist.github.com/scottkellum/0c29c4722394c72d311c5045a30398e5)
55 |
56 | CSSWG issues:
57 | - [Interpolate values between breakpoints](https://github.com/w3c/csswg-drafts/issues/6245)
58 | - [Split CSS event bindings from application](https://github.com/w3c/csswg-drafts/issues/4343)
59 | - [Higher level CSS interpolation module](https://github.com/w3c/csswg-drafts/issues/5617)
60 | - [Need method to interpolate variable font settings](https://github.com/w3c/csswg-drafts/issues/5635)
61 | - [Native interpolation function in CSS](https://github.com/w3c/csswg-drafts/issues/581)
62 |
63 | ## Notes
64 |
65 | A few notes from my conversations with Scott:
66 |
67 | - The most common use-case
68 | is that each property has a start-value and end-value
69 | aligned to particular container sizes,
70 | and an easing curve to interpolate.
71 | This is more like a transition than a keyframe animation.
72 | - While it's rare for a single property
73 | to have additional/intermediate "stops" defined,
74 | it is useful to define multiple properties in the same place,
75 | even with different start/end points.
76 | A keyframe animation with multiple stops
77 | makes that possible in Typetura.
78 |
79 | ### Overlap with Scroll Animations
80 |
81 | This reminds me of the proposed
82 | [`@scroll-timeline`](https://drafts.csswg.org/scroll-animations-1/#scroll-timeline-at-rule) --
83 | and I see Scott had the same thought:
84 |
85 | [Split CSS event bindings from application](https://github.com/w3c/csswg-drafts/issues/4343)
86 |
87 | I think the syntax could use some finesse,
88 | but that direction _feels right_ to me --
89 | building on current animation/transition syntax,
90 | to make it work with inputs other than "time"
91 | (like scrolling, or container-width).
92 |
93 | I think there's potential here for a
94 | shared `@timeline` at-rule
95 | that could be used for:
96 |
97 | - scroll timelines
98 | - container-size timelines
99 | - media-size timelines
100 |
101 | (I also think this can all be done
102 | without the `selector()` function,
103 | but I need to look into it more.)
104 |
105 | ### Interpolation Function
106 |
107 | The CSSWG resolved at one point
108 | to add an interpolation function --
109 | though the syntax/details are TBD.
110 |
111 | That would require:
112 |
113 | - an easing function
114 | - a percentage that represents current interpolated position
115 | (potentially provided by a timeline)
116 | - a list of values to interpolate
117 |
--------------------------------------------------------------------------------
/src/scope/prior-art.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Prior Art
3 | created: 2021-10-05
4 | ---
5 |
6 | ## Existing Specifications
7 |
8 | ### [CSS Selectors - Level 4](https://www.w3.org/TR/selectors-4/)
9 |
10 | - [Scoped Selectors](https://www.w3.org/TR/selectors-4/#scoping)
11 | that only refer to a subtree or fragment of the document
12 |
13 | > When a selector is scoped, it matches an element
14 | > only if the element is a descendant of the scoping root.
15 | > (The rest of the selector can match unrestricted;
16 | > it’s only the final matched elements that must be within the scope.)
17 |
18 | - [Reference Element](https://www.w3.org/TR/selectors-4/#the-scope-pseudo)
19 | (`:scope`) pseudo-class
20 | (broad [browser support](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope))
21 |
22 | In CSS, this is the same as `:root`, since there is no way to scope elements. However, it is used by JS APIs to refer to the base element of e.g. `element.querySelector()`
23 |
24 | > “Specifications intending for this pseudo-class to match specific elements
25 | > rather than the document’s root element
26 | > must define either a scoping root (if using scoped selectors)
27 | > or an explicit set of :scope elements.”
28 |
29 | ### [CSS Scoping - Level 1](https://drafts.csswg.org/css-scoping/)
30 |
31 | The latest draft is primarily concerned
32 | with Custom Elements & Shadow DOM.
33 |
34 | The [First Public Working Draft](https://www.w3.org/TR/css-scoping-1/)
35 | had more scoping features that have since been removed:
36 |
37 | A `