In front end development, there has always been a principle called “separation of concerns”, which means that technologies are only in their own domain and don’t mix and couple. This principle is straightforward: don’t write inline style and inline script. Keep HTML, CSS, and JavaScript separate and avoid mixing (see introduction to CSS in JS here)

Now, due to the use of various front-end frameworks and packaging tools, our previous separation of concerns has changed into a strategy that is actually implemented in JS.

The framework doesn’t have any special treatment for CSS compared to HTML, and it doesn’t have a JSX-like solution, but there is one interesting solution: CSS-in-JS (although writing CSS in JS feels awkward anyway).

In addition CSS itself programming ability is weak, the community has formed a variety of programs to improve CSS programming ability. I find Postcss more elegant than the others, so I’m going to highlight it here

It is currently based on PostCSS 7.0.32

The basic concept

  • Postcss is a tool for converting CSS using JS plug-ins
  • Postcss is not a preprocessor

Preprocessor refers to the enhancement of CSS capabilities by adding some non-CSS functions (such as nesting and variables), which can be converted into ordinary CSS after processing.

  • Postcss is not a post-processor

Improve existing CSS with rules such as adding browser prefixes

  • Postcss exists as a platform. Plug-ins provided by Postcss can combine various modules to build more complex functions

Demo

  • Any directory NPM init -y

In this way, the name of the project must not conflict with the name of the library, such as webpack, postCSS, which will cause ENOSELF errors when installing the related library

  • Installation-dependent dependencies
    • Css-loader is the ability to import CSS using import in a page
    • Style-loader uses CSS code to generate style tags and place them in the head tag
    • Mini-css-extract-plugin Plugin used to extract CSS

npm i –save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin mini-css-extract-plugin css-loader style-loader @babel/cli @babel/core @babel/preset-env vue-loader vue-template-compiler

npm i –save vue

  • Create two new folderssrcdist, as well asbabel.config.js,webpack.config.jsAnd other relevant documents
/// babel.config.js const presets = [["@babel/env"]]; module.exports = { presets } ... /// webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { entry: './src/index.js', resolve: { extensions: ['.js', '.vue'] }, output: { filename: '[name].js', publicPath: '/' }, mode: 'development', module: { rules: [ {test: /\.js$/, use: 'babel-loader', exclude: /node_modules/}, {test: /\.vue$/, use: 'vue-loader', exclude: /node_modules/}, {test: /\.css/, use: ['style-loader', 'css-loader']} ] }, devServer: { port: '8111' }, plugins: [ new HtmlWebpackPlugin({ template: './src/tpl/index.html' }), new VueLoaderPlugin() ] } ... /// suppose there is an app.vue set as above import '.. /style/app.css';Copy the code

At this point in the JS file, you can import the style file into the page through import. However, since style-loader is used, the style will be written to the

The mini-CSs-extract-plugin can be used, which splits related styles into separate files

/// webpack.config.js const MiniCssExtractPlugin = require("mini-css-extract-plugin"); . {test: / \. CSS /, use: [MiniCssExtractPlugin loader, 'CSS - loader]} / / replace style - loader... plugins: [ ... new MiniCssExtractPlugin({ filename: "[name].css", chunkFilename: "[id].css" }) ]Copy the code

If multiple style files are imported, they will be merged into a single style file and exported as currently set. The contents of these files, however, are simply merged together, and it is entirely up to the style writer to control the contents of each style file

/// app.css .info { font-size: 24px; }... /// color.css .info { color: red; }... /// app.vue import '.. /style/app.css'; import '.. /style/color.css'; . /// The merged style file is as follows. Info {font-size: 24px; } .info { color: red; }Copy the code

BianChengHua

Install related dependencies

npm i -D postcss postcss-loader

Introduce style files through.pcss

. PCSS is a special format file of Postcss

  • The installationpostcss-importTo make the.pcssFiles can be used@importImporting style files

npm i -D postcss-import

You need to add a running configuration file for Postcss, either.postcsrc. Js or postcss.config.js

Module. exports = {plugins: []}Copy the code
  • postcss.config.jsIn addition topluginsIt also has the following parameters:
    • Syntax: Object that provides a parser and a stringalizer
    • Parser: a special syntax parser (e.g., SCSS)
    • 2. A specialized syntax output generator (such as Midas).
    • Map: Sets the map file
    • From: Enter the file name
    • To: Indicates the output file name

However, plugins are commonly used.

{test: /\.pcss$/, use: [ MiniCssExtractPlugin.loader, "css-loader", "postcss-loader" ]}, ... /// mian.pcss @import './app.css'; @import './color.css'; . /// app.vue imports main. PCSS import './main. PCSS ';Copy the code

The PostCSS, for example, is different from the Lass Sass stylus in that it has a self-configuration process, so it has a higher degree of freedom. These gaps can be written yourself, or you can directly use existing community plug-ins that set usage parameters in the PostCSS configuration file

Related to the plug-in

autoprefixer

This is probably the most widely used plugin in PostCSS, automatically recognizing the browser compatibility range and adding the browser style prefix

npm i -D autoprefixer

/// postcss.config.js
let postcssConfig = {};
postcssConfig.autoprefixer = {
    browsers: ['> 1%', 'ff 3']
}

module.exports = {
    plugins: postcssConfig
}
Copy the code
  • Modify main. PCSS as follows
b {
    border-radius:5px;
}
Copy the code

The result after compiling and running is

b {
       -moz-border-radius:5px;
            border-radius:5px;
}
Copy the code

For autoprefixer parameters, use the default Settings. Only the browsers parameter Settings are spoken here because these relate to what is ultimately prefixed.

browsers

Browsers use the Browserslist function to decide whether certain browser prefixes need to be added. Browsers are built with the browserslist documentation. You can set Settings for browser, country, specific platform, and year

> 5% cover 99.5% in US node 10 and node 10.4 since 2015 IE 6-8 not IE <= 8Copy the code

Here’s a list of browsers you’re most likely to encounter on your project

  • Android: Android WebView browser
  • IOS: Safari on iOS
  • Chrome: Google browser
  • ChromeAndroid: Google chrome for android
  • Edge: Microsoft’s Edge browser
  • Internet Explorer: Indicates the Internet Explorer
  • Safari: Safari desktop browser
  • Ff: Firefox browser
  • And_ff: Firefox Android browser
  • And_qq: Android version of QQ browser
  • And_uc: Android version of UC browser

Browsers accept an array, so can be set separately as in the example. The following means that browsers add prefixes to fit android 2.3, ios3.2, Safari3.1, and IE10

‘> 0%’, ‘the Android 2.3’, ‘iOS 3.2’, ‘Safari 3.1’, ‘Internet explorer 10’

  • > 0% : indicates that when you do not want to set up so tedious to specify the browser, you can directly specify a approximate, is I want to support the market what proportion of browsers, this number can be added before the ordinary operators >, >=, <, <=

  • The prefix modifier NOT: indicates that it is not in a range, and you can use cover extends or since for more detailed Settings, including the path specifying what version from what year.

The rounded corners function is only added to FF4. The preceding configuration has the prefix for a specific browser because it is specified for a specific browser version

/// With this set, the resulting styles are not prefixed with Firefox browsers: ['> 1%', 'ff > 4'].Copy the code

When setting a range, you need to specify the range. Do not set ff or not ff directly, because this will cause errors. You need to specify the version

Set browserslist in package.json

In the current version, this setup runs WebPack with a section warning that it is not recommended to set the browser scope in the configuration file. Either add it to package.json or set it to.browserslistrc

/// .browserslistrc > 1% ff > 4 ... Json "browserslist": ["> 1%", "ff > 4"] // This priority is lower than the plugin settingCopy the code

postcss-preset-env

This plugin allows developers to use new features that may be added to future versions of CSS in their current projects, much like writing ES6+ code, but using Babel to convert ES5 code.

Autoprefixer is included in this plugin, and a similar plugin, PostCSS-CssNext, is no longer maintained

npm i –save-dev postcss-preset-env

const PostCssEnv = require("postcss-preset-env");

const postCssEnvConfig = PostCssEnv({
  stage: 2
});

module.exports = {
  plugins: [postCssEnvConfig]
};

Copy the code

Plug-in Parameters

The following describes related parameters based on the official documents:

  • stage: According to the process of the current web standards (mainly is accredited by the w3c standard, so has the function of the in the plug-in are future is likely to be directly added to the contents of the CSS standard) to determine some CSS function need not to need to add, by means of shim can set any number of the 0 ~ 4, without setting this value, This value defaults to 2

    • 0: At this stageUnofficial draft or editorial draft stage, will most likely be deleted
    • 1: This stage is inThe experimental stage, may be set as standard
    • 2: This stage is inPending phaseThis is also the default value of the plugin. Features at this stage can be expected to be added to the future standard
    • 3: This stage is inStable phase, basically has been implemented by browser vendors, can be used directly
    • 4: This stage is inThe standard stage
  • Features: Sets specific CSS functionality separately. For example, if stage is set to 3, you can use this parameter to specify functionality that is stage 2

PostcssPresetEnv ({/* Uses the standard of stage 3, while allowing nesting rules (nesting is standard for stage 1) */ stage: 3, features: {'nesting-rules': true}})Copy the code
  • Browsers: Do not set this parameter by referring to the introduction of Browserslist above

  • InsertBefore/insertAfter: Allows you to run one or more plug-ins before or after the plug-in runs

import postcssSimpleVars from 'postcss-simple-vars'; PostcssPresetEnv ({insertBefore: {'all-property': postcssSimpleVars}})Copy the code
  • Autoprefixer: Set to false to disable autoprefixer. The Autoprefixer and Browsers included with the plug-in can be set here, but are usually built with the default
Const postCssEnvConfig = PostCssEnv({stage: 2, autoprefixer: {} // Blank is used by default. The default is autoprefixer, browsers are all turned on});Copy the code
  • Preserve: Determines whether all plug-ins should receive the same Preserve option, which can preserve or remove CSS populated in other ways
Use custom selectors in the style file @custom selectors :--heading H1, H2, H3, h4, h5, h6; article :--heading + p { color: red; }... @custom-selector :--heading H1, H2, h3, h4, h5, h6; article h1 + p,article h2 + p,article h3 + p,article h4 + p,article h5 + p,article h6 + p { color: red; } article :--heading + p { color: red; }... /// When set to false, Article h1 + p,article h2 + p,article h3 + p,article h4 + p,article h5 + p,article h6 + p {color: red; }Copy the code
  • ImportFrom: Import related variable information (such as custom media, custom properties, custom selectors, and environment variables) from an external source, which can be CSS, JS, or JSON (functions and direct object values are also supported). This feature is perfectly fine
/// style/theme.css @custom-media --small-viewport (max-width: 30em); @custom-selector :--heading h1, h2, h3, h4, h5, h6; :root { --color: red; }... PostCssEnv({ ... ImportFrom: "SRC /style/theme. CSS"Copy the code

If the postcss.config.js configuration is used, in the Node runtime environment, you can determine the most basic variable parameters according to the runtime ENV and some of the parameters you set, easily implement the function of skin

  • ExportTo: Export related variables as opposed to importFrom (this should encourage us to keep variables in a common file for easy maintenance)

Stage 2 and above CSS syntax

Is to enable the default configuration of the CSS syntax can be used directly

  • allUsed to reset all properties [stage 3, numeric abbreviation below]
A {all: initial; }Copy the code
value describe
initial Modifies the values of all element attributes or parent elements to their initial values
inherit Modify all element attributes or parent element values to their parent element values
unset Modify all element attributes or parent element values to parent element values (if inherited) or their initial values
  • :any-linkCSS pseudo-class selector will match:link:visited [2]
Nav: any-link> span {background-color: yellow; }... // compile to nav :link > span,nav :visited > span {background-color: yellow; }Copy the code
  • Break property: Property used to define interrupt behavior in a multi-column layout [3]
    • Break-inside: describes how a content box breaks under a multi-column layout page
    • Break-after: Describes the break behavior of a page, column, or region after the generated box
    • Break-before: Describes how the column or region should handle interrupts before generating boxes
  • Case-insensitive Attributes: Defining attribute selectors case-insensitive [2]
[title="hs" i] { border-style: solid none; }... /// convert to all possible combinations, use less. Conversion of too much [title = "hs"], [the title = "hs"], [the title = "hs"], [the title = "hs"] {border - style: solid none; }Copy the code
  • Custom Properties: Used to define variable values accepted by CSS properties [3]
Img {--some-length: 32px; img {--some-length: 32px; height: var(--some-length); width: var(--some-length); }Copy the code
  • :dir(rtl|ltr)Elements matching a specific writing direction are not of concern to Chinese language families [2]
  • Double-position-gradients: gradients [2]
.pie_chart {
  background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
}
Copy the code

Others include Linear Gradients, Radial Gradients

  • :focus-visibleFocus of elements triggered by keyboard access (selecting elements by tabbing) [2]
Outline: none; outline: none; outline: none; outline: none; outline: none; outline: none; outline: none; }. Name: focal-visible {// Outline: #00ff00 dotted thick; }... /// DOM <div class="name" tabindex="0">name</div>Copy the code

When you click on the element on the page with the mouse, you will have a different experience than when you switch with the TAB key. Mouse click because the outline is set to None, so you can see nothing. However, when tab-toggling elements, there is an obvious border around them, which is a great help in improving accessibility.

The postCSS-focus-visible plugin is used internally. The plugin author assumed that Polyfill was needed to solve the compatibility problem, so if you write the relevant style code in the.pcss file, .name:focus-visible becomes.name. Focus-visible. To avoid this conversion, put the relevant code in a.css file

  • :focus-withinThe current element or children of the current element are in focus state [2]
.tab-content:focus-within { background: #f00; }... /// If you have a DOM element tag in the page, follow the style code above, as soon as the input gets focus, the whole area will turn red. <div class="tab-content"> <input placeholder=" Please input your name "type="text" /> </div>Copy the code
  • Font-variant: A font with small uppercase letters that displays text. This means that all lowercase letters are converted to uppercase letters, but all letters with small uppercase fonts are smaller than the rest of the text. Another attribute that is not useful for The Chinese area [3]
  • Gap properties [3]

This property is used to set gutters between Grid rows and columns, which is short for row-gap and column-gap, a concept in a Css Grid

.grid-1 { gap: 20px; } .grid-2 { column-gap: 40px; row-gap: 20px; }... Grid-1 {grid-gap: 20px; } .grid-2 { grid-column-gap: 40px; grid-row-gap: 20px; }Copy the code
  • gray(): Function for specifying fully desaturated colors [2]
p { color: gray(50); }... /// convert to p {color: RGB (119,119,119); }Copy the code
  • Alpha: Hexadecimal color notation is 1/2 more characters than the usual 3/6 notation, and transparency can be specified [2]
section { background-color: #f3f3f3f3; color: #0003; }... /// convert to section {background-color: rgba(243,243,243,0.95294); Color: rgba (0,0,0,0.2); }Copy the code
  • lab()Use LAB for color [2]
  • lch()Use LCH for colors [2]
  • hwb()Use HWB for colors [2]
color: lch(53 105 40);
color: lab(240 50 20);
color: hwb(120 44% 50%);
Copy the code

Generally these colors are used more in the field of design or typography, and the front end is generally RGB RGBA

  • Image-set () : reference different image sources according to user resolution [2]
.foo { background-image: image-set( "https://www.baidu.com/img/flexible/logo/pc/[email protected]" 1x, "https://www.baidu.com/img/flexible/logo/pc/[email protected]" 2x, "https://www.baidu.com/img/flexible/logo/pc/[email protected]" 600dpi ); }... // become .foo { background-image: https://www.baidu.com/img/flexible/logo/pc/[email protected]; } @media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (min-resolution: 192dpi){ .foo { background-image: https://www.baidu.com/img/flexible/logo/pc/[email protected]; }} @media (-webkit-min-device-pixel-ratio: 6.25), (min--moz-device-pixel-ratio: 6.25), (min-resolution: 600dpi){ .foo { background-image: https://www.baidu.com/img/flexible/logo/pc/[email protected]; }}Copy the code
  • Logical Properties of CSS [2]

*-start, *-end, *-inline-start, *-inline-end, *-block-start, *-block-end, *-inline-start, *-block-end, *-inline-start, *-block-end This is opposed to a property like padding-left that has a clear direction. This CSS logical property has a number of values, as described in the W3C standard

p:first-child { float: inline-start; margin-inline-start: 10px; Margin-left} margin-left} margin-left} margin-left}Copy the code

Margin-inline and margin-block are CSS logical properties. The former is short for margin-inline-start and margin-inline-end. The latter is short for margin-block-start and margin-block-end. Margin-inline refers to horizontal margin control, while margin-block refers to vertical margin control

  • :matchesMatching pseudo-classes, multiple property values can be set at once [2]
p:matches(:first-child, .special) { margin-top: 1em; }... p:first-child, p.special { margin-top: 1em; }Copy the code
  • :notReject pseudo classes, setting out of current range [2]
p:not(:first-child, .special) { margin-top: 1em; }... p:not(:first-child):not(.special) { margin-top: 1em; }Copy the code
  • Define the scope of media queries in a more understandable way [3]
@media (width < 480px) {b {font-size: 14px}} @media (480px <= width < 768px) {// 18px} } @media (width >= 768px) { b { font-size: 20px} } ... @media (max-width: 479px) { b { font-size: 14px; } } @media (min-width: 480px) and (max-width: 767px) { b { font-size: 18px; } } @media (min-width: 768px) { b { font-size: 20px; }}Copy the code
  • overflowforoverflow-xoverflow-yThe shorthand [2]
html { overflow: hidden auto; }... html { overflow-x: hidden; overflow-y: auto; }Copy the code
  • overflow-wrapSets or retrieves line breaks when content exceeds the bounds of the specified container [2]
    • Normal: Allows content to overshoot or overflow specified container boundaries.
    • Break-word: The content will be wrapped within the boundary. Line breaks are allowed inside words if necessary.

CSS3 renamed word-wrap to overflow-wrap; So this will monitor your browser’s compatibility range, and the lower version browsers will synchronize overflow-wrap values to word-wrap

  • The CSS in the gridplace-Short form of attribute [2]
    • place-itemsAttributes arealign-itemsProperties andjustify-itemsThe merged short form of a property
    • place-contentAttributes arealign-contentProperties andjustify-contentThe merged short form of a property
    • place-selfAttributes arealign-selfProperties andjustify-selfThe merged short form of a property
.example { place-content: flex-end; place-items: center / space-between; place-self: flex-start / center; }... .example { -ms-flex-line-pack: end; align-content: flex-end; -webkit-box-pack: end; -ms-flex-pack: end; justify-content: flex-end; -webkit-box-align: center; -ms-flex-align: center; align-items: center; justify-items: /, space-between; -ms-flex-item-align: start; align-self: flex-start; justify-self: /, center; }Copy the code
  • Rebeccapurple a special color value [2]
HTML {color: rebeccapurple; / / # 663399}Copy the code
  • System-ui matches universal fonts [2]
body {
  font-family: system-ui;
}
Copy the code

CSS syntax for Stage 1

Since stage is set to 2, if you want to enable syntax that requires stage 1, enable it in the Features configuration. You can click the relevant API to check the hash corresponding to the URL, such as https://preset-env.cssdb.org/features#custom-media-queries, The corresponding ID is custom-media-queries. If the ID is not the same as the GIthub JS file, you can query it in the github JS file

postcssPresetEnv({ 
    stage: 2,
    features: {
      'nesting-rules': true,
      'custom-media-queries': true,
      'custom-selectors': true
    }
})
Copy the code
  • Custom-media-queries (Correlation ID)
    • Custom media query
@custom-media --small-viewport (max-width: 30em); @media (--small-viewport) { h1 {font-size: 16px} } ... Max-width: 30em) {h1 {font-size: 16px}}Copy the code

The maximum and minimum width can be >= <= instead

@custom-media --small-viewport (width >= 500px) and (width <= 1200px); @media (--small-viewport) { h1 {font-size: 16px} } ... // Convert @media (min-width: 500px) and (max-width: 1200px) {h1 {font-size: 16px}}Copy the code
  • custom-selectors
    • Custom selectors

The CSS Extensions specification allows the creation of custom selectors, which can be defined using @custom-Selector

@custom-selector :--heading h1, h2, h3, h4, h5, h6;
 
:--heading {
 font-weight: bold;
}
Copy the code

After running into

h1,h2,h3,h4,h5,h6 {
  font-weight: bold;
}
Copy the code
  • nesting-rules
    • Nesting, to reduce duplicate selector declarations, is done in two ways: the first way requires nested style declarations to be used&As a prefix,&Can only be used as the starting position of a declaration; The second style declaration is used@nestAs a prefix, and&It can appear anywhere
// Nesting can only start with &, unless prefixed with @nest. message {font-weight: normal; & .header { font-weight: bold; } @nest .body & { color: black; }}... .message { font-weight: normal } .message .header { font-weight: bold; } .body .message { color: black }Copy the code
  • prefers-color-scheme-query
    • Query media in dark mode
      • Light Theme
      • Dark theme
body { background-color: white; color: black; } @media (prefern-color scheme: dark) {body {background-color: black; color: white; }}Copy the code

cssnano

The version of webpack4+, which already integrates cssnano, is automatically enabled when mode is set to production mode

npm install –save-dev cssnano

Module. exports = {plugins: [require('cssnano')({preset: 'default',}),],};Copy the code

Implement a SASS using PostCSS

Postcss can define the use of related plug-ins, combine functions suitable for their own use, with postCSS plug-ins to achieve a class SASS (general function)

Introduction to related plug-ins

  • postcss
    • Basic Feature Pack
  • postcss-cli
    • Provides terminal operation capability
  • postcss-advanced-variables
    • Provides nesting similar to sassVariables, @if, @else, @for, @each, @mixin, @include, @content
  • postcss-scss
    • Sass can be used normally#{$var-name}Variable form
  • postcss-apply
  • postcss-assets
  • postcss-import
    • Make it possible to import in a file using @import.pcssfile
  • postcss-preset-env

@import

Use the postCSs-import plug-in

const atImport = require("postcss-import");
module.exports = {
  plugins: [
    atImport(),
Copy the code

Elements nested

Use nesting-rules in the postCSS-preset-env plug-in stage:1

const PostCssEnv = require("postcss-preset-env");

const postCssEnvConfig = PostCssEnv({
  stage: 2,
  features: {
    "nesting-rules": true
  }
});
Copy the code

It’s a little different than sASS nesting, but it’s the future CSS standard, and it’s the main one

Variables, @if, @else, @for, @each, @mixin, @include, @content

Use postcss – advanced – variables this plug-in, this plug-in can achieve the function of sass variable most, but a special syntax # {$var – name} need to use the plug-in postcss – SCSS, And set parser to postCSs-scss in postcss.config.js

const advanced = require("postcss-advanced-variables");
module.exports = {
  parser: "postcss-scss",
  plugins: [
    advanced(),
    ...
Copy the code

variable

$the font - size: 1.25 em. $font-stack: "Helvetica Neue", sans-serif; $primary-color: #333; body { font: $font-size $(font-stack); color: #{$primary-color}; }... Font: 1.25em "Helvetica Neue", sans-serif; color: #333; }Copy the code

@ the if, @ the else

$type: monster; p { @if $type == ocean { color: blue; } @else { color: black; }}... P {color: black}Copy the code

@for

@for $i from 1 through 5 by 2 { .width-#{$i} { width: #{$i}0em; }}... // convert to.width-1 {width: 10em; } .width-3 { width: 30em; } .width-5 { width: 50em; }Copy the code

@each

@each $animal in (red, yellow, black, white) { .#{$animal}-icon { color: #{$animal}; }}... // convert to.red-icon {color: red; } .yellow-icon { color: yellow; } .black-icon { color: black; } .white-icon { color: white; }Copy the code

@mixin @include

@mixin heading-text { color: #242424; font-size: 4em; } h1, h2, h3 { @include heading-text; }... // turn to h1, h2, h3 {color: #242424; font-size: 4em; }Copy the code

Attributes are nested

postcss-nested-props

const nestedProps = require("postcss-nested-props");
module.exports = {
  plugins: [
    nestedProps(),
Copy the code
.funky { font: { family: fantasy; size: 30em; weight: bold; }}... // convert to.funky {font-family: arial; font-size: 30em; font-weight: bold }Copy the code

Extend/Inheritance(Extend/ inherit)

postcss-extend

const extend = require("postcss-extend");
module.exports = {
  plugins: [
    extend(),
Copy the code
@define-placeholder message-shared {border: 1px solid # CCC; padding: 10px; color: #333; } .message { @extend message-shared; } .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; }... Message {border: 1px solid # CCC; // convert to.message {border: 1px solid # CCC; padding: 10px; color: #333; } .error, .seriousError { border: 1px #f00; background-color: #fdd; } .seriousError { border-width: 3px; }Copy the code

Add calc() calculation

postcss-calc

const calc = require("postcss-calc");
module.exports = {
  plugins: [
    calc(),
Copy the code
@mixin columns_calc($count) { width: calc(100% / $count); @if $count > 1 { float: left; } } .column_calculated { @include columns_calc(2); }... // Change to.column_calculated {width: 50%; float: left; }Copy the code

With these plug-ins, normal development needs are almost completely met

The complete configuration is as follows:

const PostCssEnv = require("postcss-preset-env");
const AtImport = require("postcss-import");
const advancedVariables = require("postcss-advanced-variables");
const nestedProps = require("postcss-nested-props");
const extend = require("postcss-extend");
const calc = require("postcss-calc");

const postCssEnvConfig = PostCssEnv({
  stage: 2,
  features: {
    "nesting-rules": true
  }
});

module.exports = {
  parser: "postcss-scss",
  plugins: [
    AtImport(),
    advancedVariables(),
    nestedProps(),
    extend(),
    calc(),
    postCssEnvConfig
  ]
};

Copy the code

Use PostCSS independently

You can build a standalone CSS processing platform using the postCSs-CLI plug-in by adding the following commands to package.json

  "scripts": {
    "build:pc": "npx postcss src/main.pc.css -o dist/main.pc.css",
    "build:h5": "npx postcss src/main.h5.css -o dist/main.h5.css"
Copy the code
// src/main.pc.css
@import 'normalize.css';
@import 'reset.css';
@import 'variables.css';
@import 'common.css';
@import 'common.mixin.css';
@import 'layout.mixin.css';
@import 'layout.css';
@import 'layout-flex.css';
@import 'button.mixin.css';
@import 'button.css';
@import 'button-group.css';
@import 'skeleton.mixin.css';
@import 'skeleton.css';
@import 'breadcrumb.css';
@import 'dropdown.css';
@import 'menu.css';
@import 'pagination.mixin.css';
@import 'pagination.css';
@import 'step.css';
@import 'checkbox.css';
@import 'cascader.css';
@import 'form.css';
@import 'calendar.css';
@import 'input-number.css';
@import 'rate.css'
Copy the code

There is a unified entry file that controls the output of different style sheets for PC and H5. In the entry file, you can set different variables to be introduced (such as the variable.css in the example above). CSS (variables.pc. CSS or variables.orange. CSS) to make skin classes easier to implement

Avoid compiler errors on PCSS files

I use vscode, which refers to the style written after the plug-in, and the compiler basically does not know, will give you an error, so here is how to avoid PCSS error, other compilers should have a similar method

Add support for.pcss files to vscode

  • Install the postCSs-Sugarss-language plug-in
  • Go to Setting, search for files.associations, and open settings.json to add the following content
"Files. associations": {"*.css": "postcss"}, "postcss.validate": false // Avoid checker.pcSSCopy the code

css module

CSS Module and CSS in JS are both solutions proposed by the community for CSS scope. In the actual development process, we feel that CSS Module is more suitable for the requirements of division of labor and cooperation.

In development today, no matter what framework you use, the basic flow is probably the same: do static pages first, then dynamic data. Two lines of work can easily be formed here: one is dedicated to refactoring and interacting with designers to achieve visual implementation; The other is dedicated to connecting business needs with the product manager and the back end (large companies will split into two jobs, small companies will do it all, but the work scene is mostly the same).

CSS in JS is more in line with the encapsulation of independent components. Everything from style and logic to content presentation is implemented in a SINGLE JS, without the need to import other files, which is great if you are writing UI components.

However, if it is a normal development requirement, you use this way, it means that the changes and fixes of style problems and the implementation of business logic are all carried out in a file, which is not conducive to the division of labor.

Personally, CSS in JS makes JS files confusing and less readable. And there is no way to export style files separately, no way to drop style files under a CDN server. It also affects component reusability. To reuse a component (business component) means to accept the component’s own style. If you change the dot size or color, add a separate receive parameter, or create a new component (list-red, for example). It is perfectly possible to add an outer layer of this component like

, which is controlled directly in the outer style file, and can easily be extended to multiple different styles, skins, etc.).

CSS also not friendly to reconstruct personnel in js, before they check style problem, directly modify the style file can see after deployment problem can be solved, now need to modify the js files such as js files to see if changes can take effect after deployment (if refactoring branches and development branch is different, you release a different situation, This can get messy…)

To enable the

Refer to the CSS Modules tutorial

With CSS-Loader, set the following parameters in the WebPack configuration item:

{test: / \. PCSS /, use: [MiniCssExtractPlugin loader, 'CSS - loader? Modules',' postcss - loader]}.Copy the code

This opens up the CSS Module, whose use will change the corresponding style name into a regular, but unexpected, name, such as

{border-radius:5px;} /// main.pcss /// since the style file itself does not require.classname to be repeated, so make sure that you do not repeat it, otherwise there will be problems with the same classname for multiple variable names. } .info { color: red; font-size: 24px; }... /// app.vue <template> <div :class="$style.info">{{ msg }}</div> </template> import style from '.. /style/main.pcss'; . computed: { $style () { return style; }}Copy the code

$style is a reference to vue-Loader’s CSS Modules scheme. Vue loader uses the $style calculation property to inject CSS Modules local objects into components

Style will print (value is a dynamic value)

{box: "_2sI8WybUY_1NGPVWmXjdbV", info: "_hA0iOLbXZy9PpOuCjpkc"}
Copy the code

The name of the style that is directly used in the component is automatically replaced by these names, and the style file is automatically converted to these names. This can solve the problem of CSS style conflict (pollution), the problem of global pollution, and also can solve the problem of dependency. Components only need to introduce their own related styles. Define the styles you want to use in the related styles file, and then use the $style for the related components.

Vue is a bit more cumbersome to write (it’s easier if you use JSX), but you can use it directly if you use React

import style from '.. /style/main.css'; class App extends Component { render () { return <div className={style.info}>app info</div> } }Copy the code

Global scope

In the imported style file, all styles are converted by default. If your style is intended to be used in a generic way, there are two options:

  • Only for.pcssopencss module..cssDon’t open
/// webpack.config.js {test: /\.css/, use: [MiniCssExtractPlugin.loader, 'css-loader']}, {test: /\.pcss/, use: [MiniCssExtractPlugin.loader, 'css-loader?modules', 'postcss-loader']} ... /// global.css body { font-size: 18px; background: #cccccc; }... /// app.vue import '.. /style/global.css'; import style from '.. /style/main.pcss'; // This is a separate import, but will eventually merge with a style file... /// main. CSS export style file body {font-size: 18px; background: #cccccc; } ._2sI8WybUY_1NGPVWmXjdbV { border-radius:5px; } ._hA0iOLbXZy9PpOuCjpkc { color: red; font-size: 24px; }Copy the code
  • Used in the style file to be compiled:global(.className)(Can also be omitted:global .className), so that the corresponding style does not compile

:local allows you to set what needs to be converted, since the default is conversion, there is no need to add another layer to indicate that it needs to be converted

** For conversions, always use.classname instead of id **

/// main.pcss
...
:global(body)  {
    font-size: 18px;
    background: #cccccc;
}
Copy the code

The two methods are relative, I feel the first one is better

Composing and Importing

  • The point of composition is not to mix style code, but to use the name of the combined class, including its subclasses when referenced
.box { border-radius:5px; } .info { color: red; font-size: 24px; } .foo { composes: box; composes: info; padding: 10px; } /// The corresponding JSON information after conversion is as follows: box: "src-style-main__box--2sI8W", info: "src-style-main__info--_hA0i", foo: "Src-style-main__foo --LiN2X src-style-main__box--2sI8W src-style-main__info--_hA0i", /// if we used $style.foo would also include the contents of the other two subclassesCopy the code
  • composesIt is also possible to import styles from other style modules for composition, which is used in a way that does not include blended classes synchronously.
.foo {
    composes: main-title header-title from './color.css';
    padding: 10px;
}
Copy the code

@value

There are many solutions to CSS variables. This is the CSS-loader solution, and it can only be used when CSS modules are enabled

There are official naming suggestions: V-define value, S-selector m-define media rule

@value v-primary: #BF4040; @value s-black: black-selector; @value m-large: (min-width: 960px); .header { color: v-primary; padding: 0 10px; } :global .s-black { color: black; } @media m-large { .header { padding: 0 20px; }}... ._2Q-2IY8XIGQEwnpoQr8qIF { color: #BF4040; padding: 0 10px; } .black-selector { color: black; } @media (min-width: 960px) { ._2Q-2IY8XIGQEwnpoQr8qIF { padding: 0 20px; }}Copy the code

Custom compiled class name

The default csS-loader hash algorithm is [hash:base64], and the output is this _2sI8WybUY_1NGPVWmXjdbV. The converted name can be customized

Loader: 'css-loader', options: {modules: {localIdentName: '[path][name]__[local]--[hash:base64:5]'}Copy the code

On official advice

  • Development environment Usage[path][name]__[local]--[hash:base64:5]
  • Use in production environment[hash:base64]

The resulting class name is similar to src-style-main__box–2sI8W, which allows you to see the path and use modules to locate style problems

CSS loader parameters

The name of the type The default describe
url {Boolean|Function} true Enable/disable the URL () function
import {Boolean|Function} true Enable/disable @import processing
modules {Boolean|String|Object} false Enable/disable CSS Modules and related configurations
sourceMap {Boolean} false The map function was enabled or disabled
importLoaders {Number} 0 How many loaders to use before CSS-loader (default, do not touch this value, use loader in the order set in Webpack)
localsConvention {String} ‘asIs’ Key rule corresponding to the exported JSON
onlyLocals {Boolean} false It affects the loader sequence during packaging. You can set this value in some SSR scenarios, but do not use it in general cases
esModule {Boolean} false Whether to enable es Module

url

/ / / install url - loader processing image first, and add the relevant configuration information {test: / \. (PNG | SVG | JPG jpeg | | GIF) $/, use: "url - loader"},... /// main.pcss .foo { color: red; font-size: 14px; background: url(".. /image/timg.jpeg"); // Set the background}Copy the code

If you do this, the converted CSS will process the image, but if you set this value to false

{loader: "CSS-loader ", options: {modules: true, url: false // This value defaults to true}},Copy the code

The converted CSS does not process the URL () and outputs it as is

/// background: url(".. /image/timg.jpeg"); Url: (url, resourcePath) => {// url.. /image/timg.jpeg // resourcePath - CSS absolute path // not processing 'img. PNG 'urls if (url.includes('img.png')) {return false; } return true; },Copy the code

import

This value is similar to the url function, except that it controls the import and export of files. This value can also be set to true or false. If this parameter is set directly, then there is a problem

/// @import "./color.css"; import: (parsedImport, resourcePath) => { // parsedImport { url: './color.css', media: Url - '@import' file path // paralport. media - '@import' Media query path // resourcePath - the absolute path of the CSS file / / contains ` style.css. CSS ` merging processing if not (parsedImport. Url. Includes (' style. The CSS ')) {return false. } return true; },Copy the code

@import is a widely supported CSS attribute that can be used in browsers larger than IE9

modules

True or false Enables/disables (you can also enable/disable CSS modules by setting the modules value to ‘local’ or ‘global’)

In my view, global :local, Composing Importing, @value, and localIdentName are all configuration information for modules, which can accept an object for other configurations

Modules: {mode: 'local', // Set local enable global Disable CSS module exportGlobals: true, localIdentName: '[path][name]__[local]--[hash:base64:5]', // Compiled class name Context: path.resolve(__dirname, 'SRC '), hashPrefix: 'my-custom-hash', },Copy the code
  • modeIn addition tolocal globalPlus, there’s another valuepureTo use this value requires that the style file must be a pure selector and cannot be usedglobal localOn the parcel
/// when mode is pure, a compilation error is prompted :local(.zoo)... /// mode can also take a function form that performs special processing on the style files in the specified path (which files are converted and which files are not). The return values can only be these three values: (resourcePath) => { if (/pure.css$/i.test(resourcePath)) { return 'pure'; } if (/global.css$/i.test(resourcePath)) { return 'global'; } return 'local'; },Copy the code
  • ExportGlobals = exportGlobals = exportGlobals

  • Context generates the same hash, which is the same as GitHub bug description. In some cases, the same hash is generated, and this parameter is used to solve the problem, but I have tried many cases, and I have not found the same hash

  • HashPrefix sets the group’s own hash rule

  • GetLocalIdent sets the compiled rule name, the same as localIdentName except that it’s a function that can be set in more detail, usually using localIdentName

  • What does localIdentRegExp do

localsConvention

This sets how the key value maps to the class name when exporting JSON. The default is ‘asIs’.

loader: 'css-loader', options: { modules: { mode: 'local', localIdentName: '[path][name]__[local]--[hash:base64:5]' }, localsConvention: 'asIs' } ... .infoNews { font-size: 35px; } .info-old { color: white; } .info_dashes { color: salmon; } .info { color: red; }... Info: "src-component-page1-index__info --10GK2" info-old: "src-components-page1-index__info-old--k163w" infoNews: "src-components-page1-index__infoNews--1uma1" info_dashes: "src-components-page1-index__info_dashes--FVVUn" ... /// camelCase camelCase will change the non-camelcase name to camelCase and keep the previous class name info: "src-component-page1-index__info --10GK2" info-old: "src-components-page1-index__info-old--k163w" infoDashes: "Src-components -page1-index__info_dashes--FVVUn" // same as info_dashes infoNews: "src-components-page1-index__infoNews--1uma1" infoOld: "Src-components -page1-index__info-old--k163w" // same as info-old info_dashes: "src-components-page1-index__info_dashes--FVVUn" ... /// camelCaseOnly is similar to hump except that it does not keep the non-hump conversion info: "src-component-page1-index__info --10GK2" infoDashes: "src-components-page1-index__info_dashes--FVVUn" infoNews: "src-components-page1-index__infoNews--1uma1" infoOld: "src-components-page1-index__info-old--k163w" ... Info: "src-components-page1-index__info--10GK2" info-old: "SRC -components-page1-index__info--10GK2" info-old: "src-components-page1-index__info-old--k163w" infoNews: "src-components-page1-index__infoNews--1uma1" infoOld: "Src-compones-page1-index__info-old --k163w" info_dashes:" src-compones-page1-index__info_dashes --FVVUn" /// dashesOnly Does not retain the pre-conversion info: "src-components-page1-index__info--10GK2" infoNews: "src-components-page1-index__infoNews--1uma1" infoOld: "src-components-page1-index__info-old--k163w" info_dashes: "src-components-page1-index__info_dashes--FVVUn"Copy the code

The reason for this argument is that when we use CSS modules, we may end up dynamically binding to a component for easy use in JS