Anchor
Anchor (앵커)
Anchor는 페이지에 앵커 하이퍼링크를 표시하고 그 사이를 이동할 수 있게 해 주는 컴포넌트예요.
출처: 문서
본문
언제 사용하나요
페이지에 앵커 하이퍼링크를 표시하고 그 사이를 점프할 때 사용해요.
개발자 참고
4.24.0버전 이후부터 Anchor를 FC(Function Component)로 다시 작성했어요.ref를 얻거나 내부 인스턴스 메서드를 호출하는 일부 방법은 더 이상 동작하지 않아요.
예제 (Examples)
기본 (Basic)
가장 단순한 사용법이에요.
import React from 'react';
import { Anchor, Col, Row } from 'antd';
const App: React.FC = () => (
<Row>
<Col span={16}>
<div id="part-1" style={{ height: '100vh', background: 'rgba(255,0,0,0.02)' }} />
<div id="part-2" style={{ height: '100vh', background: 'rgba(0,255,0,0.02)' }} />
<div id="part-3" style={{ height: '100vh', background: 'rgba(0,0,255,0.02)' }} />
</Col>
<Col span={8}>
<Anchor
items={[
{
key: 'part-1',
href: '#part-1',
title: 'Part 1',
},
{
key: 'part-2',
href: '#part-2',
title: 'Part 2',
},
{
key: 'part-3',
href: '#part-3',
title: 'Part 3',
},
]}
/>
</Col>
</Row>
);
export default App;
가로 앵커 (Horizontal Anchor)
가로로 정렬된 앵커예요.
import React from 'react';
import { Anchor } from 'antd';
const App: React.FC = () => (
<>
<div style={{ padding: '20px' }}>
<Anchor
direction="horizontal"
items={[
{
key: 'part-1',
href: '#part-1',
title: 'Part 1',
},
{
key: 'part-2',
href: '#part-2',
title: 'Part 2',
},
{
key: 'part-3',
href: '#part-3',
title: 'Part 3',
},
]}
/>
</div>
<div>
<div
id="part-1"
style={{
width: '100vw',
height: '100vh',
textAlign: 'center',
background: 'rgba(0,255,0,0.02)',
}}
/>
<div
id="part-2"
style={{
width: '100vw',
height: '100vh',
textAlign: 'center',
background: 'rgba(0,0,255,0.02)',
}}
/>
<div
id="part-3"
style={{ width: '100vw', height: '100vh', textAlign: 'center', background: '#FFFBE9' }}
/>
</div>
</>
);
export default App;
정적 앵커 (Static Anchor)
페이지가 스크롤돼도 상태를 바꾸지 않아요.
import React from 'react';
import { Anchor } from 'antd';
const App: React.FC = () => (
<Anchor
affix={false}
items={[
{
key: '1',
href: '#anchor-demo-basic',
title: 'Basic demo',
},
{
key: '2',
href: '#anchor-demo-static',
title: 'Static demo',
},
{
key: '3',
href: '#api',
title: 'API',
children: [
{
key: '4',
href: '#anchor-props',
title: 'Anchor Props',
},
{
key: '5',
href: '#link-props',
title: 'Link Props',
},
],
},
]}
/>
);
export default App;
onClick 이벤트 커스터마이즈
앵커를 클릭해도 히스토리를 기록하지 않아요.
import React from 'react';
import { Anchor } from 'antd';
const handleClick = (
e: React.MouseEvent<HTMLElement>,
link: {
title: React.ReactNode;
href: string;
},
) => {
e.preventDefault();
console.log(link);
};
const App: React.FC = () => (
<Anchor
affix={false}
onClick={handleClick}
items={[
{
key: '1',
href: '#anchor-demo-basic',
title: 'Basic demo',
},
{
key: '2',
href: '#anchor-demo-static',
title: 'Static demo',
},
{
key: '3',
href: '#api',
title: 'API',
children: [
{
key: '4',
href: '#anchor-props',
title: 'Anchor Props',
},
{
key: '5',
href: '#link-props',
title: 'Link Props',
},
],
},
]}
/>
);
export default App;
앵커 하이라이트 커스터마이즈
앵커 하이라이트를 커스터마이즈해요.
import React from 'react';
import { Anchor } from 'antd';
const getCurrentAnchor = () => '#anchor-demo-static';
const App: React.FC = () => (
<Anchor
affix={false}
getCurrentAnchor={getCurrentAnchor}
items={[
{
key: '1',
href: '#anchor-demo-basic',
title: 'Basic demo',
},
{
key: '2',
href: '#anchor-demo-static',
title: 'Static demo',
},
{
key: '3',
href: '#api',
title: 'API',
children: [
{
key: '4',
href: '#anchor-props',
title: 'Anchor Props',
},
{
key: '5',
href: '#link-props',
title: 'Link Props',
},
],
},
]}
/>
);
export default App;
Anchor 스크롤 오프셋 설정
앵커 대상이 화면 중앙으로 스크롤되게 해요.
import React, { useEffect, useState } from 'react';
import { Anchor, Col, Row } from 'antd';
const style: React.CSSProperties = {
height: '30vh',
backgroundColor: 'rgba(0, 0, 0, 0.85)',
position: 'fixed',
top: 0,
insetInlineStart: 0,
width: '75%',
color: '#fff',
};
const App: React.FC = () => {
const topRef = React.useRef<HTMLDivElement>(null);
const [targetOffset, setTargetOffset] = useState<number>();
useEffect(() => {
setTargetOffset(topRef.current?.clientHeight);
}, []);
return (
<div>
<Row>
<Col span={18}>
<div
id="part-1"
style={{ height: '100vh', background: 'rgba(255,0,0,0.02)', marginTop: '30vh' }}
>
Part 1
</div>
<div id="part-2" style={{ height: '100vh', background: 'rgba(0,255,0,0.02)' }}>
Part 2
</div>
<div id="part-3" style={{ height: '100vh', background: 'rgba(0,0,255,0.02)' }}>
Part 3
</div>
</Col>
<Col span={6}>
<Anchor
targetOffset={targetOffset}
items={[
{ key: 'part-1', href: '#part-1', title: 'Part 1' },
{ key: 'part-2', href: '#part-2', title: 'Part 2' },
{ key: 'part-3', href: '#part-3', title: 'Part 3' },
]}
/>
</Col>
</Row>
<div style={style} ref={topRef}>
<div>Fixed Top Block</div>
</div>
</div>
);
};
export default App;
앵커 링크 변경 감지
앵커 링크의 변경을 감지해요.
import React from 'react';
import { Anchor } from 'antd';
const onChange = (link: string) => {
console.log('Anchor:OnChange', link);
};
const App: React.FC = () => (
<Anchor
affix={false}
onChange={onChange}
items={[
{
key: '1',
href: '#anchor-demo-basic',
title: 'Basic demo',
},
{
key: '2',
href: '#anchor-demo-static',
title: 'Static demo',
},
{
key: '3',
href: '#api',
title: 'API',
children: [
{
key: '4',
href: '#anchor-props',
title: 'Anchor Props',
},
{
key: '5',
href: '#link-props',
title: 'Link Props',
},
],
},
]}
/>
);
export default App;
history에서 href 대체 (Replace href in history)
브라우저 히스토리에서 경로를 대체해, 뒤로 가기 버튼이 이전 앵커 항목이 아니라 이전 페이지로 돌아가게 해요.
import React from 'react';
import { Anchor, Col, Row } from 'antd';
const App: React.FC = () => (
<Row>
<Col span={16}>
<div id="part-1" style={{ height: '100vh', background: 'rgba(255,0,0,0.02)' }} />
<div id="part-2" style={{ height: '100vh', background: 'rgba(0,255,0,0.02)' }} />
<div id="part-3" style={{ height: '100vh', background: 'rgba(0,0,255,0.02)' }} />
</Col>
<Col span={8}>
<Anchor
replace
items={[
{
key: 'part-1',
href: '#part-1',
title: 'Part 1',
},
{
key: 'part-2',
href: '#part-2',
title: 'Part 2',
},
{
key: 'part-3',
href: '#part-3',
title: 'Part 3',
},
]}
/>
</Col>
</Row>
);
export default App;
커스텀 시맨틱 DOM 스타일링
classNames와 styles에 객체/함수를 전달해 Anchor의 시맨틱 DOM 스타일을 커스터마이즈할 수 있어요.
import React from 'react';
import { Anchor, Col, Row } from 'antd';
import type { AnchorProps, GetProp } from 'antd';
const classNamesObject: AnchorProps['classNames'] = {
root: 'demo-anchor-root',
item: 'demo-anchor-item',
itemTitle: 'demo-anchor-title',
indicator: 'demo-anchor-indicator',
};
const stylesFn: AnchorProps['styles'] = (info): GetProp<AnchorProps, 'styles', 'Return'> => {
if (info.props.direction === 'vertical') {
return {
root: {
backgroundColor: 'rgba(255,251,230,0.5)',
height: '100vh',
},
};
}
return {};
};
const items: NonNullable<AnchorProps['items']> = [
{
key: 'part-1',
href: '#part-1',
title: 'Part 1',
},
{
key: 'part-2',
href: '#part-2',
title: 'Part 2',
},
{
key: 'part-3',
href: '#part-3',
title: 'Part 3',
},
];
const App: React.FC = () => {
return (
<Row>
<Col span={16}>
<div id="part-1" style={{ height: '100vh', background: 'rgba(255,0,0,0.08)' }} />
<div id="part-2" style={{ height: '100vh', background: 'rgba(0,255,0,0.08)' }} />
<div id="part-3" style={{ height: '100vh', background: 'rgba(0,0,255,0.08)' }} />
</Col>
<Col span={8}>
<Anchor replace items={items} styles={stylesFn} classNames={classNamesObject} />
</Col>
</Row>
);
};
export default App;
API
공통 props 참고: Common props
Anchor Props
| 속성 | 설명 | 타입 | 기본값 | 버전 | 전역 설정 |
|---|---|---|---|---|---|
| affix | Anchor의 고정 모드 | boolean | Omit<AffixProps, 'offsetTop' | 'target' | 'children'> | true | object: 5.19.0 | × |
| bounds | 앵커 영역의 경계 거리 | number | 5 | × | |
| classNames | 컴포넌트 내부 각 시맨틱 구조의 클래스를 커스터마이즈. 객체 또는 함수 지원 | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | 6.0.0 | |
| getContainer | 스크롤 컨테이너 | () => HTMLElement | () => window | × | |
| getCurrentAnchor | 앵커 하이라이트 커스터마이즈 | (activeLink: string) => string | - | × | |
| offsetTop | 스크롤 위치 계산 시 위로부터의 오프셋 픽셀 | number | 0 | × | |
| showInkInFixed | affix={false}일 때 ink-square를 표시할지 여부 |
boolean | false | × | |
| styles | 컴포넌트 내부 각 시맨틱 구조의 인라인 스타일 커스터마이즈. 객체 또는 함수 지원 | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | 6.0.0 | |
| targetOffset | Anchor 스크롤 오프셋, 기본값은 offsetTop, 예시 |
number | - | × | |
| onChange | 앵커 링크 변경 감지 | (currentActiveLink: string) => void | - | × | |
| onClick | click 이벤트를 처리하는 핸들러 설정 |
(e: MouseEvent, link: object) => void | - | × | |
| items | 데이터 설정 옵션 콘텐츠. children으로 중첩 지원 | { key, href, title, target, children }[] 참고 | - | 5.1.0 | × |
| direction | Anchor 방향 설정 | vertical | horizontal |
vertical |
5.2.0 | × |
| replace | 브라우저 히스토리에 push 대신 items의 href를 replace | boolean | false | 5.7.0 | × |
AnchorItem
| 속성 | 설명 | 타입 | 기본값 | 버전 |
|---|---|---|---|---|
| key | Anchor 링크의 고유 식별자 | string | number | - | |
| href | 하이퍼링크의 대상 | string | - | |
| target | 연결된 URL을 표시할 위치 지정 | string | - | |
| title | 하이퍼링크의 내용 | ReactNode | - | |
| children | 중첩 Anchor 링크, 주의: 이 속성은 가로 방향을 지원하지 않아요 |
AnchorItem[] | - | |
| replace | 브라우저 히스토리에 push 대신 항목 href를 replace | boolean | false | 5.7.0 |
| targetOffset | 이 앵커 링크의 스크롤 오프셋 커스터마이즈. Anchor 컴포넌트의 targetOffset prop보다 우선 |
number | - | 6.4.0 |
Link Props
items 형식을 사용하는 것을 권장해요.
| 속성 | 설명 | 타입 | 기본값 | 버전 |
|---|---|---|---|---|
| href | 하이퍼링크의 대상 | string | - | |
| target | 연결된 URL을 표시할 위치 지정 | string | - | |
| title | 하이퍼링크의 내용 | ReactNode | - | |
| targetOffset | 이 앵커 링크의 스크롤 오프셋 커스터마이즈. Anchor 컴포넌트의 targetOffset prop보다 우선 |
number | - | 6.4.0 |
시맨틱 DOM (Semantic DOM)
https://ant.design/components/anchor/semantic.md
디자인 토큰 (Design Token)
컴포넌트 토큰 (Anchor)
| 토큰 이름 | 설명 | 타입 | 기본값 |
|---|---|---|---|
| linkPaddingBlock | 링크의 세로 패딩 | number | 4 |
| linkPaddingInlineStart | 링크의 가로 패딩 | number | 16 |
전역 토큰 (Global Token)
| 토큰 이름 | 설명 | 타입 | 기본값 |
|---|---|---|---|
| colorPrimary | 브랜드 색은 제품의 특성과 커뮤니케이션을 반영하는 가장 직접적인 시각 요소 중 하나. 브랜드 색을 선택하면 완전한 색 팔레트가 자동 생성되고 유효한 디자인 시맨틱이 할당됨. | string | |
| colorSplit | 구분선 색으로 사용됨. colorBorderSecondary와 같지만 투명도가 있음. | string | |
| colorText | W3C 표준을 준수하는 기본 텍스트 색. 가장 어두운 중성색이기도 함. | string | |
| fontFamily | 시스템 기본 인터페이스 폰트와 화면 표시에 적합한 대체 폰트 라이브러리 세트를 제공해 플랫폼·브라우저에서 가독성을 유지. | string | |
| fontSize | 디자인 시스템에서 가장 널리 사용되는 폰트 크기. | number | |
| fontSizeLG | 큰 폰트 크기 | number | |
| lineHeight | 텍스트의 줄 높이. | number | |
| lineType | 기본 컴포넌트의 테두리 스타일 | string | |
| lineWidth | 기본 컴포넌트의 테두리 너비 | number | |
| lineWidthBold | Button, Input, Select 등 아웃라인 계열 컴포넌트의 기본 선 너비 | number | |
| motionDurationSlow | 모션 속도, 느린 속도. 대형 요소 애니메이션 상호작용에 사용 | string | |
| paddingXXS | 요소의 매우 작은 여분의 패딩 제어 | number |
FAQ
5.25.0+ 버전에서 앵커 내비게이션 후 대상 요소의 :target 의사 클래스가 예상대로 동작하지 않아요. {#faq-target-pseudo-class}
페이지 성능 최적화를 위해 앵커 내비게이션 구현이 window.location.href에서 window.history.pushState/replaceState로 바뀌었어요. pushState/replaceState는 페이지 새로고침을 일으키지 않기 때문에, 브라우저가 :target 의사 클래스의 매칭 상태를 자동으로 갱신하지 않아요. 이 문제를 해결하려면 전체 URL을 직접 구성할 수 있어요: href = window.location.origin + window.location.pathname + '#xxx'.
더 알아보기 (Learn more)
- Affix 컴포넌트 — 고정 컨테이너
- BackTop 컴포넌트 — 페이지 상단으로
- Ant Design 시작하기 — 프로젝트 설정