background

With the rapid development of front-end engineering, CSS as a non-programming language has many problems when it comes to modularity:

  1. Unable to modularize styles

Component-based development is the core of front-end modularization, but the idea of native CSS is cascading styles, which is not friendly to components and will cause problems such as component styles being overwritten.

So we want styles to be scoped, that is, within the scope of a component, component styles apply only to that component.

  1. Named chaos

In large projects, multi-party collaboration often leads to naming confusion, which leads to inconsistent code styles and style conflicts.

  1. High repetition

Component development also means that a lot of style code is repetitive and redundant in a project.

So we want to have a mechanism to import and export CSS and reuse styles.

There are many solutions to CSS modularization. In the Vue project, the two supported by Vue Loader are Scoped CSS and CSS Modules.

Scoped CSS is supported by Vue Loader by default and therefore can be used directly in Vue projects;

CSS Modules are considered by the Vue Loader as an alternative to emulating Scoped CSS and also provide integration support, but require some configuration to be written.

// vue.config.js
// With vue-cli, you can configure directly in this file without exposing the webpack configurationmodule.exports = {
    css: {
        // Enable CSS Modules
        requireModuleExtension: true;
        loaderOptions: {
            // Pass configuration options to loader
            css: {
                modules: {
                    // Custom class naming rules
                    // In our project, the name of the class changes according to the environment. In the development environment, the file path of the class will be displayed for debugging, and in other environments, the hash value will be encapsulated
                    localIdentName: process.env.NODE_ENV === 'development' ? '[path][name]__[local]' :                          '[hash:base62:8]',}}}}}Copy the code

It is important to note that neither of these solutions is an official SPECIFICATION for CSS, but we use build tools such as Webpack or scaffolding to load the corresponding Loader and convert the CSS code to achieve modularity.

CSS Modules

The principle of

CSS Modules The principle of CSS modularization is to generate a unique name for a class according to the class naming rules defined in the Config file, so as to achieve scope isolation.

  • Before the
<style module>
.example {
  color: red;
}
</style><template>
  <div class="example">hi</div>
</template>
Copy the code
  • After the transformation
<! The conversion rules are self-defined.
<! Hash hash hash hash hash hash hash hash hash hash
<style module>
._1TdbN_VT {
  color: red;
}
</style><template>
  <div class="._1TdbN_VT">hi</div>
</template><! -- In the development environment, the source will be displayed -->
<style module>
.src-views-login-Index__example {
  color: red;
}
</style><template>
  <div class=".src-views-login-Index__example">hi</div>
</template>
Copy the code

The rules

  1. Use in Vue projects

Declare the Module feature in the style tag:

<style module>.</style>
Copy the code

After declaring the Module feature, the Vue Loader generates a $style calculation property that injects CSS Modules objects into the component. We can use this calculation property to access CSS Modules objects in template and JS.

<template>
    <! $style = 'red'; $style = 'red'; $style = 'red';
  <p :class="$style.red">
    This should be red
  </p>
</template>
Copy the code
  1. 4. Composition
.classA {
    color: green;
    background: red;
}
​
.classB {
    composes: classA;
    color: red;
}
Copy the code
  • Use the composes rule to combine other classes and their styles

  • Note that comPoses declare rules that must precede their own rules;

    Multiple classes can be combined at once, separated by Spaces, but they must all be local scoped

  1. Dependencies: Implement Dependencies through imports

If you need to combine styles from other modules, you can import them:

.classC {
    composes: classA from './style.css'
}
Copy the code
  • Note that CSS Modules default to no order between classes when combining classes in different CSS files, so make sure there are no rule conflicts between classes when importing them
  • There can be no circular dependencies between composite classes
  • Composes are implemented by using the loader to process the import CSS file into the ICSS middleware and export an object that holds the mapping of all local class names to global class names. In fact, this is also the principle of importing CSS files directly from the JS file

: the global selector

:global() allows selectors declared in parentheses to hit globally, that is, their class names are not wrapped by rules and therefore not scoped.

In a real project, when we want to change the default style of the component library we use, we can use :global() to change the default style of the component library using CSS Modules, but it is better to have a layer of class encapsulation, otherwise it may affect the global style.

Vue3 new features

  1. Custom Module naming
<style module="login">.</style>
Copy the code

Support for naming the module, you can use the module name instead of $style, such as

.

  1. CSS Modules in the combined API

You can use the useCssModuleAPI in setup() to get module objects.

  1. In the CSSv-bind

Support for binding the value of a rule to a value in data in style, for example:

.red {
    color: v-bind(color);
}
Copy the code

Scoped CSS

The principle of

By default, the Vue Loader implements Scoped CSS using PostCSS. The principle is to add a custom attribute to the element hit by the selector in the Scoped style declaration, and then implement Scoped style effects through the property selector.

  • Before the
<style module>
.example {
  color: red;
}
</style><template>
  <div class="example">hi</div>
</template>
Copy the code
  • After the transformation
<! Class name wrapped in custom attributes -->
<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style><template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>
Copy the code

The rules

  1. You can have both global and scoped styles in a Vue file, allowing you to declare both style tags.
<style>
/* global styles */
</style><style scoped>
/* local styles */
</style>
Copy the code
  1. With Scoped CSS, the style of the parent component does not affect the child component because the style is Scoped, that is, the style of the parent component and the child component have their own scope.

    However, for the root element of the child component, its style can still be controlled by the parent component, allowing the parent component to control the layout.

  1. Note that byv-htmlThe DOM content you create is not controlled by Scoped CSS, and if you want to modify the style in it, you can use the depth selector.
  2. Because Scoped CSS is implemented through property selectors, it is best not to mix them with label selectors, which can cause performance problems.

Depth action selector

  1. Depth-acting selectors allow styles from parent components to permeate child components by using descendant selectors.
/* Before conversion */<style scoped>
.a :deep(.b) {
  /* ... */
}
</style>A [data-v-f3f3eg9]. B {/*... * /}Copy the code
  1. Note the difference between a depth-acting selector, which is declared as a global style, and a depth-acting selector, which is declared only to allow the parent component to control the child component style, whereas a global style is applied globally.

  2. In a real project, when we want to change the default style of the component library we are using, we can use the depth selector to change the default style using the Scoped CSS scenario.

  3. Several depth left and right selectors are written:

    • /deep/: obsolete
    • >>>: Can be used when the Sass preprocessor is not used
    • ::v-deep: Used when Sass preprocessors are used

Vue3 new features

  1. Depth action selector

    Discard /deep and >>> and use :deep(.child-class) instead of ::v-deep

  2. Selector: slotted ()

    Slotted (Selector) is supported to control styles in slot

  3. : the global selector ()

    When only certain rules require global effect, it is allowed not to repeatedly declare a globally scoped style tag, but to declare it as a global style using :global(selector).

Comparison of the two

CSS Modules Scoped CSS
Additional configuration is required in vue.config.js Vue Loader is supported by default. No additional configuration is required
Scope isolation is achieved by generating unique class names for elements based on configured class naming rules Scope isolation is achieved by giving elements a custom hash attribute and selecting them using the attribute selector
Declare it in the style tagmodule Declare it in the style tagscoped
Support for importing styles from other modules, support for style combinations /
through:global()To unisolate the scope and make the style global 1. Global styles can be defined so that they are not scoped; 2. You can control the style of child components by hitting them with the depth effect selector

\