웹 페이지를 피그마로 가져올 때 아이콘이 사라지는 이유
다 들어왔는데 아이콘만 안 왔습니다. 빈 상자거나 검은 사각형이거나 작은 네모예요. 원인이 네 가지고, 어느 쪽이냐에 따라 고칠 수 있는지가 갈립니다.
페이지를 피그마로 옮겼는데 아이콘만 안 왔습니다. 화살표와 돋보기와 외부 링크 표시가 있던 자리에 빈 사각형이 있거나, 검은 덩어리가 있거나, 아무것도 없어요.
이건 버그 하나가 아닙니다. 웹에서 아이콘을 그리는 방식이 완전히 다른 네 가지가 있고, 각각 다르게 깨져요. 지금 보고 있는 게 어느 쪽인지 알면 고칠 수 있는지 없는지, 어떻게 고쳐야 하는지가 나옵니다.
네 가지 아이콘과 각각의 실패 방식
1. 인라인 SVG
가장 쉬운 경우입니다. 아이콘이 HTML 안에 <svg> 요소로 직접 쓰여 있고 path도 거기 있어요. DOM을 읽는 변환기라면 도형을 그대로 보고 피그마에 벡터로 넘길 수 있습니다.
이게 실패한다면 보통 변환기가 뭔가를 뭉갠 경우입니다. 다른 곳에 정의된 심볼을 <use>로 참조하고 있거나, CSS filter가 걸려 있거나, currentColor로 칠해져 있는데 상속 맥락을 벗어나 색이 없어졌거나요.
2. SVG 스프라이트
파일 하나에 모든 아이콘이 <symbol>로 들어 있고, 아이콘이 쓰이는 자리에는 참조만 있습니다.
<svg class="icon"><use href="/icons.svg#chevron-down" /></svg>
웹에서는 효율적이지만 단순한 변환기 눈에는 안 보입니다. DOM에 있는 그 요소 안에는 path가 없거든요. 곧이곧대로 읽으면 빈 <svg>가 나오고, 그래서 스프라이트는 크기만 맞는 빈 상자로 들어오는 일이 잦습니다.
해결하려면 참조를 따라가서 스프라이트 파일을 받아오고, id로 심볼을 찾아서 도형을 끼워 넣어야 합니다. 스프라이트가 다른 출처에 있다면 그 요청 자체가 허용돼야 하고요.
3. 아이콘 폰트
아이콘이 폰트의 한 글자인 경우입니다. Font Awesome이나 Material Icons, 사내 아이콘 폰트가 다 이 방식이에요. 클래스가 붙은 요소, ::before 가상 요소, 유니코드 사용자 영역의 코드포인트를 담은 content 속성으로 이루어집니다.
.fa-search::before { content: "\f002"; }
두 가지가 어긋납니다. 먼저 아이콘이 가상 요소에 살고 있는데 이건 DOM에 없어요. 요소 트리를 아무리 훑어도 나오지 않습니다. 그리고 변환기가 이걸 텍스트로 잡아냈다 해도, 피그마에는 그 글자 자체로 들어옵니다. 아이콘 폰트가 내 컴퓨터에 없으면 피그마는 대체 글꼴이 가진 걸 그리죠. 빈 네모거나 엉뚱한 글자가요.
가져온 페이지가 작은 사각형투성이인 그 흔한 증상이 여기서 나옵니다.
4. CSS 마스크 아이콘
따로 다룰 만합니다. 점점 흔해지고 있고, 성공한 것처럼 보이는 방식으로 실패하거든요. 요소에 내용이 아예 없고 배경색과 마스크만 있습니다.
.icon {
background-color: currentColor;
-webkit-mask-image: url(/icons/search.svg);
mask-size: contain;
}
모양은 마스크 이미지에 있고 색은 요소에 있습니다. 배경을 읽는 변환기는 아이콘 색으로 칠해진 사각형을 얻어요. 그래서 이 경우는 아무것도 없는 게 아니라 검거나 색이 있는 네모로 들어옵니다. 색은 맞고 모양이 사라진 거죠.
VitePress로 만든 문서 사이트가 이 방식을 많이 씁니다. 저희가 처음 이 문제를 만난 것도 그래서였어요. 어떤 문서 사이트의 아이콘이 전부 검은 사각형으로 들어왔다는 제보를 받았거든요.
변환기들이 놓치는 이유
네 가지를 다 처리하려면 네 가지 다른 일을 해야 하는데, 그중 셋은 DOM을 읽는 것 이상이 필요합니다.
- 스프라이트는 참조된 파일을 받아와서 심볼을 꺼내야 합니다.
- 아이콘 폰트는 가상 요소의 스타일을 읽고 코드포인트를 해석해서, 글자로 넘기는 대신 글리프를 벡터로 그려야 합니다.
- 마스크 아이콘은 마스크 이미지를 받아오고, 요소의 색을 사각형이 아니라 그 결과 도형에 입혀야 합니다.
DOM만 훑어서 찾은 걸 복사하는 변환기는 첫 번째만 되고 나머지는 조용히 실패합니다. 드문 동작이 아니라 흔한 동작이에요.
내가 어느 경우인지 알아보는 법
페이지를 열고 아이콘에서 우클릭해 검사하면 30초면 나옵니다.
| 검사 도구에 보이는 것 | 종류 | 보통 이렇게 깨짐 |
|---|---|---|
안에 <path>가 있는 <svg> | 인라인 SVG | 대개 정상 |
<use href="…#id">가 있는 <svg> | 스프라이트 | 빈 상자 |
아이콘 클래스가 붙고 자식이 없는 <i>나 <span> | 아이콘 폰트 | 빠진 글자 네모 |
계산된 스타일에 mask-image가 있는 요소 | CSS 마스크 | 색만 있는 사각형 |
Snapture는 각각을 어떻게 처리하나
네 가지 모두 처리합니다. "아이콘 지원합니다"는 어느 도구나 하는 말이라 어떻게 하는지를 구체적으로 적어 둘게요.
- 인라인 SVG는 벡터 도형 그대로 넘어갑니다. 다만 중첩 마스크나 filter,
foreignObject처럼 피그마 임포터가 감당 못 할 만큼 복잡한 SVG는 래스터로 바꿉니다. 조용한 실패가 아니라 의도적인 품질 저하예요. - 스프라이트는
<use>참조를 따라가 스프라이트를 받아오고, 해당 심볼의 도형을 올바른 viewBox와 함께 끼워 넣습니다. - 아이콘 폰트는 가상 요소의 계산된
content를 읽어서 감지하고, 글리프를 도형으로 그립니다. 피그마에 글자로 넘기지 않아요. 아이콘 폰트가 설치돼 있는지에 결과가 좌우되지 않습니다. - CSS 마스크 아이콘은 마스크 이미지를 받아와서 요소 자신의 색을 그 도형에 입힙니다. 색칠된 사각형이 아니라 제 색을 가진 아이콘으로 들어와요.
실측 페이지에 올린 측정에서 Linear 홈페이지는 벡터 노드 215개, Stripe는 153개가 나왔습니다. 대부분이 아이콘 작업이고, 편집할 수 있는 파일과 구멍 뚫린 파일의 차이가 여기서 갈립니다.
이미 깨진 파일이 있다면
래스터로 굳은 검은 사각형은 되살릴 방법이 없습니다. 모양 정보가 애초에 파일에 들어오지 않았거든요. 그 경우를 처리하는 도구로 다시 가져오는 수밖에 없습니다.
예외는 아이콘 폰트입니다. 글자로 들어왔고 아이콘 폰트가 내 컴퓨터에 설치돼 있다면 피그마가 제대로 그려 줍니다. 다만 그 폰트가 없는 사람이 파일을 열면 깨져요. 나만 제대로 보이는 파일을 넘기느니 다시 가져오는 게 낫습니다.
내 페이지로 직접 해보세요 무료 캡처 5회, 전 기능 포함. 카드도 계정도 필요 없어요.English · 한국어 · 日本語 · 简体中文 · 繁體中文 · Español · Português · Français · Deutsch · Русский · Italiano · Bahasa Indonesia