Working with nested selectors & vuejs css modules

Viewed 3852

Is it possible to work with nested css selectors when using vuejs css modules?

For example, I want to scope this css (so that id does not affect child components):

.list {
    ...

    .item {
       ...
     }
}

In the documentation I could see only not-nested examples, but is it at all convenient, since I'll need then name them like .list-item which resembles BEM. But if I use BEM there is no point in using css modules, is there?

3 Answers

Yes, it's possible to work with nested css selectors so they will not affect child components; use css modules.

You need to use a preprocessor to enable nesting, either LESS or SASS.

If using Single File Components your component would look something like this

<template>
  <ul :class="$style.list">
    <li :class="$style.item"></li>
  </ul>
</template>

<!--       Or lang="less" -->
<style module lang="scss">
.list {
    ...

    .item {
       ...
     }
}
</style>

Yes, nesting css selectors is called using scss. You will have to setup scss.

Example make your style tag in the vue component:

<style scoped lang="scss">

The scoped attribute tells it to apply only to this component.

In regards to bem you can do stuff like this in scss:

.list {
   //styles-a

   &-item {
      //styles-b
   }
}

which will convert to this in css:

.list {
    //styles-a
}
.list-item {
    //styles-b
}

If you want, for example, override CSS class of some UI library in Vue you can use :global keyword. Let's say you have a n-dropdown component from Naive UI library. And you want to customize it with overriding its native very deeeeeply nested n-dropdown-option-body__prefix--show-icon CSS class only in current component using CSS modules. Here is how you can do it:

<template>
    <n-dropdown :class="$style.menu">
    </n-dropdown>
</template>

<style module>
.menu:global.n-dropdown-menu .n-dropdown-option .n-dropdown-option-body .n-dropdown-option-body__prefix.n-dropdown-option-body__prefix--show-icon {
    margin-left: 33px;
    margin-right: 19px;
}
</style>

In the end you will get selector which looks something like this

.MobileNavMenu_menu_NhSka.n-dropdown-menu .n-dropdown-option .n-dropdown-option-body .n-dropdown-option-body__prefix.n-dropdown-option-body__prefix--show-icon {
    margin-left: 33px;
    margin-right: 19px;
}

So all classes after :global keyword will be untouched by module manipulations.
If .n-dropdown-menu should be a child of menu then :global should have a whitespace from both sides: .menu :global .n-dropdown-menu
Vue will remind you about it with horrible crash

Related