NARADESIGN

웹표준, 웹접근성, 유니버설디자인, HTML, CSS, UI, UX, UD


CSS flexible 레이아웃: flex item의 팽창과 수축.

본문 건너 뛰기

오늘은 흔히 flex 또는 flexible 박스 모델이라고 부르는 CSS Flexsible box layout module level 1(Candidate Recommendation) 명세를 설명해 보려고 합니다. 아직 표준 후보 단계이지만 현존하는 최신 브라우저에 flexible box layout module은 이미 구현되어 있습니다.

기존에 우리가 사용하던 레이아웃 기법은 display, float, position 으로써 컬럼 레이아웃을 표현하는데 한계가 있고 구현 방법이 복잡한 문제가 있었는데요. flexible(신축성 있는, 유연한) 박스 모델의 장점을 한 마디로 표현하면 “복잡한 계산 없이 박스의 크기와 순서를 유연하게 배치할 수 있다.” 라고 정리할 수 있습니다. 쉬운 예를 들면 컬럼의 한 쪽은 고정하고 다른 한 쪽을 가변폭으로 처리하고 싶을 때 유용하지만 그것 이상의 편의를 제공합니다. 어떤 속성과 값을 통해 무엇을 할 수 있는지 설명해 보겠습니다.

플렉스 컨테이너와 플렉스 아이템(flex container & flex item)의 개념.

flex 박스 모델은 tr/td 개념와 유사합니다.  flex 박스는 flex container(부모, 마치 tr)와 flex item(자식, 마치 td)으로 이루어 집니다. flex container 요소에 display 속성의 값을 flex 또는 inline-flex 라고 선언하면 해당 요소는 flex container가 되고 자식 요소는 자동으로 flex item이 되어 flex 박스로 렌더링하기 시작합니다.

flex container

flex container는 flex item의 면적, 방향, 정렬을 결정하는 컨테이너 입니다. flex container 요소에 display 속성의 값으로 inline-flex를 선언하면 인라인 수준의 flex container를 생성하고, flex 값을 선언하면 블럭 수준의 flex container를 생성합니다. inline-flex 상태의 컨테이너는 inline-block 박스와 같은 형태로 표시합니다.

flex item

flex item은 컨테이너 내부에 형성된 free space(남거나 모자라는 공간, margin과 유사한 개념이지만 margin은 아님)를 팽창지수 또는 수축지수 값에 따라 형제들이 서로 나누어 갖습니다. flex container에 inline-flex 또는 flex 값을 선언하면 자식 요소들은 자동으로 flex item이 됩니다. flex item의 기본적인 스타일(User Agent 기본값)은 다음과 같습니다. 기본 스타일(flex-grow:0; flex-shrink:1; flex-basis:auto; flex-direction:row; flex-wrap:nowrap;)은 개발자가 변경할 수 있으며, 단축 속성(flex)을 사용할 때 값이 자동으로 재설정(flex item의 단축 속성 ‘flex’ 참고)되기도 합니다.

  • 여분의 free space가 있어도 폭이 저절로 늘어나지 않습니다.(flex-grow:0)
  • 부모 박스 초과 시(이 때 flex container 내부에 음수 free space 발생) 자동으로 균등 수축(음수 free space 크기 ÷ flex item 개수)합니다.(flex-shrink:1)
  • 콘텐츠 너비만큼 수축합니다.(flex-basis:auto)
  • 행으로 배치 합니다.(flex-derection:row)
  • 개행하지 않습니다.(flex-wrap:nowrap)
  • 텍스트 노드도 익명 flex item이 됩니다. 공백은 flex item이 되지 않습니다.

그 밖에 이런 특징도 있습니다.

  • float 속성은 무시합니다.
  • position:absolute|fixed 속성이 부여되면 flex item에서 빠지게 됩니다.
  • flex item은 형제 또는 부모와 수직 또는 수평 margin을 중첩하지 않습니다.
  • 브라우저마다 구현이 다를 수 있기 때문에 margin/padding의 값으로 상대 단위(%)를 사용하지 않는 것이 좋습니다.

flex container의 자손은 flex item이 되지 않습니다.

  • Name: display
  • Values: flex | inline-flex

See the Pen CSS flex container ‘display’ property test. by Jeong Chan-Myeong (@naradesign) on CodePen.

신축성(flexibility): flex item의 팽창 및 수축.

flex item은 flex-grow(팽창지수), flex-shrink(수축지수), flex-basis(기준 사이즈) 속성과 이것들의 단축 속성인 flex 속성으로 박스의 팽창, 수축, 기준 사이즈를 제어할 수 있습니다. W3C 명세는 flex 단축 속성(flex : none | [<flex-grow> <flex-shrink>? || <flex-basis>])으로 제어하는 것을 권장합니다. 단축 속성은 명시하지 않은 값을 일반적인 용도에 맞게 재설정하기 때문입니다. 단축 속성 선언 시 재설정되는 값에 대한 설명은 flex item의 단축 속성 ‘flex’를 참고하세요. 참고: CSS 명세에서 바 ‘|‘는 분리된 값들 중 반드시 ‘하나’를 선언해야 한다는 의미입니다. 더블 바 ‘||‘는 분리된 값들 중 ‘하나 또는 그 이상’을 선언할 수 있다는 의미입니다. 물음표 ‘?‘는 ‘생략하거나 또는 한 번만 선언’해야 한다는 의미입니다.

flex item의 팽창을 제어하는 ‘flex-grow‘ 속성.

  • Name: flex-grow
  • Value: <number> // 음수 값은 유효하지 않음. 보통 ‘0‘ 또는 ‘1‘ 값을 선언.
  • Initial: 0 // 단축 속성 flex 사용 시 flex-grow 값을 생략하면 값은 초기 값은 ‘1‘으로 다시 설정 됨.
  • Applies to: flex items

flex-grow 속성의 기본값은 ‘0‘ 이기 때문에 flex item은 기본적으로 팽창하지 않습니다. flex-grow의 값이 ‘0‘이 아닌 경우에는 컨테이너 내부에 형성된 빈 공간(free space)을 팽창지수(flex-grow)에 따라 flex item에 반영하여 남은 공간을 채우게 됩니다. 공간이 남는 경우에는 flex-grow 속성에 의해 팽창하지만, 공간이 남지 않는 경우에는 아무리 값을 올려도 컨테이너의 너비 이상으로 팽창하지 않습니다. max-width 속성을 선언했다면 이 값을 초과하여 팽창하지 않습니다.

See the Pen CSS ‘flex-grow’ property test. by Jeong Chan-Myeong (@naradesign) on CodePen.

flex item의 수축을 제어하는 ‘flex-shrink‘ 속성.

  • Name: flex-shrink
  • Value: <number> // 음수 값은 유효하지 않음. 보통 ‘0‘ 또는 ‘1‘ 값을 선언.
  • Initial: 1 // 단축 속성 flex 사용 시 flex-shrink 값을 생략해도 초기 값은 여전히 ‘1‘이 된다.
  • Applies to: flex items

flex-shrink 속성의 기본값은 ‘1‘ 이기 때문에 flex item은 기본적으로 수축합니다. flex-shrink 값이 ‘0‘인 경우 flex item의 너비가 컨테이너를 초과 해도 수축하지 않습니다. 한편 flex-shrink 값이 ‘0‘이 아닌 경우에는 flex item이 컨테이너를 초과했을 때 넘치는 공간(이 때 음수 free space 발생)의 크기를 기준으로 수축지수(flex-shrink)에 따라 수축하게 됩니다. 컨테이너를 초과해서 공간이 모자라는 경우에는 flex-shrink 속성에 의해 수축하지만, 공간이 모자라지 않는 경우에는 아무리 값을 올려도 수축하지 않습니다. min-width 속성을 선언했다면 이 값 미만으로 수축하지 않습니다.

See the Pen CSS ‘flex-shrink’ property test. by Jeong Chan-Myeong (@naradesign) on CodePen.

flex item의 기준 사이즈를 제어하는 ‘flex-basis‘ 속성.

  • Name: flex-basis
  • Value: content | <width>
  • Initial: auto
  • Applies to: flex items

flex-basis 속성은 flex item 요소가 flex-grow 또는 flex-shrink 속성에 의해 팽창/수축하기 이전의 기준 크기를 명시하는 속성입니다. flex item에 width값을 명시하는 것은 flex-basis 값을 선언하는 것과 결과적으로 동일합니다. flex item의 팽창 또는 수축은 width값 또는 flex-basis에 선언한 값을 기준으로 free space(빈 공간) 값을 구하게 되고, free space 값은 팽창/수축 지수를 통해 flex item의 크기에 영향을 미치게 되므로 flex-basis(또는 width) 값을 가능하다면 명시적으로 선언하는 것이 좋습니다. 동일한 flex item에 width 값과 flex-basis 값을 동시 선언하는 경우 flex-basis 값은 width 값을 덮어 쓰기 때문에 코드를 간결하게 작성하려면 width 값을 선언하는 것보다 flex-basis 값을 선언하는 것을 권장합니다.

See the Pen CSS ‘flex-basis’ property test. by Jeong Chan-Myeong (@naradesign) on CodePen.

flex item의 단축 속성 ‘flex‘.

flex 속성은 flex-grow, flex-shrink, flex-basis 속성의 값을 하나의 속성값으로 작성할 수 있는 단축 속성입니다. flex item 요소에 flex와 관련 있는 아무런 속성도 선언하지 않은 경우 flex-grow:0; flex-shrink:1; flex-basis:auto; 다시 말하면 flex:0 1 auto; 상태가 됩니다. 세 가지 속성을 모두 선언할 수도 있지만 하나만 선언하고 다른 값을 생략할 수도 있는데요. 생략한 속성의 값은 자동으로 재설정 됩니다.

flex 단축 속성은 아래와 같이 다양한 형태로 선언할 수 있습니다. 생략한 일부 속성의 값은 flex item에 아무런 속성도 선언하지 않았을 때의 값 flex:0 1 auto; 와도 다르고 flex:none; 을 선언했을 때의 값 flex:0 0 auto; 와도 다르다는 점에 유의하세요.

  • flex: none;
    // flex-grow:0; flex-shrink:0; flex-basis:auto; 상태가 된다.
  • flex: <flex-grow>
    // flex-shrink:1; flex-basis:0; 상태가 된다.
  • flex: <flex-basis>
    // flex-grow:1; flex-shrink:1; 상태가 된다.
  • flex: <flex-grow> <flex-shrink>
    // flex-basis:0; 상태가 된다.
  • flex: <flex-grow> <flex-basis>
    // flex-shrink:1; 상태가 된다.
  • flex: <flex-grow> <flex-shrink> <flex-basis>
    // 생략한 속성 없음.

관련 글

참고

분류: CSS,웹 표준 | 2017년 4월 20일, 18:31 | 정찬명 | 댓글: 6개 |
트랙백URI - http://naradesign.net/wp/2017/04/20/2363/trackback/

6개의 댓글이 있습니다.

  1. 1번자리오타언니 댓글:

    flex이용해서 모바일코딩중입니다
    메뉴가 1-4개까지 있는데 3개까지는 메뉴가 1열로 정렬되고
    메뉴가 4개일때부터는 2개씩 나눠서 두줄이 되길 원하는데 flex로 이용해 하려고하니 너무어렵네요..

    ul.tabs a:first-child:nth-last-child(4),
    ul.tabs a:first-child:nth-last-child(4)~a{flex-grow:4?}

    4로해도 안되고, flex-wrap을 사용하자니 부모에 줘야해서 메뉴가 1-3개있을때는 해당이 안되구요 flex로는 해결이 안될까요? 미디어쿼리로만 사용해야할까요?

  2. 정찬명 댓글:

    @1번자리오타언티
    혹시 이런 결과를 원하는 것 맞나요? 미디어 쿼리는 필요 없어요.
    https://codepen.io/naradesign/pen/QvZqKB?editors=1100

  3. 1번자리오타언니 댓글:

    맞아요 와 감사해요 엄청 간단한 스타일로 정리가 되네요;
    .flex-container{display:flex;flex-flow:wrap;}
    .flex-item{flex:50%;}
    메뉴4개일경우는 정의하지 않았던데,
    flex-flow:wrap 속성은 어떤걸 의미하는건가요?
    flex-wrap속성을 사용해도 두줄로 떨어지지않았는데..

  4. 정찬명 댓글:

    @1번자리오타언니

    1. 먼저 플렉스 컨테이너의 display 속성 값을 flex로 처리하지요.
    .flex-container{display:flex;}

    2. 그 다음 아래 코드를 이용해서 모든 플렉스 아이템의 박스 너비를 50%로 만들어요. 그러면 일단 수량에 관계 없이 모두 50%가 되겠지요.
    .flex-item{flex-basis:50%;} // 원래는 이 속성을 써야 하죠.
    .flex-item{flex:50%;} // 하지만 저는 이렇게 단축 속성을 썼고요.

    3. 그 다음 플렉스 아이템이 한 개 일 때와 3개 일 때 박스 너비를 지정해서 2번에서 지정한 너비를 덮어쓰기 시도하지요.
    .flex-item:only-child{flex:100%;}
    .flex-item:first-child:nth-last-child(3),
    .flex-item:first-child:nth-last-child(3)~*{flex:33.33%;}

    4. 마지막으로 플렉스 컨테이너에 줄 바꿈을 만들어 주는 flex-wrap 속성 값을 wrap으로 처리합니다. flex-wrap의 기본값은 원래 nowrap 이에요. 이 속성 때문에 한 줄로 처리하기에 비좁은 경우 줄 바꿈을 시도하게 돼요.
    .flex-container{display:flex;flex-wrap:wrap;} // 원래는 이 속성을 써야 하지만
    .flex-container{display:flex;flex-flow:wrap;} // 저는 단축 속성을 사용했습니다.

    flex-wrap, flex-flow 속성에 대한 설명은 제 블로그 “CSS flexible 레이아웃: flex item의 방향과 순서.” 게시물에 설명해 놨으니까 살펴 보세요.

  5. 1번자리오타언니 댓글:

    nowrap속성만 있고 wrap속성이 있는줄 몰랐어요…….하하
    그럼 4개이상의 메뉴가 생길경우는 무조건 50%로 2행에 두개씩 떨어지게 되는거죠?
    자세한설명 감사합니다———

  6. 정찬명 댓글:

    @1번자리오타언니
    네, 맞아요! ^^;

댓글 쓰기

전송된 글이 나타나지 않는다면 필터링 된 것입니다. dece24앳gmail.com 으로 메일 주세요.
(X)HTML 코드 사용이 가능하지만 소스 코드 출력을 원하시면 <꺽쇠>는 [괄호]로 변환하여 작성해 주세요.

필수 아님

필수 아님