CSS 호환성

CSS 호환성 (CSS Compatible)

Ant Design은 최신 브라우저의 최근 2개 버전을 지원해요. 레거시 브라우저와 호환되어야 한다면 실제 요구에 따라 다운그레이드 처리를 해 주면 돼요.

출처: 문서

본문

기본 스타일 호환성

Ant Design은 최신 브라우저의 최근 2개 버전을 지원해요. 레거시 브라우저와 호환되어야 한다면 실제 요구에 따라 다운그레이드 처리를 해 주세요:

Feature antd version Compatibility Minimum Chrome Version Compatibility workaround
:where Selector >=5.0.0 caniuse Chrome 88 <StyleProvider hashPriority="high">
CSS Logical Properties >=5.0.0 caniuse Chrome 89 <StyleProvider transformers={[legacyLogicalPropertiesTransformer]}>

더 오래된 브라우저를 지원해야 한다면 @ant-design/cssinjs의 StyleProvider를 사용해 실제 요구에 맞게 다운그레이드 처리를 하세요.

선택자 안의 :where

  • antd 버전: >=5.0.0
  • MDN: :where
  • 브라우저 호환성: caniuse
  • 지원되는 최소 Chrome 버전: 88
  • 기본 활성화: 예

Ant Design의 CSS-in-JS 기능은 기본적으로 ":where" 선택자를 사용해 CSS 선택자 특이도(specificity)를 낮추므로, 사용자가 업그레이드할 때 커스텀 스타일을 조정하는 추가 비용을 줄여 줘요. 하지만 ":where" 문법의 호환성은 오래된 브라우저에서 비교적 좋지 않아요 (호환성). 특정 시나리오에서 오래된 브라우저를 지원해야 한다면 @ant-design/cssinjs로 기본 특이도 낮추기를 끌 수 있어요 (antd와 버전 일치를 확인해 주세요).

import { StyleProvider } from '@ant-design/cssinjs';

// Config `hashPriority` to `high` instead of default `low`
// Which will remove `:where` wrapper
export default () => (
  <StyleProvider hashPriority="high">
    <MyApp />
  </StyleProvider>
);

이러면 :where를 클래스 선택자로 바꿔 줘요:

--  :where(.css-bAMboO).ant-btn {
++  .css-bAMboO.ant-btn {
      color: #fff;
    }

참고: :where 다운그레이드를 끄면 일부 스타일의 우선순위를 수동으로 조정해야 할 수 있어요. 또는 PostCSS 플러그인을 사용해서 애플리케이션 CSS 선택자 우선순위를 높일 수도 있어요. PostCSS에는 이를 도와주는 플러그인이 많아요. 예를 들어:

플러그인으로 우선순위 올리기:

--  .my-btn {
++  #root .my-btn {
      background: red;
    }

CSS Logical Properties

LTR과 RTL 스타일을 통일하기 위해 Ant Design은 CSS 논리 속성(logical properties)을 사용해요. 예를 들어 원래의 margin-left가 margin-inline-start로 바뀌어서, LTR과 RTL 양쪽에서 모두 시작 위치 간격이 되도록 해요. 오래된 브라우저와 호환되어야 한다면 @ant-design/cssinjs의 StyleProvider로 transformers를 구성할 수 있어요:

import { legacyLogicalPropertiesTransformer, StyleProvider } from '@ant-design/cssinjs';

// `transformers` provides a way to transform CSS properties
export default () => (
  <StyleProvider transformers={[legacyLogicalPropertiesTransformer]}>
    <MyApp />
  </StyleProvider>
);

켜면 스타일이 CSS 논리 속성을 다음과 같이 다운그레이드해요:

.ant-modal-root {
-- inset: 0;
++ top: 0;
++ right: 0;
++ bottom: 0;
++ left: 0;
}

@layer

  • antd 버전: >=5.17.0
  • MDN:CSS @layer
  • 브라우저 호환성: caniuse
  • 지원되는 최소 Chrome 버전: 99
  • 기본 활성화: 아니오

Ant Design은 5.17.0부터 통일된 CSS 우선순위 다운그레이드를 위해 @layer 구성을 지원해요. 다운그레이드 후 antd의 스타일은 항상 기본 CSS 선택자 우선순위보다 낮아져서, 사용자가 스타일을 쉽게 덮어쓸 수 있어요 (@layer의 브라우저 호환성을 꼭 확인해 주세요). layer를 활성화하면 자식 요소 반드시 ConfigProvider로 감싸 아이콘 관련 스타일을 갱신해야 해요:

import { StyleProvider } from '@ant-design/cssinjs';
import { ConfigProvider } from 'antd';

export default () => (
  <StyleProvider layer>
    <ConfigProvider>
      <MyApp />
    </ConfigProvider>
  </StyleProvider>
);

antd 스타일은 @layer 안에 캡슐화되어 우선순위가 낮아져요:

++  @layer antd {
      :where(.css-bAMboO).ant-btn {
        color: #fff;
      }
++  }

⚠️ zeroRuntime 시나리오 참고 (6.0.0에서 추가됨)

zeroRuntime이 활성화되면 Ant Design 스타일은 독립된 antd.css 파일로 미리 컴파일돼요. @layer 특이도 낮추기 메커니즘도 함께 켠다면, antd.css가 반드시 같은 레이어(예: layer(antd)) 안에 들어가도록 해야 해요. 그렇지 않으면 그 특이도가 StyleProvider가 주입한 스타일보다 높아져서, 낮추기 메커니즘이 실패하거나 의도치 않은 오버라이드 동작이 발생할 수 있어요.

/* global.css / app.css */
@layer theme, base, antd, components, utilities;

/* The precompiled antd.css output by zeroRuntime must explicitly specify a layer */
@import url(antd.css) layer(antd);

@import ... layer() 문법을 사용할 수 없다면, 빌드 과정에서 내용을 감싸 주는 방법을 쓸 수 있어요:

@layer antd {
  /* contents of antd.css */
}

autoPrefixer

  • antd 버전: >=6.0.0
  • 브라우저 호환성: 더 넓은 브라우저 지원을 위해 자동으로 브라우저 접두사 추가
  • 기본 활성화: 아니오

일부 스타일은 브라우저 접두사에 의존해 호환돼요. autoPrefixer 트랜스포머는 스타일에 브라우저 접두사를 자동으로 추가해, 서로 다른 브라우저에서도 잘 동작하게 보장해 줘요.

import { autoPrefixTransformer, StyleProvider } from '@ant-design/cssinjs';

export default () => (
  <StyleProvider transformers={[autoPrefixTransformer]}>
    <MyApp />
  </StyleProvider>
);

최종 변환된 스타일:

  .sample-box {
--  user-select: none;
++  -webkit-user-select: none;
++  -moz-user-select: none;
++  -ms-user-select: none;
++  user-select: none;
  }

Rem 적응

반응형 웹 개발에서는 페이지 적응과 반응형 디자인을 편리하고 유연하게 구현할 필요가 있어요. px2remTransformer 트랜스포머가 스타일 시트의 픽셀 단위를 루트 요소(HTML 태그) 기준 rem 단위로 빠르고 정확하게 변환해서, 적응형·반응형 레이아웃을 구현할 수 있게 해 줘요.

import { px2remTransformer, StyleProvider } from '@ant-design/cssinjs';

const px2rem = px2remTransformer({
  rootValue: 32, // 32px = 1rem; @default 16
});

export default () => (
  <StyleProvider transformers={[px2rem]}>
    <MyApp />
  </StyleProvider>
);

변환된 결과 스타일:

 .px2rem-box {
-  width: 400px;
+  width: 12.5rem;
   background-color: green;
-  font-size: 32px;
+  font-size: 1rem;
   border: 10PX solid #f0f;
 }

 @media only screen and (max-width: 600px) {
   .px2rem-box {
     background-color: red;
-    margin: 10px;
+    margin: 0.3125rem;
   }
 }

옵션

Parameter Description Type Default
rootValue Font size of the root element number 16
precision Decimal places for the converted value number 5
mediaQuery Whether to convert px in media queries boolean false

더 자세한 내용은 px2rem.ts#Options를 참고하세요.

Shadow DOM 사용

Shadow DOM 시나리오에서는 <style /> 태그 삽입이 일반 DOM과 달라서, @ant-design/cssinjs의 StyleProvider로 container 속성을 구성해 삽입 위치를 지정해야 해요:

import { StyleProvider } from '@ant-design/cssinjs';
import { createRoot } from 'react-dom/client';

const shadowRoot = someEle.attachShadow({ mode: 'open' });
const container = document.createElement('div');
shadowRoot.appendChild(container);
const root = createRoot(container);

root.render(
  <StyleProvider container={shadowRoot}>
    <MyApp />
  </StyleProvider>,
);

서드파티 스타일 라이브러리와의 호환

어떤 경우에는 antd가 Tailwind CSS, Emotion, styled-components 같은 다른 스타일 라이브러리와 공존해야 할 수도 있어요. 전통적인 CSS 솔루션과 달리, 이런 서드파티 라이브러리는 CSS 선택자 우선순위를 높여서 antd 스타일을 덮어쓰기가 어려운 경우가 많아요. antd에 @layer를 구성해 CSS 선택자 가중치를 낮추고, @layer 순서를 정리해서 스타일 오버라이드 문제를 해결할 수 있어요:

antd @layer 구성

앞서 언급했듯이 StyleProvider를 사용할 때는 ConfigProvider로 감싸 아이콘 관련 스타일을 갱신해야 해요:

import { StyleProvider } from '@ant-design/cssinjs';

export default () => (
  <StyleProvider layer>
    <ConfigProvider>
      <MyApp />
    </ConfigProvider>
  </StyleProvider>
);

TailwindCSS @layer 정리

아래 구성을 시작하기 전에 @layer 기능을 먼저 활성화해야 해요.

TailwindCSS v3

global.css에서 @layer를 조정해 스타일 오버라이드 순서를 제어하세요. tailwind-base를 antd 앞에 두세요:

@layer tailwind-base, antd;

@layer tailwind-base {
  @tailwind base;
}
@tailwind components;
@tailwind utilities;

TailwindCSS v4

global.css에서 @layer를 조정해 스타일 오버라이드 순서를 제어하세요. antd를 올바른 위치에 두세요:

@layer theme, base, antd, components, utilities;

@import 'tailwindcss';

reset.css와 antd.css

Ant Design의 reset.css를 사용한다면, 특이도가 낮아진 antd 스타일을 덮어쓰지 않도록 그것을 특정 @layer에 배정해야 해요. 마찬가지로 zeroRuntime 시나리오에서 antd.css를 별도로 임포트한다면, 반드시 layer(antd) 안에 두어 레이어 계층을 일관되게 유지해야 해요:

/* Both reset.css and antd.css must specify a layer */
@layer reset, antd;

/* reset styles */
@import url(reset.css) layer(reset);

/* antd styles */
@import url(antd.css) layer(antd);

이렇게 하면 다음이 보장돼요:

  • reset.css가 @layer로 낮춰진 Ant Design 스타일을 덮어쓰지 않아요
  • (zeroRuntime 모드에서) antd.css가 StyleProvider가 주입한 레이어와 정렬을 유지해요
  • Tailwind, Emotion 또는 다른 CSS-in-JS 라이브러리 같은 서드파티 스타일링 시스템과도 레이어 순서가 올바르게 동작해요

다른 CSS-in-JS 라이브러리와 함께

antd에 @layer를 구성한 뒤에는 다른 CSS-in-JS 라이브러리에는 추가 설정이 필요 없어요. 여러분의 CSS-in-JS가 antd 스타일을 완전히 덮어쓸 수 있어요.

SSR 시나리오

SSR을 사용할 때 스타일은 종종 <style />로 HTML에 인라인 렌더링돼요. 이때 특정 @layer 우선순위 순서가 있는 스타일이 @layer를 사용하기 전에 로드되도록 확인해 주세요.

❌ 잘못된 예

<head>
  <!-- SSR Injection style -->
  <style>
    @layer antd {
      /** ... */
    }
  </style>

  <!-- css file contains @layer xxx, antd; -->
  <link rel="stylesheet" href="/b9a0m0b9o0o3.css" />
  <!-- or write @layer xxx, antd; in html directly -->
  <style>
    @layer xxx, antd;
  </style>
</head>

✅ 올바른 예

<head>
  <!-- css file contains @layer xxx, antd; -->
  <link rel="stylesheet" href="/b9a0m0b9o0o3.css" />
  <!-- or write @layer xxx, antd; in html directly -->
  <style>
    @layer xxx, antd;
  </style>

  <!-- SSR Injection style -->
  <style>
    @layer antd {
      /** ... */
    }
  </style>
</head>

더 알아보기 (Learn more)