[w3c/webcomponents] CSS Modules (#759)

In addition to [HTML Modules](https://github.com/w3c/webcomponents/issues/645), the ability to load CSS into a component definition is an important capability that we're currently lacking. Loading CSS is probably a more important use case judging by the popularity of CSS loaders in JavaScript bundlers.

Currently, styles are usually either defined inline with HTML templating or JSX or loaded with various JS Bundler CSS Loaders. The CSS loaders often have global side-effects like appending a `<style>` tag to the document, which does not generally work well with the style scoping of Shadow DOM.

I propose that we add CSS Modules to the platform, allowing CSS to be imported directly by JavaScript:

```js
import styles from './styles.css';
```

## Exports

The semantics for CSS Modules can be very simple, and combined with [Constructable Stylesheets](https://wicg.github.io/construct-stylesheets/index.html) allow the importer to determine how the CSS should be applied to the document.

To start with, the only export of a CSS module would be a default export of the StyleSheet object. This can then simply be added to `document.styles` or `shadowRoot.styles`:

```js
import styles from './styles.css';

class MyElement extends HTMLElement {
  constructor() {
    this.attachShadow({mode: open});
    this.shadowRoot.moreStyleSheets.push(styles); // push() doesn't actually exist yet
  }
}
```

## Additional Features

Other userland CSS module systems often have more features, like the ability to import or export symbols that are defined in the module. ie:

```js
import (LitElement, html} from 'lit-element';
import styles from './styles.css';

class MyElement extends LitElement {
  constructor() {
    this.attachShadow({mode: open});
    this.shadowRoot.moreStyleSheets.push(styles); // push() doesn't actually exist yet
  }

  render() {
    return html`<div class=${styles.exampleClass}></div>`;
  }
}
```

These features may be very useful, but they can be considered for addition to the CSSOM itself so that they're exposed on CSSStyleSheet and available to both CSS Modules and styles loaded via `<style>` and `<link>` tags, or constructed from a string.

## Polyfilling

It's not easy to polyfill a new module type, but build-time tools can create JavaScript modules that adhere to the CSS Module interface.

```css
.exampleClass {
  color: red;
}
```

Can be compiled to:

```js
// create a container and scope to hold a style sheet:
const container = document.createElement('div');
const shadowRoot = container.attachShadow({mode: 'open'});

// create a <style> element to add css text to
let styleElement = document.createElement('style');

// add the styles
styleElement.textContent = String.raw`
.exampleClass {
  color: red;
}
`;

// add the <style> to the document so it creates a StyleSheet
shadowRoot.appendChild(styleElement);

const stylesheet = styleElement.sheet;
export default stylesheet;
```

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/759

Received on Wednesday, 8 August 2018 23:49:53 UTC