본문 바로가기

카테고리 없음

CSS로 글자 바깥쪽에 테두리를 그리는 세 가지 방법

지켜보고 있는 참새. Unsplash 에 Valentin Petkov 님이 올림.

들어가는 말

살다 보면 한 번쯤 이런 부탁을 받을지도 모릅니다.
"글자 바깥쪽 테두리에 2픽셀정도 색깔을 입히고 싶어요!"

1. -webkit-text-stroke

css에는 이런 속성이 있습니다. 가장 늦게 반영된 파이어폭스랑 엣지조차 2016년도에 적용되었으니까 지금이라면 충분히 쓸 만합니다. (인터넷 익스플로러를 쓰는 데는 군대밖에 없을 것 같으니 이젠 제발 버리도록 합시다)

 

.text {
  -webkit-text-stroke: 2px #ea00d9;
}

 

하지만 무작정 적용하기에는 문제가 있습니다. 아래 사진을 보시죠.

 

기본
-webkit-text-stroke

 

뭔가 이상합니다. 조금 더 확대해서 볼까요?

 

비교

'참' 글자에서 떨어져 있던 초성, 중성, 종성이 붙은 걸로 봐서 글자가 뚱뚱해진 건 맞는데 원래 글자도 얇아진 것 같이 보입니다. 이게 바로 -webkit-text-stroke의 문제점인데요. 글자 경계선을 기준으로 안쪽과 바깥쪽을 반반씩 먹으면서 커집니다.

 

-webkit-text-stroke의 동작 방식 상상도

만약 2px의 stroke를 준다면 이렇게 절반은 원래 글자의 밖으로, 나머지 절반은 원래 글자의 안으로 파고드는 동작을 하는 것으로 보여요. 그래서 만약 디자인이 애초에 css outline 속성처럼 글자 바깥으로만 테두리를 그리는 것을 원한다면 이 방법은 문제가 될 수 있습니다.

2. text-shadow

글자의 그림자를 사방으로 준다면 마치 테두리처럼 보이지 않을까요?

 

.text {
  text-shadow: -2px 0 #ea00d9, 0 2px #ea00d9, 2px 0 #ea00d9, 0 -2px #ea00d9;
}

 

text-shadow

글자를 먹는 것 같지는 않은데 뭔가 이상합니다.

 

확대

이런! 안타깝게도 그림자가 상하좌우에만 깔려서 대각선이 비어버렸네요. 레트로 감성을 살리는 데는 탁월한 효과겠지만 아쉽게 지금은 그럴 때가 아닙니다. 사진은 첨부하지 않았지만 상하좌우 대각선을 모두 포함해도 원하는 결과는 나오지 않았습니다.

3. ::before, ::after

그렇다면 이제 방법은 하나. 직접 테두리를 그리는 겁니다. 정확히는 '테두리'를 그리기에는 힘드니 글자 뒤쪽에 조금 더 큰 글자를 겹쳐서 놓는다면 앞에서 봤을 때 테두리처럼 보이지 않을까요? 색종이로 글자 테두리를 만들 때 일단 딱풀로 글자를 종이에 붙이고, 가위로 살짝 여유롭게 잘라주는 것처럼요.

 

그러기 위해서는 원래 글자와 테두리가 되어줄 글자 총 두 개가 필요합니다. html 태그를 하나 더 쓰는 방법도 있지만 여기서는 가상 요소를 사용해 보겠습니다.

 

.text {
  z-index: 0;
  position: relative;
}
.text::before {
  z-index: -1;
  content: attr(data-content);
  position: absolute;
  left: 0;
  /* 글자 바깥쪽으로 나갔으면 하는 테두리 크기의 두 배 */
  -webkit-text-stroke: 4px #ea00d9;
}
<p class="text" data-content="참새">참새</p>

 

가상 요소에도 글자를 넣어줘야 하기 때문에 html의 data-* 속성을 활용해서 원본과 똑같은 글자를 넘겨줍니다. 아까 -webkit-text-stroke가 안쪽과 바깥쪽을 반반 나눠서 테두리를 그린다는 것을 바탕으로 원래 목표 테두리인 2px의 두 배인 4px을 설정합니다. 이러면 글자 밖으로는 2px만큼 튀어나왔겠죠? 마지막으로 z-index를 적절히 사용해서 원본 글자 뒤로 넣어줍니다.

 

::before

이제 원하는 결과를 얻었습니다.

 

이 방법의 단점은 같은 글자를 두 번 적어야 한다는 점입니다. 변수를 활용해서 지정한다면 괜찮을 수 있지만 긴 글자를 하드코딩하듯이 박아넣어야 한다면 많이 못생기게 될 것 같아요.

번외: "그림자도 넣어주세요!"

만약 여기에 그림자를 추가로 넣고 싶다면 text-shadow를 사용해서는 안 됩니다. 테두리가 늘어난 그림자가 아니라 원래 글자 크기만큼의 그림자를 만들기 때문에 테두리를 포함한 글자보다 그림자가 작게 나와요. 그래서 아래처럼 그림자 역할을 할 가상 요소를 만들어줘야 합니다.

 

.text::after {
  z-index: -2;
  content: attr(data-content);
  position: absolute;
  left: 0;
  top: 4px;
  color: #0abdc6;
  /* 테두리를 포함해서 동일한 글자 크기를 맞춰주기 위해 같은 값의 stroke 사용 */
  -webkit-text-stroke: 4px #0abdc6;
}

 

이제 그림자까지 완성되었습니다.

 

사이버펑크 느낌의 글자 테두리와 그림자.

마치며

왜 figma의 stroke는 글자 바깥쪽으로 나오고, css로 그린 stroke는 반반 나눠먹는 걸까요. 너무 슬픕니다.

 

사용한 코드
실제 적용한 페이지