Skip to content

[css-cascade-6] A way for <style> elements to scope to their parent element #6606

Closed

Description

@dfabulich

https://drafts.csswg.org/css-cascade-6/#scoped-styles

The explainer references this issue: Please bring back scoped styles.

Either there's something missing from the spec or I'm missing it, which is a way to have a <style> element that gets scoped to its own parent element.

<div>
  <style scoped>p { color: red; }</style>
  <p>red</p>
</div>

<style scoped> would guarantee that the color only applied to children of the parent div.

I could do it by adding a unique ID or attribute:

<div id="foo">
  <style>#foo p { color: red; }</style>
  <p>red</p>
</div>

… this is basically what Vue does at build time. But I want the same effect without a build step!

I think we'd want something like @scope(:style-parent).

<div>
  <style>@scope(:style-parent) { p { color: red; } }</style>
  <p>red</p>
</div>

Otherwise, even with @scope back in play, I'd still have to use a build tool (or something) to generate an ID for the upper bound of the scope.

Activity

  1. mirisuzanne commented on Sep 13, 2021

    @mirisuzanne
    Contributor

    If I understand this right, the new feature required for this is a :style-parent pseudo-class (:style-root? :style-host?) which:

    • For stylesheets in the document <head> refers to the document root.
    • For nested stylesheets, refers to their parent element.

    I don't see any particular reason it should be restricted to use in @scope if we add it. Could also be used for basic child/descendant selectors, or the :in() pseudo-class. I'm not sure if that's feasible from an implementation perspective, but it's an interesting idea.

  2. dfabulich commented on Sep 13, 2021

    @dfabulich
    Author

    As is typical for spec bugs, I think I've got two ideas piled into one:

    1. I've got a problem: I want to be able to scope styles to the nested <style> element's parent.
    2. I suggest a solution: A new pseudo-class :style-parent (or :style-root or :style-host, yeah) that would refer to the parent element of a nested <style>. (As you point out, that would not be meaningful for stylesheets in the <head>, so presumably in that case we'd want it to refer to :root.)

    If :style-parent isn't feasible for some reason, I'd still wish for some solution to the problem. I guess I could try to invent a handful of other solutions…? (The scoped attribute <style scoped> could literally be another alternative, for example.)

  3. mirisuzanne commented on Sep 13, 2021

    @mirisuzanne
    Contributor

    Right. But I think one of the issues with <style scoped> is that it has backwards-compatibility problems. Browsers that don't understand the scoped attribute will continue to apply those styles globally (the current behavior) — which is not the ideal fallback here.

    I like the pseudo-class idea because it avoids that issue, while building on top of the more flexible CSS-selector driven approach to @scope.

  4. Malvoz commented on Oct 14, 2021

    @Malvoz
    Contributor

    one of the issues with <style scoped> is that it has backwards-compatibility problems. Browsers that don't understand the scoped attribute will continue to apply those styles globally

    Couldn't authors just use a polyfill (i.e. https://github.com/samthor/scoped)?

  5. Malvoz commented on Oct 14, 2021

    @Malvoz
    Contributor

    Going a bit off-topic (feel free to hide the comment as such):

    People are wanting to scope IDREFs in HTML: https://discourse.wicg.io/t/relative-element-references-in-html/5627/, someone suggested a refscope attribute, but I wonder - iff an attribute to scope IDREFs is a viable option - couldn't scoped be extended to apply to HTML elements for IDREF scoping? Or is it a bad idea to have one attribute scope different things depending on which element it is applied to?

  6. bitdivine commented on Nov 1, 2021

    @bitdivine

    Regarding the backwards compatibility issue, would it be possible to define a CSS selector that refers to the current location of a style tag? If the browser does not recognize it, the CSS selector would match nothing, rather than everything.

    That way we could have:

    <some-parent>
      <style>
        @here button {some css}
      </style>
      <button>CSS APPLIES HERE</button>
    </some-parent>
    
  7. bitdivine commented on Nov 1, 2021

    @bitdivine

    Regarding the issue of not wanting CSS to apply to all child elements, or "toroidal css", is that not a separate issue from local scoping? It feels as if it should be possible to define selectors indicating "style this element but not its children" (non-inherited styles) or "style this element like its parent" (explicit inheritance of normally non-inherited styles) but that trying to combine inheritance constraints with local scoping makes things complicated.

  8. mirisuzanne commented on Nov 1, 2021

    @mirisuzanne
    Contributor

    @bitdivine The current scope proposal (and this thread) do not have any impact on inheritance. The donut scope applies to selector targeting only.

    I do like the approach of a syntax for pointing to style location, whatever form that might take.

    @Malvoz The problem is not for authors that want to use the new feature, but for legacy sites that already have nested style tags which apply globally. Authors can recreate a scoped attr using a polyfill, but any browser support for that would break legacy styles, and that's not an option. There's no way to polyfill opting-out all legacy sites from a new feature.

  9. mirisuzanne commented on Sep 21, 2022

    @mirisuzanne
    Contributor

    I think this should be resolved by a combination of:

    The first one there allows scoped imports using @import (which we could propose to the WHATWG as an attribute, similar to the proposed layer attribute). The second means you can get the desired behavior by using the @scope rule in the nested style sheet, without waiting for an HTML attribute:

    <div>
      <style>
        /* scoped to the div, since no scope root selector is given */
        @scope { p { color: red; } }
      </style>
      <p>red</p>
    </div>

    Closing this issue as accepted by those resolutions. If we want to work on an additional scope attribute for HTML, that will need to happen in the WHATWG rather than the CSSWG.

  10. yisibl commented on Oct 27, 2022

    @yisibl
    Contributor

    @andruud As far as I know, this is not currently implemented in Chrome, can you implement the new behavior in Chrome?

    Finally, we could allow @scope without any selector clauses, which would scope the styles to the parent of the stylesheet's owner node (or the containing tree for constructable stylesheets with no owner node).
    https://github.com/oddbird/css-sandbox/pull/22/files#diff-959903105b7abdfb2fa2540f104fdd8d7f347e6f339814fdf5e57f7e65f235e9

    <div>
      <style>
        @scope {
          p { color: red; }
        }
      </style>
      <p>this is red</p>
    </div>
    <p>not red</p>

    That would be equivalent to:

    <div id="foo">
      <style>
        @scope (#foo) {
          p { color: red; }
        }
      </style>
      <p>this is red</p>
    </div>
    <p>not red</p>
  11. andruud commented on Oct 31, 2022

    @andruud
    Member

    @yisibl Right, yes, the current Chrome prototype predates the resolution add that kind of scoping. It will be added eventually. I filed crbug.com/1379844 if you want to follow that for updates.

  12. yisibl commented on Oct 31, 2022

    @yisibl
    Contributor

    @andruud Thanks! I am very much looking forward to the implementation of this feature.

  13. added a commit that references this issue on Feb 17, 2023
    bd711bf
  14. added a commit that references this issue on Feb 17, 2023
    086f663
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions