Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adoptedStyleSheet property docs #16773

Merged
merged 13 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion files/en-us/mozilla/firefox/releases/101/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ No notable changes.
For more information, see {{bug(1611957)}}.

- _Constructable stylesheets_ are now supported, making it much easier to create reusable stylesheets for use with [Shadow DOM](/en-US/docs/Web/Web_Components/Using_shadow_DOM).
The update includes the addition of a [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) for creating new stylesheets, and the {{domxref("CSSStyleSheet.replace()")}} and {{domxref("CSSStyleSheet.replaceSync()")}} methods that can be used to add CSS rules to them.
The update includes the addition of a [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) for creating new stylesheets, the {{domxref("CSSStyleSheet.replace()")}} and {{domxref("CSSStyleSheet.replaceSync()")}} methods that can be used to add/replace CSS rules in the sheet, and the [`Document.adoptedStyleSheets`](/en-US/docs/Web/API/Document/adoptedStyleSheets) and [`ShadowRoot.adoptedStyleSheets`](/en-US/docs/Web/API/ShadowRoot/adoptedStyleSheets) properties that are used to share sheets to a document and its shadow DOM subtrees.
See {{bug(1520690)}} for more information.

#### Media, WebRTC, and Web Audio
Expand Down
42 changes: 40 additions & 2 deletions files/en-us/web/api/cssstylesheet/cssstylesheet/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ browser-compat: api.CSSStyleSheet.CSSStyleSheet

The **`CSSStyleSheet()`** constructor creates a new {{domxref("CSSStyleSheet")}} object which represents a single [Stylesheet](/en-US/docs/Glossary/Stylesheet).

After constructing a stylesheet the {{domxref("CSSStyleSheet.replace()")}} or {{domxref("CSSStyleSheet.replaceSync()")}} methods can be used to add rules to the new stylesheet.
After constructing a stylesheet the {{domxref("CSSStyleSheet.replace()")}}, {{domxref("CSSStyleSheet.replaceSync()")}}, {{domxref("CSSStyleSheet.insertRule()")}}, and {{domxref("CSSStyleSheet.deleteRule()")}} methods can be used to modify the rules of the new stylesheet.

A stylesheet created using this method is referred to as a "constructed stylesheet".
A constructed stylesheet can be shared between a document and its shadow DOM subtrees using {{domxref("ShadowRoot.adoptedStyleSheets")}} and {{domxref("Document.adoptedStyleSheets")}}.


## Syntax

Expand All @@ -37,13 +41,47 @@ new CSSStyleSheet(options)

## Examples

In the following example a new {{domxref("CSSStyleSheet")}} is constructed, with a media rule of `"print"`. Printing {{domxref("StyleSheet.media")}} to the console returns a {{domxref("MediaList")}} with a single entry for this print rule.
In the following example, a new {{domxref("CSSStyleSheet")}} is constructed with a media rule of `"print"`.
Printing {{domxref("StyleSheet.media")}} to the console returns a {{domxref("MediaList")}} with a single entry for this print rule.

```css
let stylesheet = new CSSStyleSheet({media: 'print'});
console.log(stylesheet.media);
```

### Sharing stylesheets with a shadow DOM

The code below shows the sheet being constructed and then {{domxref("CSSStyleSheet.replaceSync()")}} is called to add a rule to the sheet.

```js
// Create an empty "constructed" stylesheet
const sheet = new CSSStyleSheet();
// Apply a rule to the sheet
sheet.replaceSync('a { color: red; }');
```

We then create a {{domxref("ShadowRoot")}} and pass the sheet object to the {{domxref("ShadowRoot.adoptedStyleSheets")}} property inside an array.

```js
// Create an element in the document and then create a shadow root:
const node = document.createElement('div');
const shadow = node.attachShadow({ mode: 'open' });

//Adopt the sheet into the shadow DOM
shadow.adoptedStyleSheets = [sheet];
```

We can modify the stylesheets after they have been added to the array.
Below we append a new rule to the same sheet using {{domxref("CSSStyleSheet.insertRule()")}}.

```js
sheet.insertRule("* { background-color: blue; }");
// The document will now have blue background.
```

The same sheet can be shared with multiple shadow subtrees of the same document.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
For more exmaples see {{domxref("ShadowRoot.adoptedStyleSheets")}}.

## Specifications

{{Specifications}}
Expand Down
1 change: 1 addition & 0 deletions files/en-us/web/api/cssstylesheet/deleterule/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,6 @@ This example removes the first rule from the stylesheet `myStyles`.
## See also

- [CSS Object Model](/en-US/docs/Web/API/CSS_Object_Model)
- [Constructable Stylesheets](https://web.dev/constructable-stylesheets/) (web.dev)
- [Using dynamic styling information](/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information)
- {{domxref("CSSStyleSheet.insertRule", "insertRule()")}}
6 changes: 2 additions & 4 deletions files/en-us/web/api/cssstylesheet/insertrule/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,5 @@ instead of {{domxref("CSSStyleSheet.deleteRule","deleteRule()")}} and
## See also

- {{domxref("CSSStyleSheet.deleteRule")}}
- [Cross-Browser
CSS-rules ordering (CSS1)](https://www-archive.mozilla.org/docs/web-developer/css1technote/css1tojs.html#priority)
- [Quirksmode -
CSS](https://www.quirksmode.org/dom/w3c_css.html)
- [Constructable Stylesheets](https://web.dev/constructable-stylesheets/) (web.dev)
- [Cross-Browser CSS-rules ordering (CSS1)](https://www-archive.mozilla.org/docs/web-developer/css1technote/css1tojs.html#priority)
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion files/en-us/web/api/cssstylesheet/replace/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ replace(text)
- `text`
- : A string containing the style rules to replace the content of the stylesheet. If the string does not contain a parseable list of rules, then the value will be set to an empty string.

> **Note:** If any of the rules passed in `text` are an external stylesheet imported with the {{cssxref("@import")}} rule, those rules will be removed, and a warning printed to the console.
> **Note:** If any of the rules passed in `text` are an external stylesheet imported with the {{cssxref("@import")}} rule, those rules will be removed, and a warning printed to the console.

### Return value

Expand Down
4 changes: 2 additions & 2 deletions files/en-us/web/api/cssstylesheet/replacesync/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ replaceSync(text)
- `text`
- : A string containing the style rules to replace the content of the stylesheet. If the string does not contain a parseable list of rules, then the value will be set to an empty string.

> **Note:** If any of the rules passed in `text` are an external stylesheet imported with the {{cssxref("@import")}} rule, those rules will be removed, and a warning printed to the console.
> **Note:** If any of the rules passed in `text` are an external stylesheet imported with the {{cssxref("@import")}} rule, those rules will be removed, and a warning printed to the console.

### Return value

Undefined.
None (`undefined`).

### Exceptions

Expand Down
109 changes: 109 additions & 0 deletions files/en-us/web/api/document/adoptedstylesheets/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
title: Document.adoptedStyleSheets
slug: Web/API/Document/adoptedStyleSheets
tags:
- API
- Document
- Property
- Reference
- Stylesheets
- adoptedStyleSheets
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
page-type: web-api-instance-property
browser-compat: api.Document.adoptedStyleSheets
---
{{APIRef("CSSOM")}}

The **`adoptedStyleSheets`** property of the {{domxref("Document")}} interface is used for setting an array of constructed stylesheets to be used by the document.

> **Note:** A constructed stylesheet is a stylesheet created programmatically using the [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) (as compared to one created by a user-agent when importing a stylesheet from a script, imported using {{HTMLElement('style')}} and {{CSSXref('@import')}}, or linked to via {{HTMLElement('link')}}).

The same constructed stylesheets can also be shared with one or more {{domxref("ShadowRoot")}} instances using the [`ShadowRoot.adoptedStyleSheets`](/en-US/docs/Web/API/ShadowRoot/adoptedStyleSheets) property.
Changing an adopted stylesheet will affect all the objects that adopt it.

Stylesheets in the property are considered along with the document's other stylesheets.
For the purpose of determining the final computed CSS of any element, they are considered to have been added _after_ the other stylesheets in the document ([`Document.styleSheets`](/en-US/docs/Web/API/Document/styleSheets)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as they are "later", they take precedence if selectors match, and are unlayered, so take precedence over all other styles. Is there a way to assign them to a layer?

Copy link
Collaborator Author

@hamishwillee hamishwillee Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@estelle Good question. This comes from the very last bullet point in the explainer

  • Stylesheets added to adoptedStyleSheets are part of the DocumentOrShadowRoot's style sheets, and they are ordered after theDocumentOrShadowRoot's styleSheets.
    • This means when there are conflicting rules in the adoptedStyleSheets and styleSheets and the resolution will consider the order of stylesheets, they treat the sheets in adoptedStyleSheets as ordered later.

I have more accurately captured this in suggestion: https://github.com/mdn/content/pull/16773/files#r888564793

Is there a way to assign them to a layer?

I don't know. Asked here: https://bugzilla.mozilla.org/show_bug.cgi?id=1644102#c13

AS an aside

If you search on "cascade" there are a few links other than your update topic. You might want to cross link to your updated doc (and making sure there are no glaring errors)? For example https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance

Copy link
Collaborator Author

@hamishwillee hamishwillee Jun 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@estelle Response from developer to questions:

Is there a way to assign constructed CSS stylesheet rules to a layer?

Using @layer inside the stylesheet just like in a style element.
w3c/csswg-drafts#7002 tracks adding a per-stylesheet
layer.

For calculating the cascade, the explainer says that if there are rules in conflict that would be resolved by order or import, then the adopted stylesheets come last. The question is, can I assume that they are treated as author origin and that that even if imported in inline javascript, they will not be considered to be inline styles?

Hm? Not sure I follow. Yes, these are always author stylesheets. The order of the stylesheets is

  • Stylesheets in the shadow tree (<link> and <style>, in tree order)
  • Adopted stylesheets (in whatever order the array is).

So the only "special" thing about adopted stylesheets is that they're effective order of import into the user agent is after other stylesheets and in the order of the array. All other things like layers are as per the normal cascade rules. I think that is captured by the updated comment

hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

Only stylesheets created using the [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) within the context of the current {{domxref("Document")}} may be adopted.


## Value

The value is an array of {{domxref("CSSStyleSheet()")}} instances that must have been created using the {{domxref("CSSStyleSheet.CSSStyleSheet()", "CSSStyleSheet()")}} constructor within the context of the same {{domxref("Document")}}.

If the array needs to be modified, then a new array must be assigned (in-place mutations like `push()` will throw an exception).
Note however that the {{domxref("CSSStyleSheet()")}} instances themselves can be modified, and these changes will apply wherever the stylesheet is adopted.


### Exceptions

- `NotAllowedError` {{domxref("DOMException")}}
- : One of the {{domxref("CSSStyleSheet")}} instances in the array was not created using the [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) or was constructed in a different document than the current document, such as one in a frame.


## Examples

### Adopting a stylesheet

The code below shows a stylesheet being constructed, and then {{domxref("CSSStyleSheet.replaceSync()")}} is called to add a rule to the sheet.
The stylesheet is then added to an array and assigned to the `adoptedStyleSheets` property.

```js
// Create an empty "constructed" stylesheet
const sheet = new CSSStyleSheet();
// Apply a rule to the sheet
sheet.replaceSync('a { color: red; }');

// Apply the stylesheet to a document
document.adoptedStyleSheets = [sheet];
```

We can append a new rule to the stylesheet using {{domxref("CSSStyleSheet.insertRule()")}}.

```js
sheet.insertRule("* { background-color: blue; }");
// The document will now have blue background.
```

hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
### Append a new stylesheet

To append a whole new stylesheet to the `adoptedStyleSheets` property we have to create and assign a new combined array.
This is demonstrated below using spread-syntax:

```js
const extraSheet = new CSSStyleSheet();
sheet.replaceSync('p { color: green; }');

// Combine the existing sheets and new one
document.adoptedStyleSheets = [...document.adoptedStyleSheets, extraSheet];
```

## Sharing a stylesheet with a shadow DOM

We can share a stylesheet to a shadow root in a similar way.

```js
// Create an element in the document and then create a shadow root:
const node = document.createElement('div');
const shadow = node.attachShadow({ mode: 'open' });

//Adopt the same sheet into the shadow DOM
shadow.adoptedStyleSheets = [sheet];
```

## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- [Constructable Stylesheets](https://web.dev/constructable-stylesheets/) (web.dev)
- [Using the Shadow DOM](/en-US/docs/Web/Web_Components/Using_shadow_DOM)
- [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet)
- {{domxref("CSSStyleSheet.replaceSync()")}}
- {{domxref("CSSStyleSheet.replace()")}}
- {{domxref("CSSStyleSheet.insertRule()")}}
- {{domxref("CSSStyleSheet.deleteRule()")}}
estelle marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions files/en-us/web/api/document/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ _This interface also inherits from the {{DOMxRef("Node")}} and {{DOMxRef("EventT

- {{DOMxRef("Document.activeElement")}} {{ReadOnlyInline}}
- : Returns the {{DOMxRef('Element')}} that currently has focus.
- {{DOMxRef("Document.adoptedStyleSheets")}}
- : Add an array of constructed stylesheets to be used by the document.
These stylesheets may also be shared with shadow DOM subtrees of the same document.
- {{DOMxRef("Document.body")}}
- : Returns the {{HTMLElement("body")}} or {{htmlelement("frameset")}} node of the current document.
- {{DOMxRef("Document.characterSet")}}{{ReadOnlyInline}}
Expand Down
97 changes: 97 additions & 0 deletions files/en-us/web/api/shadowroot/adoptedstylesheets/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: ShadowRoot.adoptedStyleSheets
slug: Web/API/ShadowRoot/adoptedStyleSheets
tags:
- API
- ShadowRoot
- Property
- Reference
- Stylesheets
- adoptedStyleSheets
page-type: web-api-instance-property
browser-compat: api.ShadowRoot.adoptedStyleSheets
---
{{APIRef("CSSOM")}}

The **`adoptedStyleSheets`** property of the {{domxref("ShadowRoot")}} interface sets an array of constructed stylesheets to be used by the shadow DOM subtree.

> **Note:** A constructed stylesheet is a stylesheet created programmatically using the [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet) (as compared to one created by a user-agent when importing a stylesheet from a script, imported using {{HTMLElement('style')}} and {{CSSXref('@import')}}, or linked to via {{HTMLElement('link')}}).

The same constructed stylesheet can be adopted by multiple {{domxref("ShadowRoot")}} instances, and by the parent document (using the {{domxref("Document.adoptedStyleSheets")}} property).
Changing an adopted stylesheet will affect all the adopting objects.

Stylesheets in the property are considered along with the shadow DOM's other stylesheets.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
For the purpose of determining the final computed CSS of any element, they are considered to have been added _after_ the other stylesheets in the shadow DOM ([`ShadowRoot.styleSheets`](/en-US/docs/Web/API/Document/styleSheets)).

Only stylesheets created using the [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet), and from within the same parent {{domxref("Document")}} as the shadow root, may be adopted.


## Value

The value is an array of {{domxref("CSSStyleSheet()")}} instances that must have been created using the {{domxref("CSSStyleSheet.CSSStyleSheet()", "CSSStyleSheet()")}} constructor within the context of the shadow root's parent {{domxref("Document")}}.

If the array needs to be modified, then a new array must be assigned (in-place mutations like `push()` will throw an exception).
Note however that the {{domxref("CSSStyleSheet()")}} instances themselves can be modified, and these changes will apply wherever the stylesheet is adopted.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved

## Examples

### Adopting a stylesheet

The code below first shows a stylesheet being constructed, and then {{domxref("CSSStyleSheet.replaceSync()")}} is called to add a rule to the sheet.

```js
// Create an empty "constructed" stylesheet
const sheet = new CSSStyleSheet();
// Apply a rule to the sheet
sheet.replaceSync('a { color: red; }');
```

We then create a {{domxref("ShadowRoot")}} and pass the sheet object to `adoptedStyleSheets` inside an array.

```js
// Create an element in the document and then create a shadow root:
const node = document.createElement('div');
const shadow = node.attachShadow({ mode: 'open' });

//Adopt the sheet into the shadow DOM
shadow.adoptedStyleSheets = [sheet];
```

We can still modify the stylesheets after they have been added to the array.
Below we append a new rule to the same sheet using {{domxref("CSSStyleSheet.insertRule()")}}.

```js
sheet.insertRule("* { background-color: blue; }");
// The document will now have blue background.
```

### Append a new stylesheet

To append a whole new stylesheet to the `adoptedStyleSheets` property we have to create and assign a new combined array.
hamishwillee marked this conversation as resolved.
Show resolved Hide resolved
This is demonstrated for our shadow root object below using spread-syntax:

```js
const extraSheet = new CSSStyleSheet();
sheet.replaceSync('p { color: green; }');

// Combine the existing sheets and new one
shadow.adoptedStyleSheets = [...document.adoptedStyleSheets, extraSheet];
```

## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- [Constructable Stylesheets](https://web.dev/constructable-stylesheets/) (web.dev)
- [Using the Shadow DOM](/en-US/docs/Web/Web_Components/Using_shadow_DOM)
- [`CSSStyleSheet()` constructor](/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet)
- {{domxref("CSSStyleSheet.replaceSync()")}}
- {{domxref("CSSStyleSheet.replace()")}}
- {{domxref("CSSStyleSheet.insertRule()")}}
- {{domxref("CSSStyleSheet.deleteRule()")}}
3 changes: 3 additions & 0 deletions files/en-us/web/api/shadowroot/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ You can retrieve a reference to an element's shadow root using its {{domxref("El

- {{domxref("ShadowRoot.activeElement")}} {{readonlyInline}}
- : Returns the {{domxref('Element')}} within the shadow tree that has focus.
- {{domxref("ShadowRoot.adoptedStyleSheets")}}
- : Add an array of constructed stylesheets to be used by the shadow DOM subtree.
These may be shared with other DOM subtrees that share the same parent {{domxref("Document")}} node, and the document itself.
- {{domxref("ShadowRoot.delegatesFocus")}} {{readonlyinline}} {{non-standard_inline}} {{deprecated_inline}}
- : Returns a boolean that indicates whether `delegatesFocus` was set when the shadow was attached (see {{domxref("Element.attachShadow()")}}).
- {{DOMxRef("ShadowRoot.fullscreenElement")}} {{ReadOnlyInline}}
Expand Down