어떤 요소에 텍스트 노드가 하나 있다고 가정해보겠습니다. 이 요소가 특정 너비를 갖고 있다고 한다면, 텍스트가 이 요소보다 길 수도 있겠죠?
아래는 네이버 메인 화면 중 일부분인데요. 텍스트가 컨테이닝 블록보다 길어지니 ...
처리된 것을 볼 수 있습니다.
이는 말줄임표 처리라고 하여, text-overflow: ellipsis
속성을 적용한 것입니다.
하지만 이 속성을 적용한다고, 무조건 텍스트가 넘치는 부분에 말줄임표 처리가 되지는 않습니다.
MDN 문서에 따르면, 이 속성을 적용하기 위해서는 2가지 속성이 추가적으로 더 필요합니다.
The text-overflow property doesn't force an overflow to occur. To make text overflow its container you have to set other CSS properties: overflow and white-space. For example:
overflow: hidden; white-space: nowrap;
그럼 이 속성이 어떻게 적용되는지 확인해보기 위해, 스타일 코드를 한번 작성해보겠습니다.
먼저, overflow: hidden
속성이 적용되려면, 블록 요소의 높이를 특정해줘야 합니다.
하지만, 이렇게 해도 말줄임표 처리가 되지 않습니다. 요소의 너비보다 텍스트가 길다면 자연적으로 줄바꿈이 발생하여 나머지 텍스트는 두번째 줄에서 이어서 시작되는데요.
이때, white-space: nowrap
속성을 적용하여, 텍스트를 모두 한줄에서 표시되도록 처리하면 앞서 적용한 속성들도 같이 적용되면서 말줄임표 처리를 구현할 수 있습니다.
예제를 보시면, 첫번째 div 요소와 두번째 div 요소의 결과가 다릅니다.
첫번째 div 요소가 말줄임표 적용이 되고 있지 않은 것 같아 보이시겠지만, 이는 블록 요소이기 때문에 직관적으로 보이지 않을 뿐입니다.
첫번째 div 요소가 텍스트 길이보다 더 줄어든다면, 말줄임표 처리가 적용 됩니다.
이를 통해, 텍스트를 감싸고 있는 요소의 너비가 텍스트 노드보다 더 작아야 말줄임표 속성이 적용됨을 알 수 있습니다.
그런데, span
과 같은 인라인 요소에는 말줄임표 속성이 적용되지 않습니다. 왜일까요?
인라인 요소는 특정 너비를 갖지 않기 때문에 컨텐츠의 크기가 곧 자신의 크기가 됩니다. 즉, 컨텐츠의 크기와 요소의 크기가 동일하므로 요소가 컨텐츠의 크기보다 작아질 수 없어 속성 적용이 되지 않는 것입니다.
이번에는 조금 더 실전적인 예시를 들어보겠습니다. 앞서 보여드린 네이버의 레이아웃 예시와 비슷합니다.
왼쪽에는 특정 너비와 높이를 가진 img
요소를, 오른쪽에는 이 이미지에 대한 설명을 담은 텍스트 요소를 배치하도록 하겠습니다. 이 두 요소를 감싸고 있는 요소에 flex
속성을 적용하면 주축을 기준으로 두 요소가 한 줄에 배치됩니다.
이미지 요소는 flex container
가 줄어들 때 크기가 변경되지 않도록, flex-grow
속성을 0
으로, 텍스트 요소는 자유자재로 늘어나고 줄어들수록 flex-grow
, flex-shrink
속성을 모두 1
로 설정합니다.
이때, 텍스트는 flex container
의 크기가 줄어들 때, 말줄임표 처리를 해야 합니다.
위에서 설명한 것들을 코드로 작성해보면 다음과 같습니다.
텍스트가 위치할 부분은 경우에 따라서 텍스트 노드만 들어갈 수도 있고, 여러 개의 요소 노드가 들어갈 수도 있기 때문에 나눠봤는데요. 일부 코드 결과에서 차이가 발생했습니다.
이 차이에 대해 언급하기 전에, 먼저 flex item
의 기본 동작 방식에 대해 알아보겠습니다.
Note: The auto keyword, representing an automatic minimum size, is the new initial value of the min-width and min-height properties. The keyword was previously defined in this specification, but is now defined in the CSS Sizing module.
To provide a more reasonable default minimum size for flex items, the used value of a main axis automatic minimum size on a flex item that is not a scroll container is a content-based minimum size; for scroll containers the automatic minimum size is zero, as usual.
위의 문구는 w3c 스펙에서 가져왔습니다. 해석을 해보면,
scroll container 가 아닌
flex item의 최소 크기는 갖고 있는 컨텐츠의 크기
가 되고,
scroll container 인
flex item의 최소 크기는 0
이 됩니다.
여기서 scroll container
란, overflow
속성 값으로 hidden
, auto
, scroll
이 적용되는 경우를 말합니다. 스크롤이 적용되는 요소라고 생각하시면 됩니다.
hidden
속성값이 스크롤이 적용될 수 있다는 것을 저도 이번에 처음 알았는데요. 그 이유는 스크롤이 적용될 수 있도록 코드를 작성할 수 있기 때문에, scroll container에 속한다고 합니다.
아래는 MDN에 정의된 hidden 속성값에 대한 설명 중 일부입니다.
The content can be scrolled programmatically (for example, by setting the value of a property such as scrollLeft or the scrollTo() method), so the element is still a scroll container.
이와 관련하여,
scrollTop
,scrollLeft
속성에 관한 설명을 간략하게 첨부합니다.
모던 자바스크립트 튜토리얼 scrollLeft와 scrollTop
어쨌든 overflow
속성의 기본값은 visible
이므로, 대부분의 요소는 갖고 있는 컨텐츠의 크기가 최소 크기가 됩니다.
정리해보면,
flex item의 최소 크기는 0이 아닌 갖고 있는 컨텐츠의 크기이기 때문에, flex container의 크기가 줄어될 때, flex item의 shrink 속성값이 0 이상이여도 갖고 있는 컨텐츠의 크기보다 더 줄어들 수 없게 됩니다.
갖고 있는 컨텐츠의 크기를 스타일 코드로 표현하면, min-width
, min-height
속성이 auto
로 지정되어 있음을 의미합니다. 최소 크기가 0
이라면 이 값이 0
이라는 뜻입니다.
이 속성값 적용 여부를 확인하시려면, 아래 순서대로 탭을 눌러주시면 됩니다.
개발자도구(F12)
- Elements tab
- Computed tab
- Filter (show all 체크)
이제 코드를 다시 살펴보겠습니다.
child 클래스를 갖고 있는 요소는 flex item
입니다.
말줄임표 처리를 위해 추가한 overflow: hidden
속성이 이 요소의 최소 크기를 0으로 변경하였습니다.
또한 이 요소에 flex-shrink: 1
속성을 적용했기 때문에, flex container의 크기가 줄어들 때, flex item 요소의 크기보다 작아진다면 shrink 속성이 트리거 되면서 flex item 요소의 크기도 줄어들게 됩니다.
따라서, 두 가지 속성을 합쳐 적용한다면, 이 요소는 자신의 크기가 줄어들 때 자신이 갖고 있는 컨텐츠의 크기보다 더 줄어들 수 있게 됩니다.
이때, 이 요소의 자식 요소로 텍스트 노드, 인라인 요소가 오는 경우에는 부모 요소에 말줄임표 속성을 적용해야 합니다.
텍스트 노드는 스타일 속성 자체를 적용할 수 없고, 인라인 요소에는 말줄임표 속성이 적용이 되지 않기 때문입니다.
결과적으로 이 경우는 자식 요소가 자신만의 너비를 갖지 않아, 처음 예시와 동일한 결과가 나타납니다.
여기서부터는 부모 요소에 말줄임표 속성을 적용하게 되면, 말줄임표 처리가 적용되지 않습니다. 왜일까요?
인라인 요소와 달리, 블록 요소의 경우에는 기본적으로 블록의 너비가 존재하므로, 해당 블록 요소가 아닌 부모 요소에 말줄임표 처리를 적용하게 되면, 부모 요소의 텍스트 노드에만 말줄임표 처리가 적용됩니다.
width 값을 부여한 인라인 블록 요소 역시 마찬가지입니다.
즉, 텍스트를 감싸고 있는 해당 블록 요소에 직접 css 스타일을 추가해야 합니다.
그런데 이때 한가지 문제가 더 발생합니다.
말줄임표 처리를 위해 한 줄로 표현된 자식 요소가 부모 요소인 flex item 밖으로 튀어 나오게 됩니다.
이는 사실 문제라기보다, 앞서 언급한 flex item
의 기본 동작 방식 때문입니다.
flex item
의 최소 크기는 자신의 컨텐츠 크기, 즉 자식 요소의 크기보다 더 줄어들 수 없으므로, 이 크기를 항상 보존해야 하는 의무를 갖고 있게 됩니다.
이로 인해, 자식 요소에 적용한 overflow: hidden
속성이 적용되지 않아 말줄임표 처리가 제대로 되지 않고 부모 요소 밖으로 자식이 튀어나오게 됩니다.
이때 부모 요소인 flex item
의 최소 크기를 0
으로 변경하게 되면, 부모 요소는 자신의 컨텐츠, 즉 자식 요소의 크기보다 더 줄어들 수 있으므로 이전과 달리, 자식 요소의 크기를 보존해야 할 의무가 사라집니다.
따라서, flex item
인 부모 요소의 크기가 줄어들 때, 자식 요소의 크기도 영향을 받아 자식 요소가 갖고 있는 텍스트 노드보다 더 줄어든다면, 말줄임표 속성이 적용됩니다.
이 케이스는 위의 것과 같은 원리로 동작하기 때문에 설명할 것이 많지 않습니다.
사실 이 케이스가 제가 작성하려고 했던 코드이면서, 이 글을 쓰게 된 이유입니다. 위의 케이스들은 이 케이스에 대한 원인을 찾아보면서 정리한 케이스라고 보시면 될 것 같습니다.
앞서, flex item
의 자식 요소로 인라인 요소가 올 경우에는 말줄임표 처리가 잘 구현이 됐었죠?
이때 인라인 요소를 1개만 사용하지 않고 n개를 사용하고, 블록 요소처럼 각자의 블록을 갖도록 부모 요소에 display: flex
, flex-direction: column
속성을 적용한다면 인라인 요소는 새로운 Block Formatting Context를 형성합니다.
이제부터는 더이상 부모 요소에 적용한 말줄임표 속성이 적용되지 않습니다.
인라인 요소가 flex item
요소로 변경되면서 새로운 bfc를 형성하기 때문에, 인라인 요소는 더이상 텍스트 노드처럼 작동하지 않게 됩니다.
따라서, 말줄임표 속성을 적용하려면 부모 요소가 아닌 인라인 요소에 직접 속성을 추가하고, flex item
의 최소 크기 또한 변경해야 합니다.
flex item
요소의 자식 요소, 그 중에서도 블록 요소 안의 텍스트를 말줄임표 처리하려면, flex item을 scroll container
로 변경하는 속성을 적용해야 합니다.
예를 들면, overflow: hidden
or min-width: 0
값을 적용하는 것입니다.
보통의 경우, flex item은 자신의 컨텐츠 크기보다 더 줄어들 수 없습니다.
flex item의 이러한 특징은 자식 요소가 누구인지에 따라 말줄임표 적용 방식이 달라집니다.
자식 요소가 특정 너비를 따로 갖지 않기 때문에, 텍스트의 길이가 곧 요소의 너비가 됩니다.
자식 요소에 말줄임표 속성을 추가해도 적용되지 않으므로, 부모 요소에 속성을 적용해야 합니다.
자식 요소의 특정 너비가 존재하기 때문에 부모 요소에 말줄임표 속성을 적용하면 안됩니다.
그러나 자식 요소에 말줄임표 속성을 적용해도, 부모 요소인 flex item이 자신의 컨텐츠 크기를 보존하고자 자식 요소를 밖으로 튀어나오게 하는 문제가 추가적으로 발생합니다.
이때 부모 요소인 flex item의 최소 크기를 0
으로 만들게 되면, flex item이 더이상 자신의 컨텐츠 크기를 보존하지 않으므로, flex item의 크기가 줄어들 때, 그 자식 요소에 적용한 말줄임표 속성도 적용될 수 있습니다.
잘봤습니다.