background

Due to some reasons, our team is responsible for secondary development on GitLab. The simple understanding is to hang a DOM rendering on GitLab for some components written with React, and the component library chooses ANTD. It is embarrassing to find that GitLab itself has a set of global styles after introduction. Antd also brings a set of global styles, resulting in partial overwriting of GitLab styles, as shown in the figure: a label color overwritten by ANTD:

Checkbox subtle style errors and size changes:

why

The global style of ANTD has not been an issue for a long time, there has been a lot of discussion in the community (#4331 #9363 #13459), but no progress has been made to date. Since Ant-Design is a Design language, ANTD will introduce a library forking browser default style resets from Normalize.css.

The file that introduces global styles is style/core/base.less. This is the base.less file that formats the default styles of various elements.

.// remove inner border and padding from Firefox, but don't restore the outline like Normalize.
button::-moz-focus-inner.[type='button']::-moz-focus-inner.[type='reset']::-moz-focus-inner.[type='submit']::-moz-focus-inner {
  padding: 0;
  border-style: none;
}

input[type='radio'].input[type='checkbox'] {
  box-sizing: border-box; // 1. Add the correct box sizing in IE 10-
  padding: 0; // 2. remove the padding in IE 10-}...Copy the code

The diagram below shows the dependencies for ANTD’s CSS packaging, which helps clarify how to avoid introducing base.less.

Solve the core problem

The core problem is the intrusion of the base.less file into global styles. Can I get rid of this file? No, the component styles of ANTD are based on this formatted style, which would be misplaced without reference to this file style (see figure below), so it should be introduced without affecting the global style.

In addition, when we need to converge antD global style, it is usually because another global style library exists on the current page (such as GitLab global style encountered by the author), and the purpose we need to achieve can be further changed to “converge base.less, And ensure that antD’s style cannot be easily overridden by external global styles.

Simply qualify base. Less

There have been some schemes in the community to put a layer of.ant-container around base.less, but a significant drawback is that the weight of styles in base.less increases, resulting in style dislocation.

Increased ant- priority across the board

But there is nothing wrong with limiting base.less. Base.less needs to be covered by a layer of “scope”, so it is good to increase the weight of all existing ANTD components to ensure that the existing selector priority remains the same.

Fortunately, antD-related components all have at least one class that starts with Ant -, and we can do this by taking advantage of this feature and CSS property selectors.

The process is as follows:

  1. Replace antD base. Less with magic base. Less. This magic base*[class*='ant-']Limits the “scope” of its style. This step limits the global style to all that existsant-Class element.
*[class*='ant-'] {
  @import '~antd/lib/style/core/base.less';
}
Copy the code
  1. After increasing the weight of base.less, you can also increase the weight of all ANTD styles indirectly, avoiding the intrusion of external global styles on ANTD.

    If you want to change the style, use the CSS Babel — PostCSS, write a PostCSS plugin, github.com/fi3ework/po… Raise all class selectors that start with.ant equally, using postCSS’s library of selectors that start with PostCSS -parser, filter out “first class selector that starts with Ant -.” Precede it with a property selector [class*=’ant-‘], followed by a wildcard * if the selector is first in the current rule or preceded by a combinator, the same selector as the one for base.less. Both increase the same weight at the same time to maintain the original priority unchanged.

    In addition, if you want to use antD’s global style for elements that are not in antD components, simply wrap a class name =”ant-whatever” around those elements, as long as they start with ant-.

import parser, { Node } from 'postcss-selector-parser'
import { SelectorReplace } from '.. /index'

export function antdScopeReplacerFn(node: Node) {
  if(node.type ! = ='selector') return

  const firstAntClassNodeIndex = node.nodes.findIndex((n) = > {
    return n.type === 'class' && n.value.startsWith('ant-')})if (firstAntClassNodeIndex < 0) return

  const firstAntClassNode = node.nodes[firstAntClassNodeIndex]
  const prevNode = node.nodes[firstAntClassNodeIndex - 1]

  // preserve line break
  const spaces = {
    before: firstAntClassNode.rawSpaceBefore,
    after: firstAntClassNode.rawSpaceAfter,
  }

  firstAntClassNode.setPropertyWithoutEscape('rawSpaceBefore'.' ')
  const toInsert = []

  if (firstAntClassNodeIndex === 0 || prevNode.type === 'combinator') {
    const universal = parser.universal({
      value: The '*',
    })
    toInsert.push(universal)
  }

  const attr = parser.attribute({
    attribute: 'class',
    operator: '* =',
    value: `"ant-"`,
    raws: {},
  })

  toInsert.push(attr)
  toInsert[0].spaces = spaces firstAntClassNode.parent! .nodes.splice(firstAntClassNodeIndex,0. toInsert) }export const antdReplacer: SelectorReplace = {
  type: 'each',
  replacer: antdScopeReplacerFn,
}
Copy the code

This ANTD configuration is already provided as preset, which can be imported if you want to use

const { replacer, presets } = require('postcss-rename-selector')

plugins: [
    replacer(presets.antdReplacer)
]
Copy the code

The effect is as follows:

use

Build demo repository, the following ways can be found in demo repository: github.com/fi3ework/re…

Method 1: Delete base. Less

Full amount

Idea is: in the post – install phase will antd/lib/style/core/index. The introduction of less @ import base; Delete this line and manually import our own modified base.less.

Steps:

  1. Write a post-install script and rewrite it directlyantd/lib/style/core/index.lessWe already have an implementation hereGithub.com/ant-design/…
  2. Add postcss-rename to PostCSS and configure:
const { replacer, presets } = require('postcss-rename-selector')

plugins: [
    replacer(presets.antdReplacer)
]
Copy the code
  1. Introduce full stylesimport 'antd/dist/antd.less'
  2. An additional base.less is introduced, restricted to a “scope”
@import '~antd/lib/style/mixins/index.less';

*[class*='ant-'] {
  @import '~antd/lib/style/core/base.less';
}
Copy the code

Antd is normal, and the top a tag is not affected by ANTD:

According to the need to introduce

  1. I’m going to introduce 1 to the whole thing
  2. I’m going to introduce 2
  3. Configure the Babel – plugin – import
  [
    'import',
    {
      libraryName: 'antd',
      style: true],},Copy the code
  1. I’m going to introduce 4 in full

Method 2: Manually splice antD. less

Full amount

The post-install approach is a bit of a hack, but the alternative is to manually spell out the antd/dist/ antD. less file dependencies and import them.

@import '~antd/lib/style/themes/index.less';
@import '~antd/lib/style/mixins/index.less'; * [class* ='ant-'] {
  @import '~antd/lib/style/core/base.less';
}

@import '~antd/lib/style/core/iconfont.less';
@import '~antd/lib/style/core/motion.less';

@import '~antd/lib/style/components.less';
Copy the code

The structure is the same as the original import, except that base.less is wrapped in a layer of “scope”, and alias needs to be added to the webpack configuration

alias: {
    'antd/dist/antd.less$': path.resolve(__dirname, '.. /src/custom-dist.less')}Copy the code

Then import it at the entry point of the entire file

import './custom-dist.less`
Copy the code

Is ok.

According to the need to introduce

Unfortunately, in this way, I can not do with babel-plugin-import on demand. Babel-plugin-import provides several preset style loading methods and customizable methods. Take Button as an example

  1. leadantd/lib/button/index.cssBabel-plugin-import = babel-plugin-import
  [
    'import',
    {
      libraryName: 'antd',
      customStyleName: (name) = > {
        return `antd/lib/${name}/style/index.css`}}].Copy the code

There is no problem with the Button component, but some components, such as Col, are placed in the Layout directory. If you spell the name according to the component name, you will directly report an error if you cannot find the file. In addition, for example, the Input component relies on the style of the Button. Instead of just quoting the style of the Input as needed, you need to manually import the style of the Button.

  1. leadantd/lib/button/css.jsBabel-plugin-import = babel-plugin-import
  [
    'import',
    {
      libraryName: 'antd',
      style: 'css'}].Copy the code

The file looks like this

'use strict'

require('.. /.. /style/index.css')

require('./index.css')
Copy the code

Just put the require(“.. /.. /style/index.less”); The introduction of this can be killed. Unfortunately, my attempts at IgnorePlugin and alias didn’t work. IgnorePlugin, in particular, should theoretically be ignored in the official documentation for handling moment.js.

new webpack.IgnorePlugin(/\.\.\/\.\.\/style\/index\.css/./antd$/),
Copy the code

But it has no effect. If anyone knows why, please let me know.

conclusion

The antD version I’m using is still 3.x and has not been upgraded to V4 yet, but a look at the V4 code shows that base.less is still lying quietly and visually using the same method.

This scheme has been running in our own business for several months and we have not found any problems. Ant Design as a set of Design specifications to provide a global style is reasonable, but I still hope that the official can provide an optional limited scope of the global style, after all, the next door Material-UI does not have this problem, wish that ANTD V5 can solve it!

Colored eggs (Canton)

I wrote a VS Code productivity plug-in for ANTD, I think it is the best antD VS Code plug-in (escape), welcome Star, Issue.

vscode-antd-rush

Ref

  • Elegant solution to Ant Design global styling issues
  • Github.com/ant-design/…
  • Github.com/ant-design/…
  • Github.com/ant-design/…