1

How can I handle nested SCSS rules, which expand on a base style, when dealing with the CSS Modules to import styles to the local component?

In my case, I have the following two SCSS files:

icon.scss

.my-icon {
  // base styles for an icon
}

button.scss

.my-button {
  ...
  .my-icon {
    // special styles when an icon is in a button
  }
}

Which I then import into their respective components:

MyIcon.vue

<template><i class="my-icon" /></template>
<style lang="scss" module>
@import '/path/to/icon.scss'
</style>

MyButton.vue

<template><button class="my-button"><slot /></button></template>
<style lang="scss" module>
@import '/path/to/button.scss'
</style>

The trouble is that the nested .my-icon class, in 'button.scss', generates a different hash ('._2XJ5') than the root .my-icon class, in 'icon.scss' (._2UFd). So, when I attempt to embed an icon into a button I get an output that looks like this:

<button class="._3S2w"><i class="._2UFd" /></button>

Which is correct, but the "special styles" for an icon in a button are not applied, because that class was generated as a different hash.

How do I make sure the hash value for '.my-icon' always comes out the same?

5
  • I haven't seen vanilla CSS nested like that. AFAIK only Less, SASS or other CSS preprocessors understand that, but not CSS Commented Feb 27, 2019 at 17:11
  • You cannot nest rules in CSS - this will only work when you're using SASS / LESS. Are you using webpack and single file components vuejs.org/v2/guide/single-file-components.html ? If so, in your single file component's <style> tag you should be able to add a <style lang="scss"> and have it work with SASS styling rules. Though, I've only worked with Vue in a Laravel Mix environment, so you may need some additional dependencies / webpack configuration to make that part work. Also, if you have SASS enabled in your component, make sure that those components actually have the classes. Commented Feb 27, 2019 at 17:25
  • Oops - yes, it is SASS. The two .my-icon classes are generating different hashes in the end code, so the nested icon component doesn't pick up the proper style. Commented Feb 27, 2019 at 17:25
  • When you are using scoped styles (<style scoped>) in your component, only that component will have those styles applied to it, not even nested components will have them applied, so if you want to style nested components from parent, scoped styles won't work (if you're using them). Commented Feb 27, 2019 at 17:28
  • Made an edit to hopefully make things more clear. Commented Feb 28, 2019 at 0:43

1 Answer 1

3

Somewhere, hidden deep in the Vue loader, the documentation talks briefly about how you can escape the scoped styling. The solution is to use a /deep/ selector, which is preprocessed by scss to give everything behind it no hash. There is something similar in normal css, but it is somewhat unrelated.

Say we have our my-button component and want to style my-icon classes inside it, we can do the following:

<template>
  <div>
    <slot></slot>
  </div>
</template>

<style lang="scss" scoped>
/deep/ .my-icon {
  background: red;
}
</style>

The following should generate something like the following. It is still scoped within your component, but .my-icon does not have to be part of your component. In this case, it could be inside the slot for example.

[data-v-f3f3eg9] .my-icon {
  background: red;
}
Sign up to request clarification or add additional context in comments.

3 Comments

This looks promising; I'll be able to try it soon. I'm using module instead of scoped and @import from an external SCSS file - are you aware if the same holds true?
I am not sure. I only figured out about the /deep/ earlier this month when a co-worker put it in a merge request and I had no clue what it did. It is pretty nice though.
Doesn't look like /deep/ works with module. :( At least with a file import, I just get a "/deep/" outputted in my file. Bummer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.