CSS modules Getting Started Tutorial

Source: Internet
Author: User
Tags base64 modifier naming convention css preprocessor
Why introduce CSS Modules

Or you can say, CSS modules for us to solve what pain point. For the past I write Web style experience, specifically, can be summed up as the following points:

Global style conflicts

The process is this: you now have two modules, a, B, you might write your own styles for each of these two modules, such as A.CSS, B.css, and look at the code

// A.jsimport './a.css'const html = '

Here's the style:

/* a.css */.text {    color: red;}/* b.css */.text {    color: blue;}

Import into the Portal app

// App.jsimport A from './A.js'import B from './B.js'element.innerTHML = 'xxx'

Because the styles are uniformly loaded into the portal, the actual styles are combined (here tentatively mix.css) in the order of display:

/* mix.css *//* a.css */.text {    color: red;}/* b.css */.text {    color: blue;}

According to the CSS layout rules, so the following style will overwrite the previous style declaration, the final effect is the text color blue of the rule, this is the global style overlay, the same, which also exists in the js same, so the introduction of modularity, In JS, you can isolate different modules with an immediate execution function expression.

var moduleA = (function(document, undefined){    // your module code})(document)var moduleB = (function(document, undefined){    // your module code})(document)

In the CSS in order to introduce modularity, then can only be namespace achieved through, and this will bring new problems, this will be described below

Selectors with nested levels too deep

In order to solve the problem of global style conflict, we have to introduce some special naming namespace to distinguish scope , but often some name is not namespace clear enough, it will cause to think the next style will not overwrite, it is necessary to add a new namespace to distinguish, Eventually an element might end up with a display style similar to the following:

.widget .table .row .cell .content .header .title {  padding: 10px 20px;  font-weight: bold;  font-size: 2rem;}

Using 7 selectors on the display of the previous element, the following questions are summed up:

    • Depending on the parsing rules of the CSS selector, it is possible to know that the deeper the hierarchy, the more times it will be compared. Of course, in more cases, the level of nesting may be deeper, in addition, the use of the class selector, and the use of class selectors, the whole page may be more impact on rendering.
    • Increased unnecessary byte overhead
    • Semantic confusion, when there are too many in the document, content title and item These generic class names, you may have to spend long time to know exactly which element they are using
    • Poor scalability, more constraints, less extensibility

"Note" CSS rendering rules can refer to this article to explore the principle of CSS parsing

will result in code redundancy

Since CSS does not use a modular function like JS, you may have written a common style class in a CSS file, and you need a style like this in another CSS, and you may write one more time, similar to this

/* a.css */.modal {    position: absolute;    top: 0;    bottom: 0;    left: 0;    right: 0;    z-index: 1;    background-color: rgba(0, 0, 0, 0.7);}.text {    color: red;}/* b.css */.modal {    position: absolute;    top: 0;    bottom: 0;    left: 0;    right: 0;    z-index: 1;    background-color: rgba(0, 0, 0, 0.7);}.text {    color: blue;}

Then when merging into APP.CSS, it will be written two times, although the style will not be affected, but this is actually a kind of waste of bytes, of course, the above situation is entirely possible through the common global style to achieve the purpose, but this code duplication is usually not informed of the situation occurs.

Some solutions

For some of the above issues, there are some solutions, as follows:

CSS Preprocessor (sass/less, etc.)

Sass,less usage here no longer repeat, if not clear, you can consult the relevant information to understand.

The biggest advantage of CSS preprocessor is that it can support the introduction of modules, the use of JS to write CSS, to solve some scope of the confusion and code redundancy problems, but can not be completely avoided. At the same time, there is no solution to the problem of global style conflicts

One of the SASS files is this:

/* app.sass */@import './reset'@import './color'@import './font'

Can actually be compiled after all, is still a file, so inevitably there will be conflict style

BEM (Block Element Modifier)

There is only of problems in computer Science:cache invalidation and naming Things-phil Karlton

BEMis to solve the naming conflict and better semantics of the birth.

BEM noun explanation
    • Block: The logic and page functions are independent of the page components, is a reusable unit, features are as follows:

      • Can be arbitrarily nested combinations
      • Can be placed anywhere on any page without compromising functionality and appearance
      • Reusable, interface can have any number of instances of the same block
    • Element:block component, dependent on block existence (cannot be used if block is out)
    • [optional] Define the appearance and behavior of blocks and element, just like HTML attributes, to make the same block look different

Naming rules

BlockAs the smallest reusable unit, arbitrary nesting does not affect functionality and appearance, naming can be header , and menu so on

<style>    .header { color: #042; }</style><div class="header">...</div>

ElementDependency block exists, there is no separate meaning, naming semantics as close as possible to block, such as title , and so on item

<style>    .header { color: #042; }    .header__title { color: #042; }</style><div class="header">    

ModifierIs the status display of an element, such as,, active currentselected

<style>    .header--color-black { color: #000; }    .header__title--color-red { color: #f00; }</style><div class="header header--color-black">    

Description

    • Block completely independent, can be nested, a header is a block,header under the search box can also be a block
    • There is no way Block__Element-father__Element-son_Modifer to bem this kind of name, only three levels.
    • Modifier can be added to block and element
    • Modifier loads blocks and element as an additional class name, just to change the state and to preserve the original class
A complete example
<form class="form form--theme-xmas form--simple">  <input class="form__input" type="text" />  <input    class="form__submit form__submit--disabled"    type="submit" /></form>
.form { }.form--theme-xmas { }.form--simple { }.form__input { }.form__submit { }.form__submit--disabled { }

Reference Links:

    • Get BEM
    • BEM (Block-element-modifier)
    • How do you look at the naming of BEM in CSS?

BEM solves the problem of module reuse, global naming conflict, and can be extended to a certain extent when used with pre-processing CSS, but it still has its problems:

    • It is very difficult to name the elements that need to be semantically represented in a hierarchy that is deeply nested.
    • For multi-person collaboration, a uniform naming convention is required, which also creates additional effort
CSS Modules

Having said so much, I finally got to the text.

What is CSS Modules

According to the CSS modules repo, this is the case:

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

So CSS modules is not a formal statement or a browser implementation, but a build tool (Webpack or browserify) to enable all classes to reach the scope of a process.

What the CSS Modules solves
    • Global naming conflicts, because CSS modules only cares about the component itself, so long as the component itself is not named conflict, there is no such problem, the class name of a component after it is compiled may be:
/* App.css */.text {    color: red;}/* 编译之后可能是这样的 */.App__text___3lRY_ {    color: red;}

Naming is unique, thus guaranteeing that the global does not conflict.

    • Modular

You can use composes to introduce styles in your own module and the style of another module:

.serif-font {  font-family: Georgia, serif;}.display {  composes: serif-font;  font-size: 30px;  line-height: 35px;}

Applied to elements can be used like this:

import type from "./type.css";element.innerHTML =   `

After that, the compiled template might be something like this:

Introduced from another module, you can write this:

.element {  composes: dark-red from "./colors.css";  font-size: 30px;  line-height: 1.2;}
    • Solve the problem of nesting level too deep

Because the CSS modules only focuses on the component itself, the component itself can be written using a flat class name, similar to this:

.root {  composes: box from "shared/styles/layout.css";  border-style: dotted;  border-color: green;}.text {  composes: heading from "shared/styles/typography.css";  font-weight: 200;  color: green;}
How to use CSS Modules

CSS modules is not limited to which front-end library you use, whether it's react, vue, or angular, as long as you can use the build tool to compile and package.

Below I use webpack as an example, step by step introduce CSS Modules.

Build the most initial application
.├── build│   └── bundle.js├── index.html├── node_modules├── package-lock.json├── package.json├── src│   ├── index.js│   └── styles└── webpack.config.js

Index.js as a program entry, the Styles folder stores style files, with Webpack.config.js as the Webpack configuration file.

// index.jsvar html = `<div class="header">    

Style file:

/* global.css */* {    margin: 0;    padding: 0;}.container {    padding: 20px;}/* index.css */.header {    font-size: 32px;}.title {    border-bottom: 1px solid #ccc;    padding-bottom: 20px;}

Template file:

<!-- index.html --><!DOCTYPE html>

Global installation dependency, configuration execution script:

npm install webpack webpack-cli --save-dev

Package.json

"scripts": {    "build": "npx webpack && open index.html"}

In the console execution npm run build , the result is:

> css-modules-demo@1.0.0 build /Users/yhhu/Documents/coding/css-modules-demo> npx webpack && open index.htmlHash: 5810d2ecd760c08cc078Version: webpack 4.17.1Time: 78msBuilt at: 2018-08-26 15:09:31    Asset      Size  Chunks             Chunk Namesbundle.js  3.97 KiB    main  [emitted]  mainEntrypoint main = bundle.js[./src/index.js] 196 bytes {main} [built]
adding Styles and Loaders

Package.json the ability to work with CSS in Loader

  module: {    rules: [      {        test: /\.js/,        loader: 'babel-loader',        include: __dirname + '/src',        exclude: __dirname + '/src/styles'        },      {        test: /\.css$/,        use: [          { loader: 'style-loader' },          {            loader: 'css-loader',            options: {                     }          }        ]      }    ]  }

Two CSS files introduced in Index.js

// index.jsimport './styles/global.css'import './styles/index.css'const html = `<div class="header">    

After compiling, the result is:

displayed in the browser as:

Extract public styles

You can see build that there is only one in the directory after packaging bundle.js , we are now going to extract the style file

./build/└── bundle.js
    • Installation dependencies
npm install --save-dev mini-css-extract-plugin
    • Modifywebpack.config.js
var MiniCssExtractPlugin = require("mini-css-extract-plugin");modules: {    rules: [        // {        //   test: /\.css$/,        //   use: [        //      { loader: "style-loader" },        //     {        //      loader: "css-loader",        //      options: {                //      }        //     }        //   ]        // },        {            test: /\.css$/,            use: [              {                loader: MiniCssExtractPlugin.loader,                options: {                  publicPath: './build/styles'                }              },              {                 loader: "css-loader",                options: {                                    }              }            ]        }            ]},plugins: [    new MiniCssExtractPlugin({      filename: "[name].css",      chunkFilename: "[id].css"    })],
    • Introduce a style file in a template
<!-- index.html --><!DOCTYPE html>
    • Compile Package

You can see that there is a main.css build

Turn on CSS modules features

The default in the css-loader is not open css modules function, to open can be set modules: true , more can see the official css-loader use method of modification webpack.config.js , as follows:

{    test: /\.css$/,    use: [      {        loader: MiniCssExtractPlugin.loader,        options: {          publicPath: './build/styles'        }      },      {         loader: "css-loader",        options: {            modules: true        }      }    ]}        

index.jsto modify the references in a file:

import './styles/global.css'import Index from './styles/index.css'const html = `<div class=${Index.header}>    

As you can see, it's import a direct file, and now it's a css form of exporting an object, and we can Index print out the object and see what it is:

Directly corresponds to the way we refer, and then we look at main.css what is generated in particular:

* {    margin: 0;    padding: 0;}._2BQ9qrIFipNbLIGEytIz5Q {    padding: 20px;}._3Ukt9LHwDhphmidalfey-S {    font-size: 32px;}._3XpLkKvmw0hNfJyl8yU3i4 {    border-bottom: 1px solid #ccc;    padding-bottom: 20px;}

After synthesizing a file, all class names are hashed, so that the class name is unique, so let's look at inspector the style app in the browser as follows:

In fact, the container style we do not need to convert, because I have fixed it to die on the container, then what should we do?

Global scope

To think of a class name that does not need to be loaded, you can use it :global(className) to wrap it, so the class will not be converted, it will be output as is, and we'll modifyglobal.css

/* global.css */* {    margin: 0;    padding: 0;}:global(.container) {    padding: 20px;}

We'll take a look.main.css

You can see that the .container class has not been converted

Defining a Hash class name

CSS modules By default is [Hash:base64] for the class name conversion, the level of recognition is not high, so we need to customize

To turn on customizations, you can use a configuration parameter localIdentName that is configured as follows:

{   loader: "css-loader",  options: {    modules: true,    localIdentName: '[path][name]__[local]--[hash:base64:5]'  }}

Class name combination

SassWhat do we need to do if we implement a similar inheritance function? The keyword in CSS modules composes allows us to inherit another class, modified index.css as follows:

.red {    color: red;}.header {    font-size: 32px;}.title {    composes: red;    border-bottom: 1px solid #ccc;    padding-bottom: 20px;}

We have added a red class name that title implements inheritance in, and the result after compilation is:

Found one more src-styles-index__red--1ihPk class name, which is the class we inherited above

In addition to inheriting from our own modules, we can also inherit CSS rules from other files, as follows:

We'll styles create a new folder under thecolor.css

/* color.css */.red {    color: red;}.blue {    color: blue;}

And then index.css import it into the file.

/* index.css */.red {    color: red;}.header {    font-size: 32px;}.title {    color: green;    composes: blue from './color.css';    composes: red;    border-bottom: 1px solid #ccc;    padding-bottom: 20px;}

Finally, we will find that the color of the text is green, it can be seen that its own module declaration of the highest priority, if the self-declared to color remove, then the introduction of itself and from other documents introduced by the same declaration how to display it?

The answer is that the claims introduced by itself will have a higher priority.

Summarize

At this point, all the CSS modules usage has been introduced, as for the follow-up and how to apply React , Vue and Angular in, I believe that the above content can know how to write, how to use with the preprocessor to believe that the problem is not big.

Finally, the Code Warehouse library for this article is: Github.com/rynxiao/css-modules-demo

Reference links
    • CSS modules-solving the challenges of CSS at scale
    • GitHub repo
    • What is CSS Modules and why do we need them?
    • Getting Started with CSS Modules
    • Get BEM
    • CSS Modules Usage Tutorial
    • CSS modules using the detailed
    • Explore CSS parsing principles
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.