[csswg-drafts] [css-selectors] Lexical Scoping (#4061)

chriseppstein has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-selectors] Lexical Scoping ==
https://drafts.csswg.org/selectors/

A common complaint about CSS is that everything is global. 

I know of at least a couple community proposals that attempt to work around this issue, but they seem to introduce javascript as an intermediary.

* https://github.com/w3c/csswg-drafts/issues/3714
* https://github.com/w3c/webcomponents/issues/759

I understand that web components have their own notion of a scope local to the component. But this doesn't address the notion of global scope, it just reduces the document surface and the number of selectors in the global scope. There's still no mechanism to address a naming collision.

So why not allow stylesheets and web pages to opt into lexical scoping for name references?

### Example of global css consumed into a namespace:

```css
/* navbar.css */
#navbar {
  /* main container */
}
.element {
  /* stuff contained by the navbar */
}
```

```html
<!-- unscoped.html -->
<link rel="stylesheet" href="navbar.css">
<aside>
   <ol id="navbar"> <!-- matches #navbar in the global namespace -->
      <li class="element">Home</li>  <!-- matches .element in the global namespace -->
  </ol>
</aside>
```

```html
<!-- scoped.html -->
<link rel="stylesheet" href="navbar.css" ident-namespace="nav">
<aside>
  <!-- using the html namespace sigil here... is that a bad idea? -->
   <ol id="nav:navbar">  <!-- matches, doesn't match #navbar in the global namespace defined by other css files -->
      <li class="nav:element">Home</li>  <!-- matches, doesn't match other .element in the global namespace defined by other css files -->
  </ol>
</aside>
```

### Example of lexically scoped, namespaced css

```css
/* navbar.css */
@ident-namespace local;
#navbar {
  /* main container */
}
.element {
  /* stuff contained by the navbar */
}
```

```html
<!-- unscoped.html -->
<link rel="stylesheet" href="navbar.css">
<aside>
   <ol id="navbar"> <!-- matches #navbar in the global namespace so the idents in navbar.css don't match here.  -->
      <li class="element">Home</li>  <!-- matches .element in the global namespace so the idents in navbar.css don't match here. -->
  </ol>
</aside>
```

```html
<!-- scoped.html -->
<link rel="stylesheet" href="navbar.css" ident-namespace="nav">
<aside>
   <ol id="nav:navbar">  <!-- matches #navbar in the nav namespace -->
      <li class="nav:element">Home</li>  <!-- matches .element in the nav namespace -->
  </ol>
</aside>
```

### Example of css involving multiple namespaces

```css
/* buttons.css */
@ident-namespace local;
.button { }
```

```css
/* links.css */
@ident-namespace local;
.link {}
```

```css
/* call-to-action.css */
@import url(button.css) as buttons; <!-- should this namespace get exported? -->
@import url(link.css) as links; <!-- should this namespace get exported? -->
@ident-namespace local;
/* using the css namespace sigil here... is that a bad idea? */
.cta .buttons|button.links|link {
  /* styles for elements having both of these classes */
}
```

```html
<!-- scoped.html -->
<link rel="stylesheet" href="buttons.css" ident-namespace="buttons">
<link rel="stylesheet" href="links.css" ident-namespace="links">
<link rel="stylesheet" href="call-to-action.css" ident-namespace="marketing">
<aside class="marketing:cta">
   <a href="signup.html" class="buttons:button links:link"> Sign Up! </a> <!-- matches the selector defined in call-to-action.css -->
</aside>
```

### Example of multiple namespaces in a single file (concatenation) 

```css
/* all.css */
@ident-namespace buttons {
  .button { }
}

@ident-namespace links  {
  .link { }
}

@ident-namespace call-to-action {
  .cta .buttons|button.links|link {
    /* styles for elements having both of these classes */
  }
}
```

```html
<!-- scoped.html -->
<link rel="stylesheet" href="all.css" ident-namespace="buttons:buttons links:links call-to-action:marketing">
<aside class="marketing:cta">
   <a href="signup.html" class="buttons:button links:link"> Sign Up! </a> <!-- matches the selector defined in call-to-action.css -->
</aside>
```

## Open Questions:

* Should this be applied to other idents like `@keyframes` and grids? (Probably yes)
* Can there be a way to specify a reference to an ident namespace for a url without fetching the resource there?
* If we allow exporting namespaces via `@import`, it seems like we'd need to allow nested scope references. E.g. `.scope-1|scope-2|some-class` as well as nested `@ident-namespace { }`
* Is there any reason to try to merge this notion of an identifier namespace with the xml `@namespace` directive? (Probably not)
* How to consume multiple namespaces via a single `@import`.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/4061 using your GitHub account

Received on Wednesday, 26 June 2019 19:09:40 UTC