Skip to content

:root Selector should not be scoped #85

@joe223

Description

@joe223

The :root CSS pseudo-class matches the root element of a tree representing the document, it identical to the selector html usually.

But a scoped :root selector dose not match any Element.

With a demonstration which created by @vue/cli 4.0.5:

<!--HelloWorld.vue-->
<style scoped>
:root {
  --font-color: red;
}
h3 {
  color: var(--font-color);
}
</style>

And we got:

<style type="text/css">
[data-v-469af010]:root {
  --font-color: red;
}
h3[data-v-469af010] {
  color: var(--font-color);
}
</style>

h3's font-color wont change, it still inherits from parent element rather than red.

How to resolve?

Scoped :root does not match any element, but a attribute selector with :root do. So, we can get the expected result if changing:

[data-v-469af010]:root { /*balabala*/ }

to

/* proposal A: */
:root { /*balabala*/ }

/* or  */

/* proposal B: */
:root [data-v-469af010] { /*balabala*/ }

I prefer proposal B that will make sure the scoped style rendered as wished. Such as:

<!-- HelloWorld.vue -->
<template>
  <h3>Hello</h3>
</template>

<style scoped>
:root {
  --font-color: red;
}
h3 {
  color: var(--font-color);
}
</style>

<!-- another unscoped style in HelloWorld.vue-->
<style>
:root {
  --font-color: blue;
}
</style>

We will get some css code like this:

<style type="text/css">
:root [data-v-469af010] {
  --font-color: red;
}
h3[data-v-469af010] {
  color: var(--font-color);
}
</style>
<style type="text/css">
:root {
  --font-color: blue;
}
</style>

h3 will rendered with red font color as expected.

I'll create a PR if this issue is logical.

Activity

hrobertson

hrobertson commented on Aug 27, 2020

@hrobertson

After noticing the current behaviour I came here with the intention of fixing this. Happy to see you've already submitted a PR 👍

I would question whether the :root selector should remain in the compiled CSS. Surely it is superfluous and can be removed leaving just the attribute selector:

<!-- HelloWorld.vue -->
<template>
  <h3>Hello</h3>
</template>

<style scoped>
:root {
  --font-color: red;
}
h3 {
  color: var(--font-color);
}
</style>

<!-- another unscoped style in HelloWorld.vue-->
<style>
:root {
  --font-color: blue;
}
</style>

Would compile to:

<style type="text/css">
[data-v-469af010] {
  --font-color: red;
}
h3[data-v-469af010] {
  color: var(--font-color);
}
</style>
<style type="text/css">
:root {
  --font-color: blue;
}
</style>

Additionally, I'd like to pre-empt a potential objection to this change which might be something like "You should just use `*` or `::v-deep` instead of `:root`." Consider a .scss file from a 3rd party library that uses the `:root` selector which I want to `@import` within a scoped style block in my component(s). Example:
// styles.scss
:root {
  --font-color: red;
}
<!-- HelloWorld.vue -->
<template>
  <h3>Hello</h3>
</template>

<style scoped>
@import "styles.scss";
h3 {
  color: var(--font-color);
}
</style>

Should compile to:

<style type="text/css">
[data-v-469af010] {
  --font-color: red;
}
h3[data-v-469af010] {
  color: var(--font-color);
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @hrobertson@joe223

      Issue actions

        :root Selector should not be scoped · Issue #85 · vuejs/component-compiler-utils