SVG <symbol>에 그래픽을 한 번 정의한 다음, 표시할 각 SVG 안에서 <use>로 해당 ID를 참조하세요. 각 인스턴스에 고유한 크기를 지정하고, 주변 페이지의 배치는 CSS에 맡기세요. SVG 문서 구조.

이 튜토리얼은 Mac에서 HTML 페이지를 편집하며 여러 텍스트 레이블 옆에 같은 작은 그래픽을 배치하려는 사람을 위한 것입니다. 전체 예제는 합성 타일, 일반 HTML, CSS를 사용합니다. 프레임워크, JavaScript, 다운로드한 이미지, 빌드 단계가 필요하지 않습니다.

심볼 하나로 여러 그래픽을 어떻게 표시하나요?

<symbol>은 그래픽 템플릿입니다. 자체적으로 표시되지는 않으며, <use> 참조가 표시 가능한 인스턴스를 만듭니다. 문서에 정의를 한 번 넣고 그래픽이 필요한 곳마다 작은 SVG 래퍼를 추가하세요. MDN에 따르면 두 요소 모두 널리 사용할 수 있습니다. MDN: symbol.

반복해서 작성하는 경로를 피하는 것과 브라우저의 렌더링 작업을 피하는 것은 다릅니다. HTML에는 경로 정의가 하나만 포함되지만, 브라우저는 각 <use>에 대해 렌더링 인스턴스를 만듭니다. MDN은 이를 외부에 노출되지 않는 DOM으로 복제하는 것으로 설명합니다. 재사용하면 소스를 더 쉽게 유지 관리할 수 있지만, 표시되는 여러 그래픽이 렌더링된 객체 하나가 되는 것은 아닙니다. MDN: use.

레이블과 아이콘이 있는 페이지에서는 레이블을 HTML로 유지하고 각 아이콘에 고유한 SVG 래퍼를 제공하세요. WHATWG는 SVG를 HTML의 임베디드 콘텐츠, 프레이징 콘텐츠, 플로 콘텐츠로 인정하므로 이러한 래퍼를 일반 페이지 콘텐츠 사이에 배치할 수 있습니다. HTML 표준: SVG.

정의 하나와 인스턴스 세 개로 전체 페이지 만들기

Mac의 일반 텍스트 편집기에서 svg-reuse.html라는 파일을 만드세요. 아래의 전체 문서를 붙여 넣고 저장한 다음 데스크톱 브라우저에서 여세요. .html 확장자를 유지하고 서식 있는 텍스트 문서가 아닌 일반 텍스트로 저장하세요.

이 예제는 단일 <path>를 사용해 대각선 타일 두 개를 정의합니다. 세 개의 참조가 동일한 도형을 서로 다른 크기와 색상으로 표시합니다. 각 참조는 href="#demo-tiles"를 사용합니다. 현재는 일반 href 형식을 사용하며, xlink:href는 더 이상 사용하지 않는 방식입니다. MDN: use 속성.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Reusable tile symbol</title>
  <style>
    body {
      margin: 2rem;
      font-family: system-ui, sans-serif;
      color: #263445;
    }
    .symbol-bank {
      position: absolute;
      width: 0;
      height: 0;
      overflow: hidden;
    }
    .samples {
      display: flex;
      flex-wrap: wrap;
      gap: 1.5rem;
    }
    .sample {
      display: flex;
      align-items: center;
      gap: 0.75rem;
      padding: 1rem;
      border: 1px solid #cbd5df;
    }
    .icon {
      display: block;
      width: 24px;
      height: 24px;
      flex: none;
    }
    .icon-large { width: 48px; height: 48px; }
    .icon-medium { width: 32px; height: 32px; }
    .blue { color: #2457a7; }
    .purple { color: #7140a0; }
  </style>
</head>
<body>
  <svg class="symbol-bank" width="0" height="0" aria-hidden="true">
    <symbol id="demo-tiles" viewBox="0 0 24 24"
            preserveAspectRatio="xMidYMid meet">
      <path fill="currentColor"
            d="M4 4H10V10H4Z M14 14H20V20H14Z"></path>
    </symbol>
  </svg>

  <main>
    <h1>Tile samples</h1>
    <div class="samples">
      <div class="sample">
        <svg class="icon" width="24" height="24"
             viewBox="0 0 24 24" aria-hidden="true">
          <use href="#demo-tiles" width="24" height="24"></use>
        </svg>
        <span>Small tiles</span>
      </div>

      <div class="sample blue">
        <svg class="icon icon-large" width="48" height="48"
             viewBox="0 0 24 24" aria-hidden="true">
          <use href="#demo-tiles" width="24" height="24"></use>
        </svg>
        <span>Large tiles</span>
      </div>

      <div class="sample purple">
        <svg class="icon icon-medium" width="32" height="32"
             viewBox="0 0 24 24" aria-hidden="true">
          <use href="#demo-tiles" width="24" height="24"></use>
        </svg>
        <span>Medium tiles</span>
      </div>
    </div>
  </main>
</body>
</html>

예상 결과는 동일한 대각선 타일이 들어 있는 테두리 샘플 세 개입니다. 첫 번째는 본문 텍스트 색상, 두 번째는 파란색, 세 번째는 보라색을 사용합니다. SVG 상자의 크기는 각각 가로세로 24, 48, 32 CSS 픽셀입니다. 브라우저 창을 좁혀 샘플이 어떻게 줄 바꿈되는지 확인하세요.

여기서 도형은 장식 요소이며, 옆에 있는 레이블이 내용을 전달합니다. 그래서 SVG 래퍼에 aria-hidden="true"를 사용합니다. 이렇게 하면 시각적으로 숨기지 않으면서 접근성 트리에서 제외할 수 있습니다. 장식용 그래픽에만 이 처리를 적용하세요. 텍스트에 없는 정보를 전달하는 이미지에는 적용하지 마세요. MDN: aria-hidden.

페이지 레이아웃과 SVG 레이아웃을 제어하는 설정은 무엇인가요?

서로 다른 작업은 세 가지입니다. HTML 구성 요소 배치, 각 SVG 상자의 크기 지정, 도형을 해당 상자에 맞추기입니다. 한 작업의 설정을 바꿔도 나머지 두 작업에는 영향이 없을 수 있습니다.

작업 예제의 설정 변경할 항목
페이지에서 샘플 배치 .samples는 flexbox와 줄 바꿈을 사용 여기서 간격이나 줄 바꿈을 변경합니다
각 그래픽을 레이블에 맞춰 정렬 .sample은 flexbox와 align-items: center를 사용 여기서 구성 요소의 정렬을 변경합니다
표시되는 SVG 상자 크기 지정 .icon과 크기 클래스 여기서 CSS 너비와 높이를 변경합니다
도형 좌표 정의 viewBox="0 0 24 24" 아트워크의 좌표 범위가 바뀌면 이를 변경합니다
참조된 심볼의 내부 크기 지정 <use>의 너비와 높이는 24 이 예제의 내부 좌표 영역에 맞게 유지합니다
도형을 비율에 맞춰 표시 preserveAspectRatio="xMidYMid meet" 다른 맞춤 동작이 필요할 때만 변경합니다

Flexbox는 플렉스 컨테이너의 직계 자식 요소를 배치합니다. 따라서 바깥쪽 컨테이너는 샘플을 배치하고, 안쪽 컨테이너는 SVG를 레이블 옆에 배치합니다. Flexbox는 한 번에 한 차원으로 작동하며, 줄 바꿈된 행은 각자 독립적으로 공간을 분배합니다. 행과 열을 서로 맞춰야 하는 디자인에서는 CSS Grid가 적합한 페이지 레이아웃 대안입니다. MDN: flexbox의 기본 개념.

SVG 내부에서 <use>는 다른 레이아웃 모델을 사용합니다. x 및 y 값은 SVG 좌표계에서 그래픽을 오프셋합니다. HTML 구성 요소 사이의 간격을 설정하지는 않습니다. 너비와 높이는 참조된 심볼의 뷰포트 크기를 지정할 수 있지만, 직접 참조된 경로나 그룹을 일반적으로 확대하거나 축소하는 용도는 아닙니다. W3C: 재사용 그래픽의 레이아웃.

큰 인스턴스에도 내부 크기 24를 사용하는 이유는 무엇인가요?

바깥쪽 SVG의 viewBox은 24×24 좌표 영역을 설명합니다. 내부 좌표는 그대로 둔 채 CSS 상자 크기를 48×48픽셀로 지정할 수 있습니다. <use>가 내부 24×24 영역을 채우고, 바깥쪽 SVG가 이를 더 큰 표시 상자에 맞춥니다. MDN은 viewBox를 최소 x, 최소 y, 너비, 높이의 네 숫자로 정의합니다. MDN: viewBox.

이 아트워크를 사용한 예시 계산에서 48픽셀 상자는 24 좌표 단위를 48 / 24 = 2 배율로 표시합니다. 타일 도형의 범위는 좌표 4부터 20까지이므로 전체로 칠해진 영역은 (20 - 4) × 2 = 32픽셀이 됩니다. 나머지 공간은 도형 내부에 의도적으로 둔 여백입니다.

이 때문에 아이콘의 CSS 너비를 늘려도 실제 도형이 너비 전체를 채우지 않을 수 있습니다. 페이지 여백을 조정해 보정하기 전에 viewBox 안에서 도형의 경계를 확인하세요.

직사각형 SVG 상자에서는 어떻게 되나요?

xMidYMid meet를 사용하면 도형이 균일하게 확대·축소되고 중앙에 정렬되며, 사용 가능한 뷰포트 안에 viewBox 전체가 들어갑니다. 따라서 정사각형 도형을 가로로 긴 직사각형에 넣으면 양옆에 공간이 남습니다. none은 왜곡을 허용하고, slice은 비율을 유지하지만 viewBox의 일부가 뷰포트 밖으로 나가도록 합니다. 그래픽 전체가 표시되어야 할 때는 meet를 사용하세요. MDN: preserveAspectRatio.

각 인스턴스에 고유한 색상을 어떻게 지정하나요?

경로는 fill="currentColor"을 사용합니다. 이 키워드는 요소의 color 값을 사용하므로 동일한 도형이 주변 텍스트 색상을 따를 수 있습니다. 예제에서는 .blue 또는 .purple 규칙을 바꾸면 레이블과 타일이 모두 바뀝니다. MDN: currentColor 키워드.

이는 각 인스턴스에 스타일이 상속되기 때문에 작동합니다. SVG의 재사용 모델은 <use> 호스트에서 생성된 콘텐츠로 스타일을 상속합니다. 소스 경로에 고정 색상을 직접 선언하면 부모에서 상속되는 채우기 색상보다 우선 적용됩니다. 인스턴스마다 색상을 바꿔야 한다면 공유 도형에 고정 색상을 지정하지 마세요. W3C: 스타일 범위와 상속.

표시되는 래퍼를 통해 생성된 경로에 도달하려고 .blue path 같은 선택자에 의존하지 마세요. 생성된 콘텐츠는 재사용 섀도 트리에 속하므로 상위 요소 관계가 일반적인 중첩 HTML과 다릅니다. 래퍼나 컨테이너에 color을 지정하고 소스 도형에 currentColor를 유지하세요. W3C: 스타일 범위와 상속.

재사용한 심볼이 이상하게 보일 때 무엇을 확인해야 하나요?

참조부터 바깥쪽으로 순서대로 확인하세요. 이 순서는 그래픽이 누락된 경우와 크기 또는 위치가 잘못된 경우를 구분하므로, 각 조정이 특정 원인을 해결합니다.

  1. 대상을 확인하세요. href="#demo-tiles"가 정의의 id="demo-tiles"와 일치하는지 확인하세요. 문서 트리에서 해당 ID를 고유하게 유지하세요. W3C: id 속성.
  2. 표시되는 래퍼의 크기를 확인하세요. 크기가 0인 .symbol-bank 클래스는 정의 컨테이너에만 유지하세요. .icon에 표시된 것처럼 각 인스턴스에는 0이 아닌 상자가 필요합니다.
  3. 좌표 범위를 확인하세요. 아트워크가 선언된 viewBox 안에 들어가는지 확인하세요. 예상치 못한 빈 공간은 사용되지 않는 도형 좌표에서 생길 수 있습니다. MDN: viewBox.
  4. 참조된 요소 유형을 확인하세요. 심볼을 직접 경로 참조로 바꾼 경우 <use>의 너비와 높이를 변경해도 같은 방식으로 크기가 조정되지 않습니다. 이 패턴을 사용하려면 심볼과 viewBox을 복원하세요. MDN: use.
  5. 색상 선언을 확인하세요. 인스턴스 선택자를 더 추가하기 전에 소스에 고정 색상이 지정되어 있는지 살펴보세요.
  6. 페이지 컨테이너를 확인하세요. 그래픽은 올바르게 렌더링되지만 레이블에서 너무 멀리 떨어져 있다면 구성 요소의 CSS 간격이나 정렬을 조정하세요. MDN: flexbox의 기본 개념.

예제를 기존 페이지에 통합하려면 심볼 뱅크를 한 번 삽입하고 CSS를 병합한 뒤, 다른 구성 요소에는 표시되는 SVG 래퍼만 복사하세요. 이 작은 문서는 요소의 짝이 맞는지, ID가 고유한지, 세 참조가 단일 경로 정의로 연결되는지 구조 검사를 받았습니다. 이러한 검사만으로 브라우저 렌더링이 확인되지는 않습니다. 지원하려는 Mac 브라우저에서 페이지를 열고 크기, 간격, 색상을 확인하세요.

공유 도형을 바꾸려면 경로 정의 하나를 수정하세요. 특정 인스턴스를 바꾸려면 해당 래퍼의 크기나 상속된 색상을 수정하세요. 각 책임을 분리하면 아트워크를 재사용하면서도 각 인스턴스가 표시되는 위치를 예측 가능하게 제어할 수 있습니다.

출처