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

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'.

관련 이슈: #53143 #54255

더 알아보기 (Learn more)