preface

In the front-end field, ANTD is undoubtedly the most widely used UI class library in the React ecosystem. Antd highly encapsulates common form class input components, bringing convenience out of the box, but at the same time, it is increasingly difficult to control its style. You’ve all had the experience of being forced to modify antD styles by a product or interaction. Many times, it is difficult to pass “this is an open source control, the style is not easy to modify” prevarication past. So the question is, how to elegantly modify the style of ANTD?

The specific methods

After exploration, there are roughly the following ideas:

  1. Add the class name or style directly

This is the most general approach and works directly on the current element, but sometimes we find antD components end up with many levels nested in the DOM layer. Just making changes to the outer element and having the child elements inherit the style doesn’t quite cut it; The natural idea at this point is to use CSS selectors to retrieve child elements. The code logic is as follows:

import s from './index.css';
import { Input, AutoComplete } from 'antd';
/ /... Omit irrelevant code
    <div className={s.feeWrap}>
        <Input
            disabled
            value={lanWrap('Transfer fee')}
            addonAfter={fee}
            className={cx(s.feeInput, 'tInput')} / >
    </div>
Copy the code

CSS code

.feeInput .ant-input {
    background-color: #ffffff ! important;
    font-size:.14rem;
    color: # 555555  ! important;
    user-select: none;
}
Copy the code

Now let’s test the results.



The background color of the input box did not change as we expected. Next, we will analyze the specific reasons. From the above screenshot, we can see that the CSS class name inside antD component is not processed by CSS Module, but our custom style is realized by CSS Module, resulting in dom cannot match the correct style. Let’s take a look at the webPack configuration:

    module: {
        rules: [{test: / (? 
      ,
                exclude: /node_modules/,
                use: [
                    //MiniCssExtractPlugin.loader,
                    'style-loader',
                    {
                        loader: 'typings-for-css-modules-loader'.options: {
                            modules: true.namedExport: true}}]}, {// Specifically dealing with ANTD CSS styles
                test: /\.(less)$/,
                include: /node_modules/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader: "less-loader".options: {
                            lessOptions: {
                                javascriptEnabled: true}}}],},]}Copy the code

As can be seen from the configuration here, the business code uses CSS moudle. Since antD components are written in less, we use less Loader to process styles here. CSS loader is not enabled for the part of LESS, so the class name is still the original class name seen in dom. Of course, if your project does not have CSS Module enabled and uses the original class name to control the style, this problem does not exist. 2. Use a variety of CSS file packaging strategies have analyzed the root of the problem, the next is how to solve the problem, the most natural idea is to use a special CSS style packaging strategy for this part of the special needs, in simple terms, for the STYLE of ANTD components, hang a regular string class name on the outside, Use a separate CSS file to control styles. At packaging time, take a special policy of not enabling CSS Modules for this file, so that it is consistent with antD component class name processing, and you can control styles directly through CSS class name selector. The WebPack configuration is as follows

    module: {
        rules: [{// To customize styles for ANTD, use non-fetch matches, reverse affirmative precheck, and don't use CSS Modules
                // If the file name contains antD, do not enable CSS Module
                test: / (? <=antd)\.(css|scss)$/,
                exclude: /node_modules/,
                use: [
                    //MiniCssExtractPlugin.loader,
                    'style-loader',
                    {
                        loader: 'typings-for-css-modules-loader'.options: {
                            modules: false.namedExport: true}}]}, {// If the file name does not contain antD, enable CSS Module
                test: / (? 
      ,
                exclude: /node_modules/,
                use: [
                    //MiniCssExtractPlugin.loader,
                    'style-loader',
                    {
                        loader: 'typings-for-css-modules-loader'.options: {
                            modules: true.namedExport: true}}]},]}Copy the code

For the antD special style file, we named it index.antd. CSS, so that it will not be processed by CSS Module, we made the following changes to the code:

import s from './index.css';
import './index.antd.css';

/ /... Omit irrelevant code
            <div className={s.feeWrap}>
                <Input
                    disabled
                    value={lanWrap('Transfer fee')}
                    addonAfter={fee}
                    className={cx('feeInput', 'tInput')} / >
            </div>
Copy the code

In index.antd. CSS there is the following content

.feeInput .ant-input {
    background-color: #ffffff ! important;
    font-size:.14rem;
    color: # 555555  ! important;
    user-select: none;
}
Copy the code

Let’s look at the effect:



And we can see from here, the peripheralfeeInputClass has successfully modified antD’s native through the class selector.ant-inputStyle.

3. Ultimate solution

The problem is solved, but the actual operation process is too tedious, there should be an extra file, but also new Webpack packaging rules, do not meetless is moreIs there a better solution? One thing to note here is that the CSS Module is used for global styles:globalIn other words, we can take advantage of this to define classes outside the ANTD component for refined control styles in:globalIn this way, class name hash is avoided, and style control can be realized with antD class name rules. The specific code is as follows:

import s from './index.css';

/ /... Omit irrelevant code
            <div className={s.feeWrap}>
                <Input
                    disabled
                    value={lanWrap('Transfer fee')}
                    addonAfter={fee}
                    className={cx('fee11Input', 'tInput')} / >
            </div>
Copy the code

Js code does not need to introduce a special index.antd. CSS file, CSS file like this:

:global(.fee11Input .ant-input) {
    background-color: #ffffff ! important;
    font-size:.14rem;
    color: # 555555  ! important;
    user-select: none;
}
Copy the code

This method, due to the limitations of CSS syntax, causes the class name to be unable to hash, and has the risk of polluting the global class roll. If SCSS, LESS, SASS and other precompiled tools are enabled, a more complete solution is this

.fee11Input {
    :global {
        .ant-input {
            background-color: #ffffff ! important;
            font-size:.14rem;
            color: # 555555  ! important; user-select: none; }}}Copy the code

External code should be changed to CSS Module style

    <Input
        disabled
        value={lanWrap('Transfer fee')}
        addonAfter={fee}
        className={cx(s.fee11Input)}/>
Copy the code

Let’s look at the effect:

The result is as expected, a perfect modification of the antD component’s inline style! There is no problem of introducing redundant files in the second solution, simple and efficient.