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

Scoped Style Changes #119

Merged
merged 5 commits into from
Apr 2, 2020
Merged

Scoped Style Changes #119

merged 5 commits into from
Apr 2, 2020

Conversation

yyx990803
Copy link
Member

@yyx990803 yyx990803 commented Jan 21, 2020

Provide more consistent custom CSS extensions in Single File Component scoped styles.

<style scoped>
/* deep selectors */
::v-deep(.foo) {}

/* targeting slot content */
::v-slotted(.foo) {}

/* one-off global rule */
::v-global(.foo) {}
</style>

Rendered

@yyx990803 yyx990803 added breaking change This RFC contains breaking changes or deprecations of old API. 3.x This RFC only targets 3.0 and above sfc Single File Components labels Jan 21, 2020

## One-Off Global Rules

Currently to add a global CSS rule we need to use a separate unscoped `<style>` block. We are introducing a new `::v-global()` pseudo class for one-off global rules.
Copy link
Member

Choose a reason for hiding this comment

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

does this bring any improvement in performance or anything? I find the separate style easier to read and more intuitive because it's just like a regular style tag.
Unless scoped becomes the default but that would be even harder to migrate

Copy link
Member Author

Choose a reason for hiding this comment

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

Technically, yes. For webpack, an extra <style> block becomes a separate module with a whole pipeline (i.e. all the loaders configured for CSS are invoked for this block again). Putting them in the same block improves bundler build performance.

Copy link
Member

@posva posva Jan 22, 2020

Choose a reason for hiding this comment

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

That makes sense, I think it's worth indicating that as a benefit even if it seems to be a marginal gain

@ota-meshi
Copy link
Member

ota-meshi commented Jan 22, 2020

Hi @yyx990803

I have a question about how to use ::v-deep().

How do I write a nesting selector with deep selector?

In Vue.js 2.x, I could write:

.foo ::v-deep .bar {
    & .baz {
        /* ... */
    }
}
.foo  ::v-deep .bar {
    /* ... */
    &--baz {
      /* ... */
    }
}

@yyx990803
Copy link
Member Author

yyx990803 commented Jan 22, 2020

@ota-meshi to convert to the new syntax, just put everything after ::v-deep into its arguments (wrapped with ()) instead:

.foo {
  & ::v-deep(.bar) {
    /* ... */
  }
}

Note that .foo ::v-deep(.bar) and .foo::v-deep(.bar) are equivalent, so the & isn't necessary.

@ota-meshi
Copy link
Member

ota-meshi commented Jan 22, 2020

I'm sorry. I made a mistake in the example code. Then I rewrote the question.

The code I want to ask is:

.foo ::v-deep .bar {
    & .baz {
        / * ... * /
    }
}

@Justineo
Copy link
Member

I'm afraid the function syntax won't play well with nesting as the old "combinator" did. As I understand, the whole selector inside ::v-deep() cannot be nested.

@Justineo Justineo closed this Jan 22, 2020
@Justineo Justineo reopened this Jan 22, 2020
@Justineo
Copy link
Member

Oops. Sorry for closing this by mistake.

@ota-meshi
Copy link
Member

Does that mean nested selectors after ::v-deep() are not supported?
If so, I think it is good to indicate to md file that it cannot support it.

I like the new syntax than the old syntax, which disguised the pseudo-class as a combinator.

@cawa-93
Copy link

cawa-93 commented Jan 22, 2020

The previous syntax looks a bit more flexible. Correct me if I'm wrong.

Let's say how the new syntax can be matched with :is() CSS pseudo-class function?

<style scoped>
::v-deep :is(header, footer, p) {
    /* ... */
}
</style>

Or nested selectors with some preprocessors

<style scoped lang="scss">
::v-deep {
    header, footer, p {
        /* ... */
    }
}
</style>

@yyx990803
Copy link
Member Author

yyx990803 commented Jan 23, 2020

@cawa-93

Your first example can be written as:

::v-deep(:is(header, footer, p)) {
    /* ... */
}

While for nesting, the new syntax is indeed a bit less convenient. Maybe we can keep the special case of ::v-deep as a combinator for nesting usage?

@cawa-93
Copy link

cawa-93 commented Jan 28, 2020

Current syntax is ideal for scenarios when you want to mark a single rule (selector + styles) as deep or global.

However, how about scenarios when you need to mark more than one group of rules? I do not know how this scenario is common in the community, but if it is in demand then why not implement the following syntax:

<template> ... </template>

<style>
/* Global styles (as in Vue 2)*/
</style>

<style scoped>
/* Scoped styles */
</style>

<style deep>
/* Scoped deep styles */
</style>

<style slotted>
/* Scoped slotted styles */
</style>

As far as I understand it corresponds to the syntax of Vue 2


We later switched to `/deep/`, which was once an actual proposed addition to CSS (and even natively shipped in Chrome), but later dropped. This caused confusion for some users, since they worry that using `/deep/` in Vue SFCs would make their code not supported in browsers that have dropped the feature. However, just like `>>>`, `/deep/` is only used as a compile-time hint by Vue's SFC compiler to rewrite the selector, and is removed in the final CSS.

To avoid the confusion of the dropped `/deep/` combinator, we introduced yet another custom combinator, `::v-deep`, this time being more explicit that this is a Vue-specific extension, and using the pseudo-class syntax so that any pre-processor should be able to parse it.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
To avoid the confusion of the dropped `/deep/` combinator, we introduced yet another custom combinator, `::v-deep`, this time being more explicit that this is a Vue-specific extension, and using the pseudo-class syntax so that any pre-processor should be able to parse it.
To avoid the confusion of the dropped `/deep/` combinator, we introduced yet another custom combinator, `::v-deep`, this time being more explicit that this is a Vue-specific extension, and using the pseudo-element syntax so that any pre-processor should be able to parse it.


The previous versions of the deep combinator are still supported for compatibility reasons in the current [Vue 2 SFC compiler](https://github.com/vuejs/component-compiler-utils), which again, can be confusing to users. In v3, we are deprecating the support for `>>>` and `/deep/`.

As we were working on the new SFC compiler for v3, we noticed that CSS pseudo classes are in fact semantically NOT [combinators](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators). It is more consistent with idiomatic CSS for pseudo classes to accept arguments instead, so we are also making `::v-deep()` work that way. The current usage of `::v-deep` as a combinator is still supported, however it is considered deprecated and will raise a warning.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
As we were working on the new SFC compiler for v3, we noticed that CSS pseudo classes are in fact semantically NOT [combinators](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators). It is more consistent with idiomatic CSS for pseudo classes to accept arguments instead, so we are also making `::v-deep()` work that way. The current usage of `::v-deep` as a combinator is still supported, however it is considered deprecated and will raise a warning.
As we were working on the new SFC compiler for v3, we noticed that CSS pseudo elements are in fact semantically NOT [combinators](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators). It is more consistent with idiomatic CSS for pseudo elements to accept arguments instead, so we are also making `::v-deep()` work that way. The current usage of `::v-deep` as a combinator is still supported, however it is considered deprecated and will raise a warning.

::v-deep .bar {}
```

Instead, use it as a pseudo class that accepts another selector as argument:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Instead, use it as a pseudo class that accepts another selector as argument:
Instead, use it as a pseudo element that accepts another selector as argument:


Notice the `-s` postfix which makes it target slot content only.

- New pseudo class `::v-global()` can be used to apply global rules inside a `<style scoped>` block:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- New pseudo class `::v-global()` can be used to apply global rules inside a `<style scoped>` block:
- New pseudo element `::v-global()` can be used to apply global rules inside a `<style scoped>` block:

@yyx990803
Copy link
Member Author

@Justineo can you make it into a single PR to the scope-styles-changes branch?

@Justineo
Copy link
Member

Justineo commented Feb 3, 2020

@yyx990803 Sure

@thedamon
Copy link

thedamon commented Mar 15, 2020

Current syntax is ideal for scenarios when you want to mark a single rule (selector + styles) as deep or global.

However, how about scenarios when you need to mark more than one group of rules? I do not know how this scenario is common in the community, but if it is in demand then why not implement the following syntax:

Evan mentioned having one style block is better for webpack performance as each block would be a separate module.

It's also very nice to colocate rules that are conceptually related to each other within the same style block (similar to the readability benefits of the composition API) and why we don't have multiple template tags to cover different scenarios.. we have v-if instead

@yyx990803 yyx990803 added the final comments This RFC is in final comments period label Mar 25, 2020
@yyx990803
Copy link
Member Author

This RFC is now in final comments stage. An RFC in final comments stage means that:

The core team has reviewed the feedback and reached consensus about the general direction of the RFC and believe that this RFC is a worthwhile addition to the framework.
Final comments stage does not mean the RFC's design details are final - we may still tweak the details as we implement it and discover new technical insights or constraints. It may even be further adjusted based on user feedback after it lands in an alpha/beta release.
If no major objections with solid supporting arguments have been presented after a week, the RFC will be merged and become an active RFC.

@b-strauss
Copy link

b-strauss commented Dec 18, 2020

I think the ability to nest is very important and should not be removed. While everything that can be done with the old ::v-deep can be done with ::v-deep() sometimes the result can be rather cumbersome.

In some cases you have third party components that you have no control over, but you want to customise them. So you have to overwrite many styles in the scoped child component. Until now these styles could all be written in one block. With the new system this does not work anymore.

.slider::v-deep
  .vue-slider-rail
    background-color: transparent

  .vue-slider-dot
    cursor: pointer

  .vue-slider-process
    background-color: transparent
    border-radius: 0

    &::after
      content: ''
      display: block
      position: absolute
      top: 0
      left: 0
      right: 0
      bottom: 0

  .vue-slider-process,
  .vue-slider-dot,
  .vue-slider-mark
    z-index: auto

  .vue-slider-mark-step
    display: none

  .vue-slider-dot-tooltip
    pointer-events: none

  .vue-slider-dot-tooltip-top
    top: 0

Instead you have to convert it to this which is not nice:

.slider::v-deep(.vue-slider-rail)
  background-color: transparent

.slider::v-deep(.vue-slider-dot)
  cursor: pointer

.slider::v-deep(.vue-slider-process)
  background-color: transparent
  border-radius: 0

.slider::v-deep(.vue-slider-process::after)
  content: ''
  display: block
  position: absolute
  top: 0
  left: 0
  right: 0
  bottom: 0

.slider::v-deep(.vue-slider-process),
.slider::v-deep(.vue-slider-dot),
.slider::v-deep(.vue-slider-mark)
  z-index: auto

.slider::v-deep(.vue-slider-mark-step)
  display: none

.slider::v-deep(.vue-slider-dot-tooltip)
  pointer-events: none

.slider::v-deep(.vue-slider-dot-tooltip-top)
  top: 0

I don't think v-deep's nesting functionality should be deprecated or removed.

@soulsam480
Copy link

Hii, I think the new selectors have some issues when used with BEM and scss.

example::

with ::v-deep

::v-deep .b-user-card {
  width: 100%;
  padding-bottom: 16px;
  &__profile {
    p {
      margin: 0 0 4px;
    }
  }
  &__info {
    p {
      margin: 0 0 8px;
    }
  }
  .q-card__section--vert {
    padding-bottom: 0 !important;
  }
}

This old syntax worked perfectly with BEM. But with the new :deep() syntax

.b-user-card {
  width: 100%;
  padding-bottom: 16px;
  &::v-deep(__profile) {
    p {
      margin: 0 0 4px;
    }
  }
  &::v-deep(__info) {
    p {
      margin: 0 0 8px;
    }
  }
  ::v-deep(.q-card__section--vert) {
    padding-bottom: 0 !important;
  }
}

it worked correctly for the last line ::v-deep(.q-card__section--vert), but for others it didn't work. Hii @yyx990803 am I missing something ? Please have a look into this. Thanks.

@mtskf
Copy link

mtskf commented Apr 7, 2021

I've found these below don't work...

<style deep>
/* Scoped deep styles */
</style>

<style slotted>
/* Scoped slotted styles */
</style>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.x This RFC only targets 3.0 and above breaking change This RFC contains breaking changes or deprecations of old API. final comments This RFC is in final comments period sfc Single File Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants