Как элегантно и полностью решить проблему с глобальным стилем

Ant Design
Как элегантно и полностью решить проблему с глобальным стилем

задний план

По некоторым причинам наша команда отвечает за вторичную разработку на GitLab.Простое понимание - повесить DOM на GitLab для рендеринга некоторых компонентов, написанных на React.Библиотека компонентов выбирает antd.Смущает то, что после введения обнаруживается что сам GitLab имеет набор глобальных стилей A, а antd приносит набор глобальных стилей, в результате чего некоторые стили GitLab перезаписываются, как показано на рисунке: цвет метки переопределяется с помощью antd:

image

Тонкий стиль и изменение размера флажков:

image

причина

Глобальный стиль antd - дело не одного-двух дней, и в сообществе было много обсуждений (#4331 #9363 #13459), но до сегодняшнего дня не было достигнуто никакого прогресса. Поскольку Ant-Design — это язык дизайна, antd представит набор автоматических вилок.normalize.cssБиблиотека сброса стиля браузера по умолчанию.

Файл, который импортирует глобальные стили,style/core/base.less, то есть этот base.less отформатирует стили различных элементов по умолчанию и перехватит абзац:

...
// 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-
}
...

На следующем рисунке показаны зависимости при упакованном CSS antd.Это изображение помогает нам прояснить, как избежать введения base.less.

image

решать основные проблемы

Основная проблема заключается в вторжении глобального стиля файлом base.less. Этот файл можно опустить? Нет, все стили компонентов antd основаны на этом стиле форматирования.Если вы не обратитесь к этому стилю файла, он будет неуместен (как показано на рисунке ниже), поэтому его следует вводить, не затрагивая глобальный стиль.

image

И, как правило, когда нам нужно объединить глобальный стиль antd, это происходит потому, что на текущей странице есть другой набор библиотеки глобальных стилей (например, глобальный стиль GitLab, с которым я столкнулся), цель, которую мы должны достичь, может быть далее изменено на«Сведите base.less и убедитесь, что внешние глобальные стили не могут легко переопределить стили antd».

Простая квалификационная база.less

Раньше в сообществе был слой base.less.ant-containerизстроить планы, но существенным недостатком является то, что увеличение веса стиля в base.less приводит к смещению стиля.

Поднимите приоритет муравья по всем направлениям

Но нет ничего плохого в идее ограничения base.less, Base.less нужно покрыть слоем «scope», затем увеличить вес всех существующих компонентов antd, чтобы исходный приоритет селектора оставался неизменным.

К счастью, все компоненты, связанные с antd, будут иметь по крайней мере один, начинающийся сant-Класс в начале, нам нужно только хорошо использовать эту функцию и селектор атрибутов CSS для достижения цели.

Процесс выглядит следующим образом:

  1. Замените base.less в antd на модифицированный magic base.less (подробности см. в разделе "Как использовать"). Этот модифицированный magic base.less будет покрыт слоем*[class*='ant-']Ограничивает «объем» своих стилей. Этот шаг ограничивает глобальный стиль всемиant-в элементе класса.
*[class*='ant-'] {
  @import '~antd/lib/style/core/base.less';
}
  1. После увеличения веса base.less, затем увеличьте вес стиля компонента, что также может косвенно увеличить вес всех стилей antd, чтобы избежать вторжения внешних глобальных стилей в antd.

    Так как это изменение стиля, то используйте бабел в мире CSS - PostCSS, напишите плагин PostCSS,GitHub.com/FI3E работает/сломан…, положить все.antСелекторы классов в начале также можно поднять, используяpostcss-selector-parserЭта библиотека селекторов синтаксического анализа, официально предоставляемая PostCSS, отфильтровывает «селектор первого класса, начинающийся с ant-», и добавляет перед ним селектор атрибутов.[class*='ant-'], если селектор является первым в текущем правиле или ему предшествует комбинатор, добавьте подстановочный знак*, это то же самое, что и селектор, добавленный к base.less выше Оба они увеличивают один и тот же вес одновременно и сохраняют исходный приоритет.

    Кроме того, если некоторые элементы не входят в компоненты antd, но также хотят использовать глобальный стиль antd, просто поместите класс на самый внешний слой этих элементов.className="ant-whatever",только если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: '*',
    })
    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,
}

Конфигурация для этого antd была такойpresetПри условии, если вы хотите использовать прямой импорт

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

plugins: [
    replacer(presets.antdReplacer)
]

Эффект показан на рисунке:

image

Как использовать

Демо-склад построен, и в демо-складе можно найти следующие методы:GitHub.com/FI3E работа/горячая…

Способ 1: удалить шаттл base.less

Полная сумма

Идея такова: на этапе после установкиantd/lib/style/core/index.lessпредставил@import base;Удалим эту строку напрямую, а потом вручную введем нашу собственную модифицированную магией base.less.

шаг:

  1. Напишите сценарий после установки и перепишите его напрямуюantd/lib/style/core/index.less, здесь было реализованоGitHub.com/Анта-дизайн/…
  2. Добавлено в PostCSSpostcss-rename-selectorПодключить и настроить:
const { replacer, presets } = require('postcss-rename-selector')

plugins: [
    replacer(presets.antdReplacer)
]
  1. Представьте полный стильimport 'antd/dist/antd.less'
  2. Ввести дополнительный base.less, ограниченный "сферой применения"
@import '~antd/lib/style/mixins/index.less';

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

Посмотрите на эффект, стиль antd нормальный, а самый верхний тег не влияет:

image

Внедрить по требованию

  1. Идентичный импорт 1
  2. Идентичный импорт 2
  3. Настроить импорт плагина babel
  [
    'import',
    {
      libraryName: 'antd',
      style: true,
    },
  ],
  1. Идентичный импорт 4

Способ 2: Ручная склейка antd.less

Полная сумма

Метод после установки несколько хакерский, другой метод — написать его вручную.antd/dist/antd.lessЗатем импортируются зависимости файлов.

@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';

Структура такая же, как и в оригинальном введении, единственное отличие состоит в том, что base.less обернут слоем «scope», а затем в конфигурацию webpack нужно добавить псевдонимы.

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

Затем импортируйте его при записи всего файла

import './custom-dist.less`

Просто хорошо.

Внедрить по требованию

К сожалению, таким образом автор долго бился и не смог сделать импорт по требованию с помощью babel-plugin-import. babel-plugin-import предоставляет несколько предустановленных методов загрузки стилей и настраиваемых методов, в качестве примера возьмем компонент Button

  1. Свинецantd/lib/button/index.css, то есть настроить babel-plugin-import следующим образом:
  [
    'import',
    {
      libraryName: 'antd',
      customStyleName: (name) => {
        return `antd/lib/${name}/style/index.css`
      }
    }
  ],

С компонентом Button проблем нет, но некоторые компоненты, такие какColОн находится в каталоге Layout.Написание имени в соответствии с именем компонента не найдет файл и напрямую сообщит об ошибке. Кроме того, такие какInputЭтот компонент зависитButtonстиль, только по мере необходимостиInputСтиль неприемлем, и его необходимо импортировать вручную.Buttonстиль.

  1. Свинецantd/lib/button/css.js, то есть настроить babel-plugin-import следующим образом:
  [
    'import',
    {
      libraryName: 'antd',
      style: 'css'
    }
  ],

Этот файл выглядит так

'use strict'

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

require('./index.css')

просто поставьrequire("../../style/index.less");Это введение можно исключить. Но, к сожалению, я пыталсяIgnorePluginа такжеaliasнедействительны. особенноIgnorePlugin, в соответствии с обработкой Moment.js, указанной в официальной документации, теоретически его следует игнорировать.

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

Но на самом деле это не работает, если кто-нибудь знает, почему, пожалуйста, дайте мне знать.

Суммировать

В настоящее время используемая автором версия antd еще 3.x, и она не обновлялась до v4 для проверки, но почитав код v4, base.less до сих пор там спокойно лежит, а визуальный метод использование аналогично.

Это решение работает в нашем собственном бизнесе уже несколько месяцев, и пока проблем не обнаружено. Для Ant Design разумно предоставить глобальный стиль в виде набора спецификаций дизайна, но я все же надеюсь, что официальные лица могут предоставить необязательный глобальный стиль с ограниченной областью действия.В конце концов, в соседнем Material-UI такой проблемы нет ( побег), молча желая в antd v5 Решаемо!

Цветное (кантонское) яйцо (объявление)

Я уже писал плагин производительности VS Code для antd раньше, и я думаю, что это лучший плагин antd VS Code (escape) Добро пожаловать, звездочка, выпуск.

vscode-antd-rush

Ref