칸은 남는 자리를 나눠 갖는 방식으로 정해진다
이름을 붙여야 스타일을 걸 수 있다에서 값을 어디에 적고 누구에게 거는지까지 봤습니다. 이제 그 값 중에 제일 많이 쓰는 것, 자리와 크기입니다.
uGUI 에서 이 자리를 맡던 것은 RectTransform 이었습니다. 앵커, 피벗, 오프셋을 각 요소가 스스로 들고 있었고, 부모는 Layout Group 을 붙여야만 자식 배치에 끼어들 수 있었습니다. UI Toolkit 에는 앵커도 피벗도 없습니다. 반대로 되어 있습니다. 자리는 부모가 정하고 자식은 쌓입니다.
앵커가 없어지고 쌓기가 남습니다
문서 표현으로 “The layout engine uses the layout principles of Yoga, which implements a subset of Flexbox” 입니다. 웹의 Flexbox 를 부분집합으로 가져온 것입니다.
그래서 요소 하나를 보고 “이게 어디 붙어 있지” 를 알 수 없습니다. 부모가 어느 방향으로 쌓는지, 남는 자리를 누가 가져가기로 했는지를 봐야 합니다. 값을 읽는 단위가 요소에서 부모와 자식 묶음 으로 올라갑니다.
Layout Group 을 아는 사람에게는 이렇게 말하는 게 빠릅니다. 모든 요소에 Vertical Layout Group 이 기본으로 붙어 있는 상태 입니다. 붙일지 말지를 고르는 게 아니라, 방향을 무엇으로 할지만 고릅니다.
기본 방향이 세로입니다
여기서 웹을 해 본 사람이 제일 먼저 걸립니다. CSS 의 flex-direction 기본값은 row 인데, UI Toolkit 은 column 입니다. 문서가 “makes the main-axis run from top to bottom” 이라고 적어 뒀습니다.
.uxml 에 요소 셋을 넣고 아무 스타일도 안 걸면 세로로 쌓입니다. 가로로 놓고 싶으면 부모에 한 줄을 적습니다.
.row {
flex-direction: row;
}
쓸 수 있는 값은 row, row-reverse, column, column-reverse 넷입니다. -reverse 는 순서를 뒤집습니다. uxml 의 줄 순서를 그대로 두고 화면에서만 뒤집을 때 씁니다.
남는 자리를 누가 가져갑니까
칸 크기를 정하는 값이 셋입니다.
| 속성 | 하는 일 | 기본값 |
|---|---|---|
flex-basis |
나누기 전 시작 크기 | auto (내용 크기) |
flex-grow |
남는 자리를 가져가는 비율 | 0 |
flex-shrink |
모자랄 때 줄어드는 비율 | 1 |
기본값이 flex-grow: 0 이라서, 아무것도 안 적으면 각 칸은 내용만큼만 차지하고 남는 자리는 빈 채로 남습니다. 늘리고 싶은 칸에만 flex-grow: 1 을 겁니다.
주의할 조합이 하나 있습니다. 칸 셋에 전부 flex-grow: 1 을 줘도 칸 크기가 같아지지 않습니다. 시작 크기가 내용 크기라서, 남는 자리만 똑같이 나눠 가질 뿐입니다. 진짜로 삼등분하려면 시작 크기를 0 으로 놓아야 합니다.
.item {
flex-grow: 1;
flex-basis: 0;
}
문서가 이 조합을 “ensures an even split regardless of content” 라고 적어 뒀습니다. 위 인터랙티브에서 전부 1 과 전부 1, basis 0 을 번갈아 보면 차이가 보입니다.
축이 둘이고, 각각 쓰는 속성이 다릅니다
쌓이는 방향을 주축, 그에 직각인 방향을 교차축이라고 부릅니다. 정하는 속성이 다릅니다.
| 축 | 속성 | 값 |
|---|---|---|
| 주축 | justify-content |
flex-start flex-end center space-between space-around |
| 교차축 | align-items |
flex-start flex-end center stretch |
| 교차축 (한 칸만) | align-self |
위와 같고 auto 가 추가 |
align-items 의 기본값이 stretch 입니다. 이것 때문에 처음에 헷갈리는 장면이 하나 나옵니다. 세로로 쌓은 칸에 가로 폭을 하나도 안 줬는데 부모 폭을 꽉 채우고 있습니다. 교차축이 늘어나기 때문입니다.
내용 크기만큼만 쓰고 싶으면 부모에 align-items: flex-start 를 주거나, 그 칸에만 align-self: flex-start 를 줍니다.
줄바꿈은 flex-wrap 입니다. nowrap 이 기본이고 wrap, wrap-reverse 가 있습니다. uGUI 의 Grid Layout Group 에 해당하는 것이 따로 없어서, 격자는 보통 flex-wrap: wrap 에 칸 폭을 정해서 만듭니다.
크기는 세 군데에서 옵니다
width 와 height 를 직접 적는 것이 첫째입니다. px 와 % 를 씁니다. % 는 부모 크기 기준입니다.
둘째가 위에서 본 flex-basis 와 flex-grow 입니다. 셋째가 아무것도 안 적었을 때의 내용 크기입니다.
경계는 min-width max-width min-height max-height 로 겁니다. flex-shrink 가 기본 1 이라 칸은 기본적으로 줄어드는데, 글자가 뭉개지면 안 되는 칸에는 min-width 를 걸어 두는 쪽이 낫습니다.
짧은 글자일수록 번역에서 더 길어진다에서 본 문제가 여기서도 똑같습니다. 다른 점은 uGUI 의 Content Size Fitter 에 해당하는 것이 따로 없다는 것입니다. 아무것도 안 적으면 그게 이미 내용 크기입니다.
겹쳐 놓을 때만 absolute 입니다
쌓기로 안 되는 배치가 있습니다. 배지를 아이콘 오른쪽 위에 얹는다든가, 팝업을 화면 위에 띄운다든가 하는 것입니다. 그때 쓰는 것이 position 입니다.
기본값은 relative 이고, 이때 요소는 쌓기 흐름 안에 있습니다. left 나 top 을 주면 자기 자리를 그대로 차지한 채로 그만큼 밀려납니다.
absolute 는 다릅니다. 문서 표현으로 “Absolute mode makes an element invisible to the default Flexbox-based layout engine” 입니다. 흐름에서 빠지기 때문에 형제들 배치가 그 요소를 없는 것으로 치고 다시 잡힙니다.
여기서 uGUI 의 앵커와 만나는 지점이 하나 있습니다. left 와 right 를 둘 다 주면 칸이 그 사이만큼 늘어납니다. top 과 bottom 도 마찬가지입니다. RectTransform 의 stretch 앵커가 하던 일이 이 두 줄입니다.
.overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
다만 문서가 남용을 막아 뒀습니다. “Avoid using Absolute position mode because it bypasses the built-in layout engine in UI Toolkit and can lead to high-maintenance UI.” 오버레이와 팝업에는 맞고, 일반 배치를 이걸로 짜면 화면 크기가 바뀔 때마다 손이 갑니다.
숨기는 방법이 두 가지입니다
한 칸이 바뀌면 그 캔버스는 통째로 다시 계산된다에서 uGUI 쪽 창 숨기기 세 가지를 봤습니다. 여기서 그 자리에 있는 것이 두 줄입니다.
| 적는 것 | 칸 | 언제 |
|---|---|---|
display: none |
칸까지 없어집니다 | 목록에서 항목을 빼듯 배치가 다시 잡혀야 할 때 |
visibility: hidden |
칸은 그대로 남습니다 | 자리는 지키고 안 보이게만 할 때 |
문서 표현으로 “Set the visibility to hidden to hide the element, but the element still occupies space in the layout” 입니다. display 쪽은 값이 flex 와 none 둘뿐입니다. CSS 의 display 를 아는 사람에게는 이 부분이 좁아 보이는데, 문서가 “supports keywords that work with the Yoga layout engine” 이라고 이유를 적어 뒀습니다.
opacity: 0 도 있습니다. 칸도 그대로이고 값이 0 과 1 사이로 이어져서, 페이드처럼 전환이 필요한 자리에 씁니다.
내용이 넘칠 때 자르는 것은 overflow 입니다. 기본값이 visible 이라 안 잘립니다. 스크롤 영역이나 카드 안쪽처럼 잘려야 하는 곳에는 overflow: hidden 을 직접 적어야 합니다.
정리
- 앵커와 피벗이 없습니다. 부모가 방향을 정하고 자식이 쌓입니다. 모든 요소에 Layout Group 이 붙어 있는 상태라고 보면 됩니다
- 기본 방향이
column입니다. CSS 의 기본값과 다릅니다 flex-grow기본값이0이라 안 적으면 내용 크기입니다. 남는 자리를 나누려면 적어야 합니다- 전부
flex-grow: 1이어도 크기가 같아지지 않습니다. 똑같이 나누려면flex-basis: 0을 같이 줍니다 - 주축은
justify-content, 교차축은align-items입니다.align-items기본값이stretch라서 폭을 안 줘도 꽉 찹니다 position: absolute는 흐름에서 빠집니다.left와right를 둘 다 주면 stretch 앵커처럼 늘어납니다. 오버레이에만 씁니다display: none은 칸까지 없애고visibility: hidden은 칸을 남깁니다.overflow기본값은visible이라 안 잘립니다