원문 캡처 · blog.master.dev
원문 캡처 · blog.master.dev

이전 글에서는 앵커 위치 지정(anchor positioning)을 활용해 두 원을 화살표로 연결했다. 이번에는 border-shape와 shape()를 사용해 원의 위치와 간격에 따라 모양이 바뀌는 곡선을 만든다. 글을 쓸 당시 이 기능을 완전히 지원하는 브라우저는 Chrome과 Edge뿐이며, Firefox와 Safari에서는 데모가 제대로 보이지 않을 수 있다.

이전 글: Two Circles, One Arrow, and Anchor Positioning의 ‘Linking the Circles’ 부분을 먼저 읽으면 앵커 위치 지정 설정을 이해하는 데 도움이 된다. 이번 글에서는 기존 코드 구조와 앵커 설정을 그대로 두고 연결선 모양을 바꾼다.

border-shape는 요소의 모양을 바꾸면서 테두리, 그림자, 윤곽선 같은 장식은 유지한다. 반면 clip-path는 요소 자체를 자르므로 테두리를 함께 표현하기 어렵다. border-shape와 shape()를 조합하면 두 점을 잇는 선을 그리고, border로 선의 두께와 색을 정할 수 있다.

css
.shape {
  border: 10px solid #000;
  border-shape: shape(from 0 0,curve to 100% 100% with 100% 0);
}

곡선을 원에 맞추기

기존 데모의 clip-path 모양을 곡선으로 바꾸면, 네 개의 연결 요소에 테두리가 각각 생겨 예상하지 못한 모양이 나타난다. 앵커 설정은 네 요소 가운데 하나만 보이도록 하고 나머지는 크기를 0으로 만든다. 하지만 테두리를 지정하면 나머지 요소도 크기가 생기기 때문이다.

이를 해결하려고 border-shape를 의사 요소에 적용하고, 본 요소에는 overflow: hidden을 둔다. 다만 이 방식은 곡선의 양 끝이 원의 중심에 맞지 않고, 원이 수평이나 수직으로 정렬되면 곡선이 사라지는 문제가 있다. border-box를 border-shape의 두 번째 값으로 지정하면 곡선의 시작과 끝을 맞출 수 있지만, overflow: hidden이 도형의 바깥 부분을 가린다.

글에서는 요소의 너비나 높이가 0일 때 의사 요소를 감추도록 컨테이너 쿼리 단위와 sign()을 사용한다. if()를 쓰면 보이지 않게 하는 대신 요소를 아예 표시하지 않을 수도 있다.

css
.link * {
  container-type: size;
}
.link *:before {
  display: if(style(calc(sign(1cqw)*sign(1cqh)) = 0):none);
}

테두리 너비가 12px이면 의사 요소의 너비와 높이는 각각 최소 24px가 된다. 따라서 본 요소가 작아질 때 곡선이 어긋날 수 있다. 글에서는 의사 요소를 inset: -12px로 바깥쪽에 일정하게 넘치게 하고, border-box 대신 padding-box를 사용해 위치를 조정한다.

css
.link > *:before {
  inset: -12px;
  border: 12px solid #556270;
  border-shape: shape(from 0 0,curve to 100% 100% with 100% 0) padding-box;
}

간격에 따라 모양 바꾸기

곡선은 shape() 명령을 바꿔 더 부드러운 형태로 만들 수 있다. 예를 들어 첫 곡선을 가운데까지 그린 뒤 smooth로 반대편 곡선을 이어 그린다. 또 컨테이너 쿼리 단위로 두 원 사이의 가로 또는 세로 거리를 확인해, 거리가 200px보다 짧으면 직선으로 바꾸고 그렇지 않으면 곡선을 유지할 수 있다.

css
.link > *:before {
  border-shape: if(
    style((100cqw < 200px) or (100cqh < 200px)):
      shape(from 0 0,line to 100% 100%);
    else:
      shape(from 0 0,curve to 50% 50% with 50% 0,smooth to 100% 100%);)
    padding-box;
}

두 모양의 구조를 같게 유지하고 곡선 제어점만 바꾸면 두 형태 사이를 부드럽게 전환할 수 있다. 선의 끝부분은 다른 의사 요소로 원형이나 화살표 모양을 추가해 꾸밀 수 있다. 글에는 shape()의 호 명령으로 원을 만들거나 CSS 변수와 수학 함수를 이용해 화살표를 그리는 예도 나온다.

이 기법은 앵커 위치 지정, 정렬을 위한 border-shape 설정, shape()를 활용한 도형 작성으로 구성된다. shape() 명령은 익숙해지는 데 연습이 필요하며, 글을 쓸 당시에는 Chrome과 Edge에서만 기능을 완전히 지원했다. 원문과 데모에서 전체 예제를 볼 수 있다.

부록: 원문 예시

text
<div class="circle" size="170px"></div> <div class="circle" size="100px"></div> <div class="link">   <a></a>   <b></b>   <c></c>   <d></d> </div>