How do we resolve style conflicts during development

  1. Increase the depth of CSS style selectors and increase the weight of styles.
  2. Use! Important increases the weight of the style to be applied.
  3. Give each style a unique name so that it doesn’t overlap.
  4. Set a nameSpace for the current module to distinguish it from other modules.

The above four methods 1 and 2 essentially override styles, while 3 and 4 fundamentally avoid the possibility of style overwriting.

The CSS Module takes the third approach. Classes are automatically renamed when the page is finally built, ensuring that all classes are not renamed.

What is a CSS Module

Official documents:

CSS files in which all class names and animation names are scoped locally by default.

CSS Modules are not an official specification or a mechanism for browsers, but a process in a build process. (Build usually requires the help of WebPack or Browserify). With the help of the build tool, you can scope the name of the class or the name of the selector. (Similar to namespaces).

CSS Modules just add local scope and Module dependencies, which are exactly what web components need most. This ensures that the style of one component does not affect other components.

Background of the CSS Module

Modules in project development are units that can be combined, decomposed, and replaced. We split the code according to certain rules and logic, and decomposed it into combinable and replaceable units to maximize code reuse. In CSS, in addition to code reuse, it is more important to solve the problem of local scope, that is, to avoid global style contamination

What problems does the CSS Module solve?

Global contamination can cause a number of confusing problems. For example, in the project, the style of an element has been defined, but now there is a requirement to redefine the style of the element, but the global has been defined. In this case, we have several options: Important (add an important priority), inline (write an in-line style), or write a complexity selector.

As a project gets bigger and harder to maintain, it can easily lead to naming confusion.

To avoid style name conflicts, we write more and more complex selectors, and then longer and longer names. Without a naming convention for styles, the code becomes increasingly difficult to maintain. This tends to lead to less and less clear code hierarchies. The more difficult it is to reuse a piece of code. It can be difficult to find styles that you want to reuse from thousands of pieces of code. And because of the increasing complexity of the selectors and the increasing length of the names, the code compression is not complete. Long class names cannot be used to ensure that the class name is unique.

  • Global pollution
  • Named chaos
  • The hierarchy is not clear
  • Code is hard to reuse
  • Code compression is not thorough

Nested selectors that are too deep

In order to solve the problem of global style conflict, we have to introduce some special namespac to distinguish scopes, but often some namespace names are not clear enough, so that the next style will not cover, we have to add a new namespace to distinguish scopes. An element may end up looking something like this

.wrap .table .row .cell .content .header .title {
  padding: 10px;
  font-weight: 700;
}
Copy the code

Using seven selectors on the display of the previous element causes the following problems:

  • As you can see from the parsing rules of CSS selectors, the deeper the hierarchy, the more comparisons are made. Of course, in more cases, the nesting level may be deeper, and the class selector is used only here, while the ID selector may have more impact on the rendering of the entire page.

  • Added unnecessary byte overhead

  • Semantically confusing, when there are too many generic class names like Content, title, and item in a document, it can take a long time to figure out which element they are used for

  • Poor scalability, the more constraints, the worse the scalability, may be due to changing requirements and extensive rewriting of style files

    For CSS rendering rules, see this article to explore CSS parsing principles

How to use the CSS Module?

CSS Modules are used pretty much the same in different frameworks. Today we mainly talk about the use of CSS Module in Vue

CSS Modules need to be used with build tools. So, the Vue CLI build tool is Webpack. Version: @vue/ CLI 4.4.1

  1. Configure the CSS Module in vue.config.js
/ / CSS - loader upgrade after v3 using CSS. RequireModuleExtension instead of CSS. The modules
    css: {
        // Whether to use CSS ExtractTextPlugin
        extract: true.// Enable CSS source maps
        sourceMap: true.requireModuleExtension: true
    },
Copy the code
  1. Once configured, we can use the CSS Module within the component. The usage method is as follows:
/ / <style module>. Shapes__title {color: #000; margin-top: 10px; } </style>Copy the code

The vUE official documentation explains the function of the Module as follows:

This Module feature directs the Vue Loader to inject CSS Module local objects into the component as a calculated property named $style. You can then use it in the template via a dynamic class binding.

Classes declared using CSS Modules in templates:

<template> <div class="wrap"> <! <h2 :class="$style.shapes__title">CSS Module</h1> </div> </template>Copy the code
  1. Basic syntax for CSS Modules:

CSS Modules subscope and global scope.

The two are distinguished by :local() and :global(). Because CSS Modules have local scopes by default, :local() is omitted by default. Therefore, the CSS part of the above example could also be written like this:

<style module>
:local(.shapes__title) {
    color: #000;
    margin-top: 10px;
}
</style>
Copy the code

To expose a style globally, use :global () :

<style module>
/* 使用 CSS Modules */
.shapes__title {
    color: #000;
    margin-top: 10px;
}
:global(.title){
  color: #333;
}
</style>
Copy the code

Note that styles decorated with :global() are not renamed. Global styles are assigned directly to class without class binding.

<template> <div class="hello"> <! Class ="$style.shapes__title">CSS Module</h1> <h2 class="title"> </div> </template> <style module> /* Use CSS Modules */. Shapes__title {color: #000; margin-top: 10px; } :global(.title){ color: #333; } </style>Copy the code

Composes: the combination of classes

The CSS Module can combine the styles of two selectors. That is, one selector can inherit the styles of another selector. This is done through comPoses. Composes the class of both sources:

  • Combines the class of the current stylesheet
.shapes__title {
    color: #000;
    margin-top: 10px;
}
.box{
    font-size: 16px;
    composes: shapes__title;
}
Copy the code
  • The class of the combined import stylesheet
// common.less .title { font-size: 14px; font-weight: 700; color: #333333; } .box__title { font-size: 16px; composes: title from '.. /assets/styles/common.less'; }Copy the code

Use in components. Box.box__title

<template> <div class="hello"> <! <h2 class="title"> Hello </h2> <h3 :class="$style.box"> comPoses: Class Combines the current stylesheet's class</h3> < H3 :class="$style.box__title"> comPoses: Class combines the import stylesheet's class</h3> </div> </template>Copy the code

Note: in the CSS Module, you cannot use compose github.com/css-modules…

CSS Module author mentioned in Issues /261 “Composition works differently to mixins. It does not mutates rules, just concatenates names.”

Example Set the rename rule

The CSS Module automatically renames its class. We can set rules for renaming during development

Rules are set through the configuration file:

    / / CSS - loader upgrade after v3 using CSS. RequireModuleExtension instead of CSS. The modules
    css: {
        // Whether to use CSS ExtractTextPlugin
        extract: true.// Enable CSS source maps
        sourceMap: true.// Because loaderoptions. CSS is configured, we need to point out that requireModuleExtension is the default value, though
        requireModuleExtension: true.loaderOptions: {
            css: {
                modules: {
                    // Format class name: name is the name of the current file, local is the name of the currently defined class, and hash is a string of 5 characters generated from the hash
                    localIdentName: '[local]_[hash:base64:5]'}}}}Copy the code

Some advice

CSS Modules subtracts existing CSS. To be simple and controllable, you are advised to follow the following principles:

  1. CSS Modules only convert classes and ids. Other label selectors, pseudo-classes, and so on are not converted. It is recommended to use only class.
  2. Keep CSS priorities relatively flat, don’t stack multiple classes, only use one class to define all styles
  3. All styles are reused by comPoses
  4. Not nested, CSS Modules do not use include selectors

Suggestions are just suggestions, CSS Modules don’t force you to do this. Specific according to the actual situation

The resources

  1. Introduction to CSS Modules
  2. Vue CLI CSS Modules
  3. CSS Module for vUE development and configuration