CSS 테이블 모듈 레벨 3

W3C 작업 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2025/WD-css-tables-3-20251216/
최신 공개 버전:
https://www.w3.org/TR/css-tables-3/
편집자 초안:
https://drafts.csswg.org/css-tables-3/
이전 버전:
이력:
https://www.w3.org/standards/history/css-tables-3/
피드백:
CSSWG 이슈 저장소
명세 내 인라인
편집자:
Keith Cirkel (Mozilla)
이전 편집자:
François Remy (초청 전문가)
Greg Whitworth (Microsoft)
Bert Bos (W3C)
L. David Baron (Google)
Markus Mielke (Microsoft)
Saloni Mira Rai (Microsoft)
이 명세에 대한 편집 제안:
GitHub 편집기
테스트 스위트:
https://wpt.fyi/results/css/css-tables/
구현 준비가 되지 않음

이 명세는 아직 구현할 준비가 되지 않았다. 이 명세는 아이디어를 기록하고 논의를 촉진하기 위해 이 저장소에 존재한다.

이 명세를 구현하려고 시도하기 전에, www-style@w3.org로 CSSWG에 문의해 달라.


초록

이 CSS 모듈은 표 형식 데이터 렌더링에 최적화된 2차원 그리드 기반 레이아웃 시스템을 정의한다. 테이블 레이아웃 모델에서 각 display 노드는 연속된 행 집합과 연속된 열 집합 사이의 교차 영역에 할당되며, 이 행과 열 자체는 테이블 구조에서 생성되고 그 콘텐츠에 따라 크기가 정해진다.

CSS는 구조화된 문서 (예: HTML 및 XML)의 렌더링을 화면, 종이 등에 설명하기 위한 언어이다.

이 문서의 상태

이 절은 이 문서가 공개된 시점의 상태를 설명한다. 현재 W3C 공개 문서 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 문서는 CSS Working Group권고안 트랙을 사용하여 작업 초안으로 공개했다. 작업 초안으로 공개되었다고 해서 W3C 및 그 회원의 승인을 의미하지는 않는다.

이 문서는 초안 문서이며 언제든 다른 문서로 업데이트, 대체 또는 폐기될 수 있다. 이 문서를 진행 중인 작업이 아닌 것으로 인용하는 것은 부적절하다.

피드백은 GitHub에 이슈를 제출하여 보내 달라(권장). 제목에는 다음과 같이 명세 코드 “css-tables”를 포함한다: “[css-tables] …의견 요약…”. 모든 이슈와 의견은 보관된다. 또는 피드백을 (보관된) 공개 메일링 리스트 www-style@w3.org로 보낼 수도 있다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 작성했다. W3C는 해당 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 해당 페이지에는 특허 공개를 위한 지침도 포함되어 있다. 개인이 필수 청구항을 포함한다고 믿는 특허에 대해 실제 지식을 가지고 있는 경우, 그 개인은 W3C 특허 정책 6절에 따라 해당 정보를 공개해야 한다.

1. 소개

이 절은 규범적이지 않다

많은 유형의 정보(예: 지난 1년 동안 수집된 날씨 판독값)는 두 축 그리드에서 시각적으로 표현하는 것이 가장 좋다. 여기서 행은 목록의 한 항목 (예: 날짜 및 그날 측정된 다양한 날씨 속성)을 나타내고, 열은 항목 속성의 연속적인 값 (예: 지난 1년 동안 측정된 기온)을 나타낸다.

때로는 표현을 더 이해하기 쉽게 만들기 위해, 그리드의 일부 셀이 실제 데이터 대신 부모 행/열의 설명이나 요약을 나타내는 데 사용된다. 이는 첫 번째 행 및/또는 열에 있는 셀(헤더라고 함) 또는 마지막 행 및/또는 열에 있는 셀(푸터라고 함)에서 더 자주 발생한다.

이러한 종류의 표 형식 데이터 표현은 일반적으로 테이블이라고 알려져 있다. 테이블 레이아웃은 달력이나 타임라인과 같은 다른 그리드 형태의 표현을 렌더링하는 데 남용될 수 있지만, 표현되는 정보가 데이터 테이블로서 의미가 없는 경우 작성자는 다른 레이아웃 모드를 선호해야 한다.

HTML에서 테이블의 렌더링은 오랫동안 HTML 명세에서 정의되어 왔다. 그러나 CSS에 정의된 기능과의 상호작용은 오랫동안 정의되지 않은 상태로 남아 있었다. 이 명세의 목표는 HTML 테이블과 CSS를 모두 지원하는 사용자 에이전트의 예상 동작을 정의하는 것이다.

이 문서에 정의된 일부 동작은 해당 동작이 해결하려는 문제를 해결하는 가장 논리적이거나 유용한 방식이 아닐 수 있음을 유의하라. 그러나 이러한 동작은 종종 호환성 요구 사항의 결과이며, 이 명세 편집자의 의도적인 선택이 아니다. 더 복잡한 레이아웃을 사용하려는 작성자는 CSS Grid와 같은 더 현대적인 CSS 모듈에 의존할 것을 권장한다.

테스트

다음 테스트는 이 명세에 설명된 기능의 일반적인 사용과 관련된 크래시 테스트이지만, 특정 규범적 문장에 연결되어 있지는 않다.


테이블 레이아웃과 일반적으로 관련된 테스트


1.1. 값 정의

이 명세는 CSS 속성 정의 규약[CSS2]에서 따르며, 값 정의 구문[CSS-VALUES-3]에서 사용한다. 이 명세에서 정의되지 않은 값 타입은 CSS Values & Units [CSS-VALUES-3]에 정의되어 있다. 다른 CSS 모듈과의 조합은 이러한 값 타입의 정의를 확장할 수 있다.

정의에 나열된 속성별 값에 더해, 이 명세에서 정의된 모든 속성은 CSS 전역 키워드도 속성 값으로 허용한다. 가독성을 위해 이를 명시적으로 반복하지 않았다.

2. 콘텐츠 모델

2.1. 테이블 구조

CSS 테이블 모델은 HTML4 테이블 모델을 기반으로 하며, 여기서 테이블의 구조는 테이블의 시각적 레이아웃과 밀접하게 대응한다. 이 모델에서 테이블은 선택적 캡션과 임의 개수의 셀 행으로 구성된다.

또한 인접한 행과 열은 구조적으로 그룹화될 수 있으며, 이러한 그룹화는 표현에 반영될 수 있다(예: 행 그룹 주위에 테두리가 그려질 수 있음).

테이블 모델은 작성자가 문서 언어에서 열이 아니라 행을 명시적으로 지정하므로 "행 우선"이라고 한다. 모든 행이 지정된 후 열이 파생된다: 첫 번째 행의 첫 번째 셀은 첫 번째 열과 spanning이 요구하는 만큼의 다른 열에 속하며(필요하면 이를 생성한다), 그 행의 다음 셀들은 각각 다음 사용 가능한 열과 spanning이 요구하는 만큼의 다른 열에 속한다(필요하면 이를 생성한다); 다음 행의 셀들은 각각 해당 행에서 다음 사용 가능한 열(rowspan을 고려함)과 spanning이 요구하는 만큼의 다른 열에 속한다(필요하면 이를 생성한다). (§ 3.3 행/열 그리드의 치수 산정 참조).

요약하면, 테이블 모델의 인스턴스는 다음으로 구성된다:

[see-caption-below]
테이블 구조의 두 가지 표현(트리 대 레이아웃)

CSS 모델은 문서 언어가 이러한 각 구성 요소에 대응하는 요소를 포함할 것을 요구하지 않는다. 미리 정의된 테이블 요소가 없는 문서 언어(XML 애플리케이션 등)의 경우, 작성자는 문서 언어 요소를 테이블 요소에 매핑해야 한다. 이는 display 속성으로 수행된다.

다음 display 값은 임의 요소에 테이블 서식 지정 규칙을 할당한다:

table (HTML: <table>과 동등)
요소가 흐름 레이아웃에 배치될 때 블록 수준인 테이블을 정의한다고 지정한다.
inline-table (HTML: <table>과 동등)
요소가 흐름 레이아웃에 배치될 때 인라인 수준인 테이블을 정의한다고 지정한다.
table-row (HTML: <tr>과 동등)
요소가 셀의 행임을 지정한다.
table-row-group (HTML: <tbody>와 동등)
요소가 일정 수의 행을 그룹화한다고 지정한다.

명시적으로 달리 언급되지 않는 한, 이 명세에서 table-row-groups에 대한 언급은 특수화된 table-header-groupstable-footer-groups도 포함한다.

table-header-group (HTML: <thead>와 동등)
table-row-group과 같지만, 레이아웃 목적상, 이러한 첫 번째 행 그룹은 항상 다른 모든 행 및 행 그룹보다 먼저 표시된다.
테이블이 여러 display: table-header-group 박스를 소유하는 경우, 첫 번째 것만 헤더로 취급되고, 나머지는 display: table-row-group을 가진 것처럼 취급된다.
table-footer-group (HTML: <tfoot>와 동등)
table-row-group과 같지만, 레이아웃 목적상, 이러한 첫 번째 행 그룹은 항상 다른 모든 행 및 행 그룹 뒤에 표시된다.
테이블이 여러 display: table-footer-group 박스를 소유하는 경우, 첫 번째 것만 푸터로 취급되고, 나머지는 display: table-row-group을 가진 것처럼 취급된다.
table-column (HTML: <col>과 동등)
요소가 셀의 열을 설명한다고 지정한다.
table-column-group (HTML: <colgroup>과 동등)
요소가 하나 이상의 열을 그룹화한다고 지정한다.
table-cell (HTML: <td> 또는 <th>와 동등)
요소가 테이블 셀을 나타낸다고 지정한다.
table-caption (HTML: <caption>과 동등)
테이블의 캡션을 지정한다. 테이블 캡션은 테이블 여백과 그 테두리 사이에 배치된다.
테스트

참고: 대체 요소display 값이 table-row, table-row-group , table-header-group, table-footer-group, table-column, table-column-group, table-cell, 그리고 table-caption인 요소는 인라인 수준 박스로 취급된다. 이는 CSS Display 3 § 2.4 Layout-Internal Display Types: the table-* and ruby-* keywords에 따른 것이다; 대체 요소display 값이 table 또는 inline-table인 요소는 자신의 외부 display 타입에 따라 동작한다. 이는 CSS Display 3 § 2.1 Outer Display Roles for Flow Layout: the block, inline, and run-in keywords에 따른 것이다. 이는 CSS 2.1에서의 중단적 변경이지만 구현과 일치한다.

테스트

2.1.1. 용어

테이블 구조 display 타입 외에도, 이 명세에서는 다음 표현도 사용된다:

테이블 래퍼 박스
자신이 소유한 각 table-caption이 차지하는 공간을 고려하기 위해 테이블 그리드 박스 주위에 생성되는 블록 컨테이너 박스.
테이블 그리드 박스
캡션을 제외한 table-internal 박스를 포함하는 블록 수준 박스.
table-root 요소
내부 display 타입table인 요소.
table-non-root 박스 또는 요소
적절한 테이블 자식 또는 table-cell 박스.
table-track 박스 또는 요소
table-row 또는 table-column 박스.
table-track-group 박스 또는 요소
table-row-group 또는 table-column-group 박스.
적절한 테이블 자식 박스 또는 요소
table-track-group, table-track 또는 table-caption 박스.
적절한 table-row 부모 박스 또는 요소
table-root 또는 table-row-group 박스.
table-internal 박스 또는 요소
table-cell, table-track 또는 table-track-group 박스.
표 형식 컨테이너
table-row 또는 적절한 table-row 부모 박스.
연속된 박스
두 형제 박스 사이에, 선택적으로 공백만 포함하는 익명 인라인 외에는 끼어 있는 형제가 없으면 두 형제 박스는 연속된 것이다. 형제 박스들의 시퀀스에서 각 박스가 그 앞의 박스와 연속적이면, 그 시퀀스는 연속된 것이다.
테스트
테이블 그리드
table-root의 모든 table-rowstable-cells의 위치를 설명하는 데 필요한 만큼의 을 포함하는 행렬. 이는 그리드 치수 산정 알고리즘에 의해 결정된다.

그리드의 각 행은 table-row에 대응할 수 있고, 각 열은 table-column에 대응할 수 있다.

슬롯 of the table grid
슬롯 (r,c)테이블 그리드에서 행 r과 열 c의 교차로 생성되는 사용 가능한 공간이다.

테이블 그리드의 각 슬롯은 적어도 하나의 table-cell에 의해 덮이며(그중 일부는 익명), 많아야 둘이다. table-root의 각 table-cell은 적어도 하나의 슬롯을 덮는다.

하나보다 많은 슬롯을 덮는 table-cell은 조밀하게 그렇게 한다. 즉, 해당 셀이 덮는 슬롯 집합은 항상 네 개의 엄격하게 양수인 정수 (rowStart, colStart, rowSpan, colSpan) 집합으로 설명될 수 있다. 이때 슬롯 (r,c)rrowStart(포함)와 rowStart+rowSpan(제외) 사이의 구간에 있고, ccolStart(포함)와 colStart+colSpan(제외) 사이의 구간에 있는 경우에만 table-cell에 의해 덮인다;

이러한 table-cell은 행 rowStart와 열 colStart에서 시작한다고 한다. 또한:

  • table-cell이 그에 대응하는 행 (resp. 열)에서 시작하면, 그 table-cell은 table-row (resp. table-column)을 시작한다고 한다.
  • table-cell의 시작 행 (resp. 열)을 그룹이 포함하면, 그 table-cell은 table-row-group (resp. table-column-group)을 시작한다고 한다.

이러한 table-cell은 위 조건에 맞는 모든 행 r과 열 c걸친다고 한다. 또한:

  • table-cell이 그에 대응하는 행 (resp. 열)에 걸치면, table-cell은 table-row (resp. table-column)에 걸친다고 한다.
  • (resp. 열)에 대응하는 table-row (resp. table-column)은 이 행 (resp. 열)에 걸친다고 한다.
  • table-row (resp. table-column)은 그리드의 모든 열 (resp. 행)에 걸친다고 한다.
  • (resp. 열)을 포함하는 table-row-group (resp. table-column)은 그 행 (resp. 열)에 걸친다고 한다.
  • table-row-group (resp. table-column)은 그리드의 모든 열 (resp. 행)에 걸친다고 한다.

2.2. 수정

HTML 이외의 문서 언어에는 CSS 2.1 테이블 모델의 모든 요소가 포함되어 있지 않을 수 있다. 이러한 경우 테이블 모델이 작동하도록 "누락된" 요소가 있다고 가정해야 한다.

모든 table-internal 요소는 필요한 경우 자신 주위에 필요한 익명 테이블 객체를 자동으로 생성한다. table-root의 자손 중 table-internal이 아닌 모든 것은 적어도 세 개의 중첩된 객체, 즉 table/inline-table, table-row, table-cell에 대응하는 조상 집합을 테이블 안에 가져야 한다. 누락된 박스는 다음 규칙에 따라 익명 박스의 생성을 야기한다:

2.2.1. 수정 알고리즘

이 규칙들의 목적상, out-of-flow 요소는 너비와 높이가 0인 인라인 요소로 표현된다. 그 포함 블록은 그에 맞게 선택된다.

다음 단계는 세 단계로 수행된다:

  1. 관련 없는 박스 제거:
    다음 박스는 display:none인 것처럼 버려진다:
    1. table-column의 자식.
    2. table-column이 아닌 table-column-group의 자식.
    3. 공백만 포함하고, 각각이 table-non-root 박스인 두 직접 형제 사이에 있는 익명 인라인 박스.
    4. 다음 기준을 모두 충족하는 익명 인라인 박스:
  2. 누락된 자식 래퍼 생성:
    1. 적절한 테이블 자식 박스가 아닌 table-root 박스의 연속된 자식들의 각 시퀀스 주위에는 익명 table-row 박스가 생성되어야 한다. !!Testcase
    2. table-row 박스가 아닌 table-row-group 박스의 연속된 자식들의 각 시퀀스 주위에는 익명 table-row 박스가 생성되어야 한다. !Testcase
    3. table-cell 박스가 아닌 table-row 박스의 연속된 자식들의 각 시퀀스 주위에는 익명 table-cell 박스가 생성되어야 한다. !Testcase
  3. 누락된 부모 생성:
    1. 부모가 table-row가 아닌 연속된 table-cell 박스들의 각 시퀀스 주위에는 익명 table-row 박스가 생성되어야 한다. Testcase
    2. 잘못 부모 지정된 연속된 적절한 테이블 자식 박스들의 각 시퀀스 주위에는 익명 table 또는 inline-table 박스가 생성되어야 한다. 해당 박스의 부모가 인라인, run-in, ruby 박스(또는 자식의 inlinification을 수행하는 모든 박스)이면, inline-table 박스가 생성되어야 하며; 그렇지 않으면 table 박스여야 한다. Testcase Testcase !Testcase
    3. table-root 주위에는 익명 table-wrapper 박스가 생성되어야 한다. 그 display 타입은 inline-table 박스의 경우 inline-block이고, table 박스의 경우 block이다. 테이블 래퍼 박스는 블록 서식 컨텍스트를 확립한다. inline-table의 baseline 수직 정렬을 수행할 때는 테이블 래퍼 박스가 아니라 table-root 박스가 사용된다. 테이블 래퍼 박스의 너비는 그 안의 테이블 그리드 박스의 border-edge 너비이다. 테이블 래퍼 박스 크기에서 widthheight에 의존하게 될 백분율은 테이블 래퍼 박스 자체가 아니라 대신 테이블 래퍼 박스의 포함 블록에 상대적이다.
flexbox 및 grid와 같은 일부 레이아웃 모드는 자식의 display 타입을 재정의한다는 점에 유의하라. 이러한 변환은 테이블 수정 전에 발생한다.
floatposition 속성은 때때로 display계산값에 영향을 준다. 이러한 속성이 table internal 박스였어야 하는 것에 사용되면, 대신 block으로 전환된다. 이 변환은 테이블 수정 전에 발생한다.
이 절의 텍스트는 읽기 쉽게 만들기 위해 CSS 2.2에서 수정했다. 이러한 변경으로 인한 실수를 발견하면 이슈를 제출해 달라
테스트

2.2.2. 수정 박스의 특성

수정 목적을 위해 생성된 익명 박스는 이 명세에서 달리 언급된 경우를 제외하고, display 타입 외에는 특정 스타일이나 기본 스타일을 받지 않는다.

이는 특히 그 계산된 배경이 “transparent”이고, 계산된 padding이 “0px”이며, 계산된 border-style이 “none”임을 의미한다.

또한 익명 박스는 박스 트리를 통해 속성 값을 상속한다는 점을 상기할 가치가 있다.

2.2.3. 예제

<div class="row">
  <div class="cell">George</div>
  <div class="cell">4287</div>
  <div class="cell">1998</div>
</div>

관련 스타일은 다음과 같다:

.row { display: table-row }
.cell { display: table-cell }

수정 후, 이는 마치 다음이 초기 HTML인 것처럼 레이아웃 박스를 생성한다:

<table>
  <tr>
    <td>George</td>
    <td>4287</td>
    <td>1998</td>
  </tr>
</table>

이 예제에서는 세 개의 table-cell 익명 박스가 행의 텍스트를 포함한다고 가정된다. display: table-row를 가진 div 내부의 텍스트는 시각적 서식 모델에 설명된 것처럼 익명 인라인 박스에 캡슐화된다:

<div class="inline-table">
  <div class="row">This is the top row.</div>
  <div class="row">This is the middle row.</div>
  <div class="row">This is the bottom row.</div>
</div>
.inline-table { display: inline-table; }
.row { display: table-row; }

이는 마치 다음이 초기 HTML인 것처럼 레이아웃 박스를 생성한다:

<table>
  <tr>
    <td>This is the top row.</td>
  </tr>
  <tr>
    <td>This is the middle row.</td>
  </tr>
  <tr>
    <td>This is the bottom row.</td>
  </tr>
</table>

3. 레이아웃

3.1. 핵심 레이아웃 원칙

다른 블록 수준 박스와 달리, 테이블은 기본적으로 자신의 포함 블록을 채우지 않는다. widthauto로 계산되면, 테이블은 대신 fit-content가 지정된 것처럼 동작한다. 이는 대신 stretch가 지정된 것처럼 동작하는 대부분의 블록 수준 박스와 다르다.

테이블의 min-content 너비는 모든 열의 min-content 너비와 분배할 수 없는 공간을 맞추는 데 필요한 너비이다.

테이블의 max-content 너비는 모든 열의 max-content 너비와 분배할 수 없는 공간을 맞추는 데 필요한 너비이다.

테이블에 할당된 너비가 그 min-content 너비보다 크면, 사용 가능한 너비 분배 알고리즘은 그 결과에 따라 열 너비를 조정한다.

이 절은 다른 명세에 설명된 너비 계산에 적용되는 일반 목적 규칙을 재정의한다. 특히, 테이블의 margin이 0으로 설정되고 width가 auto로 설정되면, 테이블은 포함 블록을 채우도록 자동으로 크기가 정해지지 않는다. 그러나 테이블에 대한 width의 사용값이 발견되면(아래에 주어진 알고리즘 사용) 해당 규칙의 다른 부분은 적용된다. 따라서 예를 들어 왼쪽 및 오른쪽 auto margin을 사용하여 테이블을 가운데 정렬할 수 있다.

3.2. 테이블 레이아웃 알고리즘

테이블을 레이아웃하려면, 사용자 에이전트는 다음 작업을 적용해야 한다:

  1. 테이블에 필요한 행/열 수를 결정한다.
    이는 § 3.3 행/열 그리드의 치수 산정에 설명된 단계를 실행하여 수행된다.
  2. [A] 행/열 그리드에 하나 이상의 슬롯이 있는 경우:
    1. 각 셀 슬롯이 적어도 하나의 셀에 의해 점유되도록 보장한다.
      이는 § 3.4 누락된 셀 수정에 설명된 단계를 실행하여 수행된다.
    2. 각 열의 최소 너비를 계산한다.
      이는 § 3.8 테이블 측정값 계산에 설명된 단계를 실행하여 수행된다.
    3. 테이블의 너비를 계산한다.
      이는 § 3.9.1 테이블 너비 계산에 설명된 단계를 실행하여 수행된다.
    4. 테이블의 너비를 열들 사이에 분배한다.
      이는 § 3.9.3 분배 알고리즘에 설명된 단계를 실행하여 수행된다.
    5. 테이블의 높이를 계산한다.
      이는 § 3.10.1 테이블 높이 계산에 설명된 단계를 실행하여 수행된다.
    6. 테이블의 높이를 행들 사이에 분배한다.
      이는 § 3.10.5 분배 알고리즘에 설명된 단계를 실행하여 수행된다.

    [B] 그렇지 않으면, 빈 테이블이 레이아웃된다:

    1. 테이블의 너비를 계산한다.
      이는 CAPMIN의 가장 큰 값과, 테이블 그리드 박스의 계산된 너비 (테두리와 padding 포함)가 definite이면 그 값을 반환하여 수행된다 (그렇지 않으면 0 사용).
    2. 테이블의 높이를 계산한다.
      이는 모든 table-caption 높이의 합 (그 너비는 테이블 너비로 설정되며, margin은 적절히 고려됨)과 테이블 그리드 박스의 계산된 높이(테두리와 padding 포함)가 definite이면 그 값을 반환하여 수행된다(그렇지 않으면 0 사용).
  3. 각 table-caption 및 table-cell에 위치와 크기를 할당한다.
    이는 § 3.11 셀, 캡션 및 기타 내부 테이블 박스의 배치 단계를 실행하여 수행된다.

다음 도식은 이해하기 쉽도록 알고리즘을 다른 방식으로 설명한다.

[see-caption-below]
테이블 레이아웃 알고리즘 개요. 규범적이지 않다.
테스트

3.3. 행/열 그리드의 치수 산정

테이블 구조 절에서 언급했듯이, 테이블에 몇 개의 행과 열이 있는지는 테이블 구조에서 결정될 수 있다. 행/열 그리드의 치수 산정과 해당 그리드에서 table-cell에 slot(들)을 할당하는 것 모두 테이블에 대한 HTML 알고리즘을 실행해야 한다.

3.3.1. HTML 알고리즘

display 타입에 해당하는 HTML table 요소에서 유래하지 않은 CSS 박스는 이 알고리즘을 적용하기 전에 아래에 설명된 것처럼 그 HTML 대응 요소로 변환되어야 한다. 이 명세 레벨에서는 CSS만으로 셀의 span을 지정할 방법이 없으며, 이를 위해서는 HTML td 요소를 사용해야 한다.

HTML5 테이블 서식 지정 알고리즘을 적용한다. 이때 박스는 자신의 display 타입에 해당하는 HTML 요소처럼 동작하며, 그 박스의 원래 요소가 같은 타입의 HTML 요소인 경우에만 그 속성을 사용한다 (그렇지 않으면 아무 속성도 없는 것처럼 동작한다).

<ul class="table">
  <li><b>One</b><i>1</i></li>
  <li><b>Two</b><i>2</i></li>
  <li><b>Three</b><i>3</i></li>
</ul>
<style>
  ul.table { display: table; }
  ul.table > li { display: table-row; }
  ul.table > li > * { display: table-cell; }
</style>

이는 다음과 같은 행/열 그리드를 생성한다

<table><tbody>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
</tbody></table>
<!-- built using dom api, as this would be fixed by the html parser -->
<grid style="display: table">
  <row style="display: table-row">
    <th rowspan="2">1</th>
    <colgroup style="display: table-cell" span="2" colspan="2">2</colgroup>
  </row>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</grid>

이는 다음과 같은 행/열 그리드를 생성한다

<table>
  <tr>
    <th rowspan="2">1</th>
    <td>2</td>
  </tr>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</table>

첫 번째 행의 두 번째 셀에는 ```colspan=2```가 적용되지 않는다는 점에 유의하라. 그 원래 요소가 HTML TD 요소가 아니기 때문이다.

Testcase. !!Testcase. !Test case. !!Test case. !!Test case.

테스트

3.3.2. 트랙 병합

HTML 테이블 서식 지정 알고리즘은 때때로 테이블을 올바르게 레이아웃하는 데 필요한 것보다 더 많은 트랙을 생성한다. 이러한 트랙은 역사적으로 사용자 에이전트에서 무시되어 왔으므로, 다음 단계는 명세의 뒤쪽에서 이를 예외로 다루지 않기 위해 완전히 제거한다. 이 변경으로 기능을 유지하려고 노력했지만, 이 변경 때문에 문제가 발생한 것을 발견하면 이슈를 제출해 달라.

얻어진 그리드를 다음과 같이 연속된 트랙을 병합하여 반복적으로 수정한다: 얻어진 행/열 그리드에 적격 트랙이 존재하고, 해당 트랙을 명시적으로 정의하는 table-column/table-row 박스가 없으며, 해당 트랙과 이전 트랙 모두가 정확히 같은 셀 집합에 의해 span되는 동안, 테이블 레이아웃을 계산할 목적상 이 두 트랙은 하나의 단일 트랙으로 병합되어야 한다. 이를 보정하기 위해 삭제된 트랙에 걸쳤던 셀의 span을 하나 줄이고, 필요한 경우 셀이 originate하는 트랙도 마찬가지로 이동한다. (spanning-ghost-rows 테스트 케이스 참조)

자동 모드의 테이블의 경우, 모든 트랙은 트랙 병합 알고리즘의 목적상 적격 트랙이다. 고정 모드의 테이블의 경우, 그런 방식으로 병합될 수 있는 것은 행뿐이다. 즉, 모든 열은 보존된다.

마지막으로, table-root 그리드에 올바른 행과 열의 개수(매핑된 요소에서)를 할당하고, 각 table-cell에는 정확한 rowStart/colStart/rowSpan/colSpan(매핑된 요소에서)을 할당한다.

테스트

3.4. 누락된 셀 수정

다음 절은 누락된 셀이 그리드에서 해당 위치를 익명 table-cell 박스가 차지한 것처럼 렌더링된다고 말하는 CSS 2.1 문장을 명확히 하고 확장한다 ("누락된 셀"은 아직 어떤 table-cell 박스에도 덮이지 않은 행/열 그리드의 슬롯이다).

테이블의 열 수가 알려지면, 모든 table-row 박스는 span을 고려했을 때 테이블의 모든 열을 채우기에 충분한 셀을 소유하도록 수정되어야 한다. 이 조건이 충족될 때까지 새 table-cell 익명 박스를 그 행의 콘텐츠에 추가해야 한다.

테스트

3.5. 테이블 레이아웃 모드

이 절은 테이블이 레이아웃되는 방식을 수정하는 플래그를 다룬다. 테이블 레이아웃에는 세 가지 주요 플래그가 있다: table-layout, border-collapse, 그리고 caption-side. border-collapse 플래그에는 선택적 border-spacing 매개변수가 있다.

3.5.1. Table-Layout 속성

이름: table-layout
값: auto | fixed
초깃값: auto
적용 대상: table grid 박스
상속: no
백분율: n/a
계산값: 지정된 키워드
표준 순서: 문법 기준
애니메이션 타입: 불연속
테스트

table-layout 속성의 계산값이 fixed와 같고, table root의 지정된 너비가 <length-percentage>, min-content 또는 fit-content 중 하나일 때마다, table-root는 고정 모드로 레이아웃된다고 한다. 지정된 너비가 그러한 값 중 하나가 아니거나, table-layout 속성의 계산값이 auto이면, table-root는 자동 모드로 레이아웃된다고 한다.

table-root가 고정 모드로 레이아웃될 때, 너비 계산의 목적상 그 table-cell의 콘텐츠는 무시되고, 열 크기 산정의 집계 알고리즘은 첫 번째 행 트랙에 속하는 table-cell만 고려한다. 따라서 레이아웃은 테이블의 table-column 또는 첫 번째 행의 셀에 대해 명시적으로 지정된 값에만 의존한다; indefinite 너비를 가진 열에는 definite 너비를 가진 열을 고려한 뒤 남은 공간의 공정한 몫이 할당되며, 남은 공간이 없으면 0px이 할당된다 (§ 3.8.3 열 측정값 계산 참조).

3.5.2. Border-Collapse 속성

이름: border-collapse
값: separate | collapse
초깃값: separate
적용 대상: table grid 박스
상속: yes
백분율: n/a
계산값: 지정된 키워드
표준 순서: 문법 기준
애니메이션 타입: 불연속

border-collapse 속성의 값이 collapse이면, 인접한 셀의 테두리가 함께 병합되어 각 셀이 공유 테두리의 절반만 그리게 된다. 그 결과 border-spacing 같은 일부 다른 속성은 이 경우 적용되지 않는다(§ 3.6.2 collapsed-borders 모드에 적용되는 재정의 참조), (§ 3.7 테두리 병합 참조).

이 경우 table-rootcollapsed-borders 모드로 레이아웃된다고 한다. 그렇지 않으면, table-rootseparated-borders 모드로 레이아웃된다고 한다.

테스트
3.5.2.1. Border-Spacing 속성
이름: border-spacing
값: <length>{1,2}
초깃값: 0px 0px
적용 대상: table grid 박스, border-collapseseparate일 때
상속: yes
백분율: n/a
계산값: 두 개의 절대 길이
표준 순서: 문법 기준
애니메이션 타입: 계산값 기준

이 길이는 separated-borders 모드에서 인접한 셀 테두리를 분리하는 거리를 지정하며, 엄격히 음수여서는 안 된다.

하나의 길이가 지정되면, 이는 가로 및 세로 간격 모두를 제공한다. 두 개가 지정되면, 첫 번째는 가로 간격을, 두 번째는 세로 간격을 제공한다.

이것이 테이블 레이아웃에 어떻게 영향을 주는지에 대한 자세한 내용은 § 3.8.1 분배할 수 없는 공간 계산을 참조하라.

테스트

3.5.3. Caption-Side 속성

이름: caption-side
값: top | bottom
초깃값: top
적용 대상: table-caption 박스
상속: yes
백분율: n/a
계산값: 지정된 키워드
표준 순서: 문법 기준
애니메이션 타입: 불연속
테스트

이 속성은 테이블 그리드 박스에 대한 캡션 박스의 위치를 지정한다. 값의 의미는 다음과 같다:

top
캡션 박스를 테이블 그리드 박스 위에 배치한다.
bottom
캡션 박스를 테이블 그리드 박스 아래에 배치한다.
CSS2는 다른 너비와 가로 정렬 동작을 설명했다. 그 동작은 CSS3에서 top-outsidebottom-outside 값을 사용하여 도입될 예정이었다. #REF
Gecko는 "left" 및 "right" 값도 지원하지만, 현재 이 명세는 해당 값의 구현을 정의하려고 하지 않는다.
Gecko는 여러 캡션을 다룰 때 버그가 있다. !Testcase

캡션 박스 안에서 캡션 콘텐츠를 가로로 정렬하려면 text-align 속성을 사용한다.

이 예제에서는 caption-side 속성이 캡션을 테이블 아래에 배치한다. 캡션은 테이블의 부모만큼 넓어지고, 캡션 텍스트는 왼쪽 정렬된다.

caption {
  caption-side: bottom;
  width: auto;
  text-align: left
}

3.6. 스타일 재정의

일부 CSS 속성은 CSS 테이블 안에서 다르게 동작한다. 다음 절들은 예외와 그 효과를 나열한다.

3.6.1. 모든 모드에 적용되는 재정의

다음 규칙은 사용 중인 레이아웃 모드와 관계없이 모든 테이블에 적용된다.

3.6.2. collapsed-borders 모드에 적용되는 재정의

테이블이 collapsed-borders 모드로 레이아웃될 때, 다음 규칙이 적용된다:

3.7. 테두리 병합

이 전체 절은 병합된 테두리 렌더링을 합리적으로 만들기 위한 제안이다. 구현들이 매우 눈에 띄게 서로 다르기 때문에, 다른 부분보다 더 많은 논의가 필요할 것으로 예상된다. 브라우저가 이를 매우 다르게 처리하므로, 재구현 없이는 수렴이 일어날 수 없다. 이 제안의 주요 우려 사항은 가능한 한 많은 경우를 지원하면서도 테이블의 새 구현에 필요한 노력을 가능한 낮게 유지하는 것이었다.

배경: CSS+HTML은 테이블 접합부에 대해 전례 없는 테두리 모드 조합을 허용하며, 모든 경우를 올바르게 지원하기 어렵게 만든다; 실제로 일부 조합은 well-posed problems가 아니므로, 어떤 렌더링 알고리즘도 최적일 수 없다.

현재 웹 브라우저가 사용하는 테이블 렌더링 모델(배경 및 테두리)은 단순한 것(HTML)에서 매우 복잡한 것(HTML+CSS)으로 성장했기 때문에 말도 안 되는 상태이다 (버그가 많고 상호 운용되지 않으며 전혀 CSS답지 않다는 의미에서). 많은 일반적인 CSS 가정이 깨져 있으며, 렌더링은 크게 갈라진다.

이 제안은 이러한 상황을 고치는 것을 목표로 한다.

테스트

border-collapsing breaking change from 2.1 [Issue #604]

3.7.1. 병합된 테두리의 충돌 해결

테스트

collapsed-borders 모드로 레이아웃될 때, 테두리를 공유하는 table-roottable-cell 박스는 동일한 스타일, 너비 및 색상으로 렌더링되도록(가능한 경우) 자신의 테두리를 통합하려고 시도한다. 이는 다음 알고리즘을 실행하여 수행된다.

3.7.1.1. 병합된 테두리의 충돌 해결 알고리즘
이 알고리즘의 목적상, 테두리 집합을 “조화”한다는 것은 주어진 테두리 집합에 대해 “병합된 테두리의 조화 알고리즘”을 적용하고, 해당 테두리들의 사용값을 알고리즘의 결과 값으로 설정하는 것을 의미한다. 다만 border-image-source가 none과 다른 셀은 예외이며, 이들은 초기값을 유지한다.

table-root의 임의의 table-cell C°에 대해:

그런 다음, 해당 table-root에 대해:

구현은 물론 이전 알고리즘의 일부 단계를 건너뛰도록 선택할 수 있다. 다만 해당 단계들이 최종 결과에 시각적 영향을 주지 않음을 증명할 수 있어야 한다; 이전 단계들을 사용하면 특정 테두리가 두 번 이상 조화되지만, 이를 막으려면 명세를 읽기 더 어렵게 만들 것이다.
독자가 이 알고리즘이 무엇을 하는지 더 잘 이해할 수 있도록, 샘플 테이블에 이전 알고리즘을 적용하는 주요 단계를 여기에 요약했다:

https://jsfiddle.net/bn3d1sm4/
https://jsfiddle.net/bn3d1sm4/1/
https://jsfiddle.net/bn3d1sm4/2/

https://jsfiddle.net/bn3d1sm4/15/
테스트
3.7.1.2. 병합된 테두리의 조화 알고리즘
이 알고리즘의 목적상, 테두리의 속성을 “고려”한다는 것은 “그 속성이 CurrentlyWinningBorderProperties보다 더 구체적이면, CurrentlyWinningBorderProperties를 그 속성으로 설정한다”는 것을 의미한다.

병합된 테두리의 조화에서 명시도를 변경할 것인가? [Issue #606]

순서 있는 테두리 스타일 집합(셀 C1, C2, …에 위치한 BC1, BC2, …)이 주어졌을 때, 해당 충돌하는 테두리에 대한 테두리 속성의 사용값을 결정하기 위해 다음 알고리즘을 실행한다.

3.7.1.3. 테두리 스타일의 명시도

두 테두리 스타일이 주어졌을 때, 가장 명시도가 높은 테두리 스타일은 다음과 같은 테두리 스타일이다…

  1. … 하나만 border-style 값으로 "hidden"을 갖는 경우, 그 값을 갖는 것
  2. … CSS 픽셀로 변환했을 때 가장 큰 border-width를 갖는 것
  3. … 다음 목록에서 가장 먼저 나오는 border-style을 갖는 것:
    double, solid, dashed, dotted, ridge, outset, groove, inset, none

이 기준 중 어느 것도 일치하지 않으면, 두 테두리는 같은 명시도를 공유한다.

3.8. 테이블 측정값 계산

테스트

3.8.1. 분배할 수 없는 공간 계산

테이블의 분배할 수 없는 공간은 연속된 table-cell의 테두리 사이 거리 (및 table-root의 테두리와 table-cell 사이 거리)의 합이다.

두 연속된 table-cell의 테두리 사이 거리는, 있다면 border-spacing이다.

테이블 테두리와 테이블 가장자리의 셀 테두리 사이 거리는 해당 변에 대한 테이블의 padding에 관련된 border spacing 거리(있다면)를 더한 값이다.

예를 들어, 오른쪽에서는 거리가 padding-right + 가로 border-spacing이다.

3.8.2. 셀 측정값 계산

다음 용어는 테이블 또는 테이블 셀의 매개변수이다. 이러한 매개변수는 border-collapse 값이 다른 테이블(separate 또는 collapse) 사이의 차이를 캡슐화하여 이 절의 나머지 하위 절들이 이를 다르게 참조할 필요가 없도록 한다.

셀 intrinsic 오프셋
셀 intrinsic 오프셋은 테이블 셀의 padding 및 border 중 intrinsic 너비 계산과 관련된 부분을 포착하는 용어이다. 이는 border-left-width, padding-left, padding-right 및 border-right-width의 계산값 집합 (margin-left 및 margin-right의 0 값과 함께)이며 다음과 같이 정의된다:
테이블 intrinsic 오프셋
테이블 intrinsic 오프셋은 테이블의 padding 및 border 중 intrinsic 너비 계산과 관련된 부분을 포착한다. 이는 border-left-width, padding-left, padding-right 및 border-right-width의 계산값 집합 (margin-left 및 margin-right의 0 값과 함께)이며 다음과 같이 정의된다:

margin은 테이블 intrinsic 오프셋에 포함되지 않는다. margin 처리는 caption-side 속성에 의존하기 때문이다.

border collapsing 모드에서 intrinsic 오프셋 처리 [Issue #608]

전체 가로 border spacing
전체 가로 border spacing은 각 테이블에 대해 정의된다:
  • 적어도 하나의 열을 포함하고 separated-borders 모드로 레이아웃된 테이블의 경우, border-spacing 속성 계산값의 가로 구성 요소에 테이블의 열 수에 1을 더한 값을 곱한 값
  • 그렇지 않으면 0
오프셋 조정 min-width, width 및 max-width

Testcase. Testcase. Testcase.

outer min-contentouter max-content 너비
outer min-content 및 max-content 너비는 테이블 셀, 열 및 열 그룹에 대해 정의된다. 이 정의에서 사용되는 width, min-width, 및 max-width 값은 위에서 정의한 오프셋 조정 값이다:
백분율 기여
테이블 셀, 열 또는 열 그룹의 백분율 기여는 백분율인 계산값을 갖는 widthmax-width의 계산값으로 정의된다:

min(percentage width, percentage max-width).

계산값이 백분율이 아니면, width에는 0%를 사용하고, max-width에는 무한 백분율을 사용한다.
min-width는 이 계산에 포함되지 않는다는 점에 유의하라. 그 결과 백분율 min-width는 무시된다. 테이블 레이아웃에서 widthmin-width처럼 동작하고, 열 크기 산정은 길이 기반과 백분율 기반을 동시에 가질 수 없으므로, 작성자는 table-internal 박스에 min-width를 사용하지 말고 대신 width에만 의존하는 것이 좋다.
테스트

3.8.3. 열 측정값 계산

이 하위 절은 테이블의 각 열과 관련된 세 가지 중요한 값을 정의한다: 그 min-content 너비(이 열에 부여되는 가능한 가장 작은 너비), 그 max-content 너비(다른 제약이 적용되지 않는다면 열에 부여될 너비), 그 intrinsic 백분율 너비(열이 얻고자 하는 테이블 너비의 백분율이며, 결국 그 max-content 너비를 재정의할 수 있다).

이러한 값을 계산하기 위해 반복 알고리즘이 사용된다. 먼저, 하나보다 많은 열에 걸치는 셀을 무시하고 이러한 값이 계산된다. 그런 다음, 점차 더 많은 열에 걸치는 셀을 고려하여 이러한 값을 업데이트한다. 테이블의 모든 열에 걸쳤던 셀을 고려하면 이 알고리즘은 끝나고 값은 최종화된다.

고정 모드로 레이아웃될 때 열을 측정하는 목적상, (헤더와 푸터를 재정렬한 후) 테이블의 첫 번째 행에서 originate하는 셀만 고려된다, 있다면. 또한 셀의 min-content 및 max-content 너비는 length-percentage로 직접 지정된 경우가 아니라면 0으로 간주되며, 직접 지정된 경우에는 테이블 너비를 기준으로 해결된다(그것이 definite이면, 그렇지 않으면 0 사용).

셀의 outer min-content 너비를 계산하는 목적상, 테이블 셀의 자손 중 자신의 너비가 부모 셀 너비의 백분율에 의존하는 것은 auto 너비를 가진 것으로 간주된다. Testcase Testcase

span이 최대 1인 셀을 기준으로 한 열의 min-content 너비
다음 중 가장 큰 값:
  • 열에 지정된 너비:
    • 그에 대응하는 table-column이 있으면(그리고 auto가 아니면), 그 outer min-content 너비
    • 그에 대응하는 table-column-group이 있으면, 그 outer min-content 너비
    • 또는 없으면 0
  • 그 열에 span하고 colSpan이 1인 각 셀의 outer min-content 너비 (고정 모드에서는 첫 번째 행의 것만) 또는 없으면 0
span이 최대 1인 셀을 기준으로 한 열의 max-content 너비
다음 중 가장 큰 값:
span이 최대 1인 셀을 기준으로 한 열의 intrinsic 백분율 너비
백분율 기여 중 가장 큰 값: 그 열에 span하고 colSpan이 1인 각 셀, 그에 대응하는 table-column(있다면), 그리고 그에 대응하는 table-column-group(있다면)의 백분율 기여
span이 최대 N(N > 1)인 셀을 기준으로 한 열의 min-content 너비
span이 최대 N-1인 셀을 기준으로 한 열의 min-content 너비와 해당 열에서 colSpan이 N인 셀들의 기여 중 가장 큰 값. 여기서 셀의 기여는 다음 단계를 수행한 결과이다:
  1. 기준 min-content 너비를 셀이 span하는 모든 열의, span이 최대 N-1인 셀을 기준으로 한 max-content 너비의 합으로 정의한다.
  2. 기준 border spacing을 셀이 span하는 모든 열 중 그 셀이 originate하는 열을 제외한 열에 대한 가로 border-spacing의 합으로 정의한다.
  3. 셀의 기여는 다음의 합이다:
    • span이 최대 N-1인 셀을 기준으로 한 열의 min-content 너비
    • 다음의 곱:
      • 다음 비율:
        • 해당 열의 span이 최대 N-1인 셀을 기준으로 한 max-content 너비에서 해당 열의 span이 최대 N-1인 셀을 기준으로 한 min-content 너비를 뺀 값 대
        • 기준 max-content 너비에서 기준 min-content 너비를 뺀 값
        또는 이 비율이 정의되지 않으면 0, 그리고
      • 셀의 outer min-content 너비에서 기준 min-content 너비와 기준 border spacing을 뺀 값. 이는 최소 0, 최대 기준 max-content 너비와 기준 min-content 너비의 차이로 clamp된다
    • 다음의 곱:
      • span이 최대 N-1인 셀을 기준으로 한 해당 열의 max-content 너비와 기준 max-content 너비의 비율
      • 셀의 outer min-content 너비에서 기준 max-content 너비와 기준 border spacing을 뺀 값, 또는 이것이 음수이면 0
span이 최대 N(N > 1)인 셀을 기준으로 한 열의 max-content 너비
span이 최대 N-1인 셀을 기준으로 한 max-content 너비와 해당 열에서 colSpan이 N인 셀들의 기여 중 가장 큰 값. 여기서 셀의 기여는 다음 단계를 수행한 결과이다:
  1. 기준 max-content 너비를 셀이 span하는 모든 열의 span이 최대 N-1인 셀을 기준으로 한 max-content 너비의 합으로 정의한다.
  2. 기준 border spacing을 셀이 span하는 모든 열 중 그 셀이 originate하는 열을 제외한 열에 대한 가로 border-spacing의 합으로 정의한다.
  3. 셀의 기여는 다음의 합이다:
    • span이 최대 N-1인 셀을 기준으로 한 열의 max-content 너비
    • 다음의 곱:
      • span이 최대 N-1인 셀을 기준으로 한 해당 열의 max-content 너비와 기준 max-content 너비의 비율
      • 셀의 outer max-content 너비에서 기준 max-content 너비와 기준 border spacing을 뺀 값, 또는 이것이 음수이면 0
span이 최대 N(N > 1)인 셀을 기준으로 한 열의 intrinsic 백분율 너비
span이 최대 N-1인 셀을 기준으로 한 열의 intrinsic 백분율 너비가 0%보다 크면, span이 최대 N인 셀을 기준으로 한 열의 intrinsic 백분율 너비는 span이 최대 N-1인 셀을 기준으로 한 열의 intrinsic 백분율 너비와 같다.

그렇지 않으면, 해당 열에서 colSpan이 N인 셀들의 기여 중 가장 큰 값이다. 여기서 셀의 기여는 다음 단계를 수행한 결과이다:
  1. 셀의 백분율 기여로 시작한다.
  2. 셀이 span하는 모든 열의 span이 최대 N-1인 셀을 기준으로 한 열의 intrinsic 백분율 너비를 뺀다. 이것이 음수 결과를 주면, 0%로 바꾼다.
  3. 다음 비율을 곱한다
    • 열의 non-spanning max-content 너비 대
    • 셀이 span하는 모든 열 중 span이 최대 N-1인 셀을 기준으로 한 열의 intrinsic 백분율 너비가 0%인 열들의 non-spanning max-content 너비의 합.
    그러나 분모가 0이어서 이 비율이 정의되지 않으면, 대신 span이 최대 N-1인 셀을 기준으로 한 열의 intrinsic 백분율 너비가 0인, 셀이 span하는 열의 수로 1을 나눈 값을 사용한다.
열의 min-content 너비
span이 최대 N인 셀을 기준으로 한 열의 min-content 너비. 여기서 N은 테이블의 열 수이다
열의 max-content 너비
span이 최대 N인 셀을 기준으로 한 열의 max-content 너비. 여기서 N은 테이블의 열 수이다
열의 intrinsic 백분율 너비
다음 중 더 작은 값:
  • span이 최대 N인 셀을 기준으로 한 열의 intrinsic 백분율 너비. 여기서 N은 테이블의 열 수이다
  • 100%에서 테이블의 모든 이전 열의 intrinsic 백분율 너비의 합을 뺀 값 (direction이 "ltr"이면 더 왼쪽, "rtl"이면 오른쪽) Testcase

열의 intrinsic 백분율 너비 총합을 최대 100%로 clamp한다는 것은 테이블 레이아웃 알고리즘이 열 전환에 대해 불변이 아님을 의미한다.

제약성
열은 다음 중 하나가 "auto"가 아니고 백분율도 아닌 계산된 width를 가지면 제약된다: 그에 대응하는 table-column-group(있다면), 그에 대응하는 table-column(있다면), 또는 해당 열에만 span하는 셀 중 하나.
이 명세의 향후 개정에서는, 이 알고리즘이 셀의 문자 정렬 (<string>' 값의 text-align 속성)에 대해 설명해야 한다. 이를 위해서는(css3-text의 2011년 3월 9일 편집자 초안 기준) 정렬 문자열의 중심 이전 부분과 정렬 문자열의 중심 이후 부분에 대해 max-content 너비를 별도로 추적해야 한다. min-content 너비 추적에는 두 가지 선택지가 있다: 추적하지 않거나, 세 값을 추적한다: 줄바꿈 지점이 없는 셀에 대해 max-content 너비와 같은 두 값, 그리고 줄바꿈 지점이 있는 모든 셀에 대한 네 번째 값 (따라서 문자 정렬이 필수가 아닌 셀에 대해).
EDITORIAL. colspanning 셀에서 너비를 분배하는 방식을 설명하는 이 방식은 잘못되었다. min-content 및 max-content 너비의 경우, intrinsic 너비 계산을 위한 초과 너비를 열에 분배하는 규칙을 참조해야 한다.
테스트

3.9. 사용 가능한 너비 분배

테스트

3.9.1. 테이블 너비 계산

모든 열의 최종 너비를 결정하기 전에, 테이블 자체의 너비를 계산할 필요가 있다.

앞서 언급했듯이, 이는 일반적으로 모든 열의 선호 너비의 합에 여분을 더한 값일 것이다. 이 경우 너비 분배의 결과는 각 열에 그 선호 너비를 부여하는 것이다. 그러나 작성자가 명시적으로 다른 너비를 요청하는 몇 가지 경우와, 테이블에 필요한 너비를 부여할 수 없는 몇 가지 경우가 있다.

캡션 너비 최솟값 (CAPMIN)테이블 캡션min-content 기여 중 가장 큰 값이다.

행/열 그리드 너비 최솟값 (GRIDMIN) 너비는 모든 열의 min-content 너비의 합에 셀 간격 또는 테두리를 더한 값이다.

행/열 그리드 너비 최댓값 (GRIDMAX) 너비는 모든 열의 max-content 너비의 합에 셀 간격 또는 테두리를 더한 값이다.

테이블의 사용 min-width는 해결된 min-width, CAPMIN, 그리고 GRIDMIN 중 더 큰 값이다.

테이블의 사용 너비는 열 및 캡션 너비에 따라 다음과 같이 달라진다:

테스트

할당 가능한 테이블 너비는 테이블의 사용 너비에서 전체 가로 border spacing(있다면)을 뺀 값이다. 이것이 우리가 열에 할당할 수 있는 너비이다.

이 알고리즘에서 행(및 행 그룹)과 열(및 열 그룹)은 모두 자신이 포함하는 셀의 치수에 의해 제약하고 또 제약을 받는다. 열의 너비 설정은 간접적으로 행의 높이에 영향을 줄 수 있으며, 그 반대도 마찬가지이다.
테스트

3.9.2. 핵심 분배 원칙

이 절은 규범적이지 않다.

3.9.2.1. 규칙

이상적으로는 각 열이 자신의 선호 너비(일반적으로 max-content 너비)를 가져야 한다. 그러나 앞서 계산된 할당 가능한 테이블 너비가 이 결과를 달성하기에 너무 크거나 너무 작을 수 있으며, 이 경우 사용자 에이전트는 너비 분배 알고리즘에 설명된 대로 임시 너비를 열에 할당해야 한다.

이 알고리즘은 열의 사용 너비를 결정할 때 세 가지 규칙을 따른다:

규칙 0: 고정 모드에서는 auto 및 백분율 열에 0픽셀의 최소 너비가 할당되며, 백분율 해결은 다른 규칙 집합을 따른다. 그 목표는 픽셀 열이 항상 자신의 선호 너비를 할당받도록 보장하는 것이다.

규칙 1: 선호 너비를 할당할 때, 지정된 백분율 열은 지정된 단위 값 열보다 높은 우선순위를 가지며, 지정된 단위 값 열은 auto 열보다 높은 우선순위를 가진다.

규칙 2: 같은 크기 지정 타입(백분율 열, 픽셀 열 또는 auto 열)을 사용하는 열은 같은 분배 방법을 따른다. 예를 들어 모두 자신의 min-content 너비를 얻거나 모두 자신의 max-content 너비를 얻는다.
이 규칙에는 하나의 예외가 있다. percent-column에 선호 백분율 너비를 부여할 때, 그 결과가 자신의 min-content 너비보다 작은 크기가 된다면, 그 열에는 대신 자신의 min-content 너비가 할당된다. 그러나 percent-columns 그룹 전체는 여전히 선호 백분율 너비를 할당받은 것으로 간주된다.

규칙 3: 모든 열에 할당된 너비의 합은 할당 가능한 테이블 너비와 같아야 한다.

테스트
3.9.2.2. 사용 가능한 크기 지정

세 가지 타입의 열 모두에는 다음과 같은 가능한 사용 너비가 있다.

  1. min-content 너비:
    열의 콘텐츠를 맞추는 데 필요한 크기
  2. min-content 너비 + delta:
    min-content와 선호 너비 사이의 값
  3. 선호 너비:
    열에 지정된 크기, 또는 줄바꿈 없이 열의 콘텐츠를 맞추는 데 필요한 크기
  4. 선호 너비 + delta
    선호 너비보다 큰 값

분배 알고리즘은 이러한 값을 정의하고 언제 사용할지 설명한다.

3.9.3. 분배 알고리즘

테이블이 주어진 사용 너비로 레이아웃될 때, 각 열의 사용 너비는 다음과 같이 결정되어야 한다. 최종적으로는 이 알고리즘에 대한 변경 사항고정 모드에 적용되는 것을 고려한 뒤이다.

먼저, 테이블의 각 열에 크기 지정 타입을 할당한다:

그런 다음, 크기 지정 타입별로 유효한 크기 지정 방법을 열에 할당하여 다음 sizing-guesses를 얻는다:

  1. min-content sizing-guess는 각 열에 자신의 min-content 너비가 할당되는 열 너비 할당 집합이다.
  2. min-content-percentage sizing-guess는 다음과 같은 열 너비 할당 집합이다:
    • percent-column에는 다음 중 더 큰 값이 할당된다:
      • 자신의 intrinsic 백분율 너비 × 할당 가능한 너비
      • 자신의 min-content 너비.
    • 그 밖의 모든 열에는 자신의 min-content 너비가 할당된다.
  3. min-content-specified sizing-guess는 다음과 같은 열 너비 할당 집합이다:
    • percent-column에는 다음 중 더 큰 값이 할당된다:
      • 자신의 intrinsic 백분율 너비 × 할당 가능한 너비
      • 자신의 min-content 너비
    • 제약된 그 밖의 모든 열에는 자신의 max-content 너비가 할당된다
    • 그 밖의 모든 열에는 자신의 min-content 너비가 할당된다.
  4. max-content sizing-guess는 다음과 같은 열 너비 할당 집합이다:
    • percent-column에는 다음 중 더 큰 값이 할당된다:
      • 자신의 intrinsic 백분율 너비 × 할당 가능한 너비
      • 자신의 min-content 너비
    • 그 밖의 모든 열에는 자신의 max-content 너비가 할당된다.
다음 사항에 유의하라:

할당 가능한 테이블 너비max-content sizing-guess보다 작거나 같으면, 열의 사용 너비는 사용 가능한 너비를 경계로 하는 두 연속 sizing-guesses의 선형 결합(가중치의 합이 1인)이어야 한다.

그렇지 않으면, 열의 사용 너비는 max-content sizing-guess에서 시작하여 테이블 열에 초과 너비를 분배한 결과이다. 이는 (사용 너비에 대해) 초과 너비를 열에 분배하는 규칙에 따른다.

다음 도식은 이해하기 쉽도록 알고리즘을 다른 방식으로 설명한다.

범례

크기 지정 알고리즘: 테이블의 각 그림은 열의 크기를 지정하는 방식을 나타낸다. 왼쪽의 네 가지 경우는 명세 위에서 설명한 sizing-guesses이다: min-content, min-content-percentage, min-content-specified, 그리고 max-content. 오른쪽의 경우는 사용 가능한 크기가 네 가지 sizing-guesses 중 하나와 정확히 일치하지 않을 때 필요한 보간이다.

크기 지정 방법의 선택: 크기 지정 방법 선택은 항상 min-content sizing-guess(왼쪽 위)에서 시작한 다음, 사용 가능한 너비와 현재 사용 중인 방법이 소비하는 너비를 비교하며 진행된다. 초록색 화살표는 현재 방법을 적용한 후 분배할 여분 공간이 있을 때 따라야 하는 방향을 나타낸다. 빨간색 화살표는 현재 방법을 적용하여 너무 많은 공간을 분배했으며 되돌아가야 할 때 따라야 하는 방향을 나타낸다.

열 타입: 각 열 타입(auto, px, %)은 도식에서 자체 색상(노란색, 파란색, 주황색)을 가진다. 보간에서는: 이전 sizing-guess의 크기에서 줄어든 열은 빨간색으로 다시 칠해지고, 이전 sizing-guess의 크기에서 커진 열은 초록색으로 다시 칠해진다.

[see-caption-below]
너비 분배 알고리즘의 개요. 규범적이지 않다.
3.9.3.1. 고정 모드에서의 너비 분배 변경

이전 알고리즘에 대한 다음 변경 사항은 고정 모드에서 적용된다:

테스트
3.9.3.2. 초과 너비를 열에 분배

초과 너비를 열에 분배하기 위한 규칙은 두 가지 방식으로 호출될 수 있다:

이 두 경우의 규칙은 대체로 같지만, 약간의 차이가 있다.

이 절의 나머지 부분에서는 분배되는 너비라는 용어를 이러한 너비 중 분배되는 하나를 가리키는 데 사용하며, 초과 너비는 분배되는 너비가 그것이 분배될 열들의 분배된 너비 합을 초과하는 양을 가리키는 데 사용된다.

  1. intrinsic 백분율 너비가 0%이고 0이 아닌 max-content 너비를 가진 originate 셀이 있는 제약되지 않은 열이 있다면 (즉 이 규칙에 의해 커질 수 있는 열), 이 규칙에 의해 커질 수 있는 열의 분배되는 너비는 max-content 너비에 비례하여 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
  2. 그렇지 않고, intrinsic 백분율 너비가 0%인 originate 셀이 있는 제약되지 않은 열이 있다면 (즉 이 규칙에 의해 커질 수 있는 열이며, 이전 규칙 덕분에 max-content 너비가 0이어야 함), 이 규칙에 의해 커질 수 있는 열의 분배되는 너비는 같은 양만큼 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
  3. 그렇지 않고, intrinsic 백분율 너비가 0%이고 0이 아닌 max-content 너비를 가진 제약된 열이 있다면 (즉 이 규칙에 의해 커질 수 있는 열이며, 다른 규칙 때문에 originate 셀이 있어야 함), 이 규칙에 의해 커질 수 있는 열의 분배되는 너비는 max-content 너비에 비례하여 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
  4. 그렇지 않고, intrinsic 백분율 너비가 0%보다 큰 열이 있다면 (즉 이 규칙에 의해 커질 수 있는 열이며, 다른 규칙 때문에 originate 셀이 있어야 함), 이 규칙에 의해 커질 수 있는 열의 분배되는 너비는 intrinsic 백분율 너비에 비례하여 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
  5. 그렇지 않고, 그러한 열이 하나라도 있다면, originate 셀이 있는 모든 열의 분배되는 너비는 같은 양만큼 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
  6. 그렇지 않으면, 모든 열의 분배되는 너비가 같은 양만큼 증가한다. 따라서 전체 증가량은 초과 너비가 된다.
이러한 규칙은 테이블이 고정 모드로 레이아웃될 때 적용되지 않는다. 이 경우에는 대신 다음의 더 단순한 규칙이 적용된다:
테스트

3.10. 사용 가능한 높이 분배

테스트

3.10.1. 테이블 높이 계산

?Testcase ?Testcase ?Testcase

테이블의 높이는 행 높이의 합에 셀 간격 또는 테두리를 더한 값이다. 테이블에 auto가 아닌 값을 가진 height 속성이 있으면, 이는 테이블 그리드의 최소 높이로 취급되며, 행들의 집합적 최소 높이가 이 수치보다 작게 되는 경우 최종적으로 행 높이에 분배된다. 집합적 크기가 지정된 height보다 커지면, 지정된 height는 효과가 없다.

행의 최소 높이는 다음 중 최댓값이다:

ROWMIN은 첫 번째 행 레이아웃 패스 이후의 행의 최소 높이의 합으로 정의된다.

테이블의 높이를 계산하려면, 따라서 모든 행에 대해 첫 번째 패스 레이아웃을 수행하고, 모든 최소 행 높이와 간격/테두리의 합을 계산한 다음, 그 값 또는 table-root에 지정된 height(min-height) 중 더 큰 값을 반환해야 한다.

테이블 높이가 결정되면, 행은 일반적으로 두 번째 레이아웃 패스를 거치며(이때 셀 높이는 더 이상 auto로 간주되지 않음), 그 다음 높이 분배가 발생하여 행 높이를 조정하고 집합적으로 테이블 높이를 충족하게 하며, 그 다음 table-cell 자손은 두 번째 레이아웃을 거칠 수 있다 (이때 백분율 높이가 해결됨).

테스트

3.10.2. 행 레이아웃 (첫 번째 패스)

행의 최소 높이(span 관련 높이 분배 없음)는 해당 행에서 originate하는 셀을 포함하는 가상의 linebox의 높이로 정의되며, 여러 행에 걸치는 셀은 높이가 0px인 것으로 간주된다 (그러나 올바른 baseline은 유지한다). 이 가상의 linebox에서 셀 높이는 auto로 간주되며, 그 너비(테두리와 padding 포함)는 셀이 span하는 열의 너비와 내부 간격으로 강제되지만, 그 밖의 속성은 보존된다.

이 높이를 계산하는 목적상, 자신의 높이가 부모 셀 높이의 백분율에 의존하는 테이블 셀의 자손은 (아래 절 참조) overflowvisible, clip, 또는 hidden으로 설정되어 있거나 대체 요소인 경우 auto 높이를 가진 것으로 간주되며, 그렇지 않으면 0px 높이를 가진 것으로 간주된다. Testcase !!Testcase

위의 결과로 백분율 높이가 무시된 table-cell 자손의 경우, 높이 분배가 끝난 뒤 이 크기 지정을 제대로 고려하려고 시도하기 위해 table-cell 콘텐츠의 두 번째 레이아웃 패스가 발생한다 (아래 절 참조)

셀의 baseline은 셀 안의 첫 번째 in-flow line box의 baseline, 또는 셀 안의 첫 번째 in-flow table-row 중 더 먼저 오는 것으로 정의된다. 그러한 line box나 table-row가 없으면, baseline은 셀 박스의 content edge의 아래쪽이다.

테스트

다음은 이것이 실제로 어떻게 작동하는지 보여준다:

td { vertical-align: baseline; outline: 3px solid silver; }
img { float: left; clear: left; width: 32px; height: 32px; }
img[title] { float: none; }

<table><tr>
  <td>Baseline</td>
  <td>Baseline<table><tr><td>After</td></tr></table></td>
  <td><table><tr><td>Baseline</td></tr></table>After</td>
  <td><table align=right><tr><td>Before</td></tr></table><p>Baseline</p></td>
  <td><img src="http://w3.org/favicon.ico"><p>Baseline</p></td>
  <td><img src="http://w3.org/favicon.ico" title="Baseline"/><br/><img src="http://w3.org/favicon.ico" title="After"></td>
  <td><img src="http://w3.org/favicon.ico"><img src="http://w3.org/favicon.ico"><!--Baseline--></td>
</tr></table>
[see-caption-below]
준수하는 브라우저에서 이 예제의 렌더링

baseline을 찾는 목적상, 스크롤 메커니즘을 가진 in-flow 박스(overflow 속성 참조)는 자신의 원점 위치로 스크롤된 것처럼 간주되어야 한다.

셀의 baseline은 셀의 아래쪽 테두리보다 아래에 위치할 수 있다. 아래 예제를 참조하라.

이 예제의 셀은 아래쪽 테두리 아래에 baseline을 가진다:

div { height: 0; overflow: hidden; }

<table>
<tr>
<td>
<div> Test </div>
</td>
</tr>
</table>

각 테이블 셀의 vertical-align 속성은 행 안에서 그 정렬을 결정한다. 각 셀의 콘텐츠는 baseline, top, middle, bottom을 가지며, 행 자체도 마찬가지이다.

테이블 셀의 컨텍스트에서 vertical-align 값은 다음 의미를 가진다:

baseline 셀의 baseline은 그 셀이 span하는 첫 번째 행의 다른 셀들의 baseline과 정렬된다 (의 baseline 정의 참조).
top 셀 박스의 위쪽이 그 셀이 span하는 첫 번째 행의 위쪽과 정렬된다.
bottom 셀 박스의 아래쪽이 그 셀이 span하는 마지막 행의 아래쪽과 정렬된다.
middle 셀의 중심이 그 셀이 span하는 행들의 중심과 정렬된다.
... 다른 값은 셀에 적용되지 않는다; 대신 셀은 baseline에서 정렬된다.

'vertical-align: baseline'을 가진 모든 셀에 대해 셀 박스의 위쪽과 baseline 사이의 최대 거리가 행의 baseline을 설정하는 데 사용된다. 행에 'vertical-align: baseline'을 가진 셀이 없다면, 그 행의 baseline은 행에서 가장 낮은 셀의 아래쪽 content edge이다.

table-root의 baseline은 첫 번째 행이 있으면 그 행의 baseline이다. 그렇지 않으면 table-root의 아래쪽 content edge이다.

Testcase !!Testcase

모호한 상황을 피하기 위해, 셀의 정렬은 다음 순서로 진행된다:

이전 알고리즘이 행의 다양한 정렬선을 어떻게 생성하는지 보여 주는 예제.

[see-caption-below]
table 셀에 대한 vertical-align의 다양한 값의 효과를 보여 주는 도식. 셀 박스 1과 2는 baseline에 정렬된다. 셀 박스 2가 baseline 위쪽에서 가장 큰 높이를 가지므로, 그것이 행의 baseline을 결정한다.

행 레이아웃 중에는 행 안 셀의 지정된 높이가 무시되었고 하나보다 많은 행에 걸치는 셀이 올바르게 크기 지정되지 않았으므로, 그 높이는 최종적으로 자신이 span한 행 집합에 분배될 필요가 있다. 이는 열 측정과 같은 알고리즘을 실행하여 수행되며, span=1 값은 (min-content의 경우) 이전 행 레이아웃의 결과 높이, 대응하는 table-row에 지정된 높이(있다면), 그리고 이 행에만 span하는 셀에 지정된 가장 큰 높이 중 가장 큰 값으로 초기화된다 (알고리즘은 그 할당 위에서 span 2의 셀을 고려하는 것으로 시작한다).

EDITORIAL. 여기로 § 3.8.3 열 측정값 계산의 관련 절을 가져온다.

이 단계를 적용한 결과 크기가 증가한 행은 아래쪽을 낮추어 조정한다.

어떤 업데이트된 행의 아래쪽에 위치가 의존하던 셀은 각각의 행에서 다시 올바르게 배치되어야 한다.

이 시점에서, 자신이 span하는 행들의 집합적 높이보다 작은 셀 박스는 추가적인 위쪽 및/또는 아래쪽 padding을 받는다. 이를 통해 콘텐츠는 수직으로 이동하지 않지만 그 위/아래 edge는 자신이 span하는 첫 번째/마지막 행의 edge와 맞게 된다.

행 그룹에 정의된 높이는 이 알고리즘에서 무시된다는 점에 유의하라
테스트

3.10.3. 행 레이아웃 (두 번째 패스)

테이블 높이가 결정되면, 필요한 경우 행/셀에 지정된 height에 사용된 백분율을 고려하여 table-row에 올바른 최소 높이를 할당하기 위해 두 번째 행 레이아웃 패스가 수행된다. 그 밖에는 첫 번째 패스 행 레이아웃에 대한 모든 지시가 적용된다 (위 참조).

이 두 번째 패스 최소 높이는 따라서 여전히 table-cell 자손의 백분율 높이를 첫 번째 패스에서 권고된 것처럼 취급한다는 점에 유의하라 (위 참조). 이러한 이유로 새 행 최소 높이를 계산하기 위해 table-cell의 콘텐츠를 다시 레이아웃할 필요는 없다. 필요한 경우 table-cell 콘텐츠는 나중에, 테이블 높이 분배가 끝난 뒤 relayout을 거친다 (아래 참조).

그런 다음 이 두 번째 패스 이후 table-row의 새 높이 합이 이전에 결정된 테이블 높이를 채우는 데 필요한 것과 다르면, 아래에 정의된 높이 분배 알고리즘이 적용된다 아래 (행을 첫 번째 패스 최소 높이와 두 번째 패스 최소 높이 사이의 중간 크기로 줄이거나, 모든 행의 높이를 두 번째 패스 최소 높이 너머로 증가시켜 사용 가능한 공간을 채우기 위해; 어느 경우에도 이는 행의 baseline에 영향을 주지 않는다).

3.10.4. 핵심 분배 원칙

EDITORIAL. TODO. 현재 제안에 대해서는 § 3.10.5 분배 알고리즘으로 건너뛰라.
높이 분배에 대한 조사

3.10.5. 분배 알고리즘

첫 번째 단계는 각 행에 base size와 reference size를 부여하는 것이다.

base size는 테이블에 지정된 높이가 없었다면 가졌을 크기 (ROWMIN이 평가될 때 할당되었던 크기)이다.

reference size는 다음 중 가장 큰 값이다

두 번째 단계는 이러한 크기를 기준으로 각 행의 최종 높이를 계산하는 것이다.

테이블 높이가 reference size 합보다 작거나 같으면, 각 행에 할당되는 최종 높이는 올바른 전체 높이를 산출하는 base size와 reference size의 가중 평균이 된다.

그렇지 않고, 테이블이 “auto-height” 행 (크기가 콘텐츠 크기에 의해서만 결정되고 지정된 높이가 없는 행)을 하나라도 소유한다면, 각 non-auto-height 행은 reference height를 받고, auto-height 행은 reference size에 어떤 증가분을 더해 받는다. 이 증가분은 지정된 테이블 높이에 도달하기 위해 부족한 높이를 그러한 행의 수로 나눈 값과 같다.

그렇지 않으면, 모든 행은 reference size에 어떤 증가분을 더해 받는다. 이 증가분은 지정된 테이블 높이에 도달하기 위해 부족한 높이를 행의 수로 나눈 값과 같다.

어떤 업데이트된 행의 아래쪽에 위치가 의존하던 셀은 각각의 행에서 다시 올바르게 배치되어야 한다.

이 시점에서, 자신이 span하는 행들의 집합적 높이보다 작은 셀 박스는 추가적인 위쪽 및/또는 아래쪽 padding을 받는다. 이를 통해 콘텐츠는 수직으로 이동하지 않지만 그 위/아래 edge는 자신이 span하는 첫 번째/마지막 행의 edge와 맞게 된다.

테스트

3.10.6. Table-cell 콘텐츠 레이아웃 (두 번째 패스)

table-height 분배가 끝나고, 행 높이의 합에 간격/테두리를 더한 값이 테이블 높이와 같아지면, 첫 번째 패스 행 레이아웃 규칙에 의해 백분율 높이가 무시되거나 0px로 취급된 자손을 포함한 table-cell의 콘텐츠는 (위 참조) 아래에 정의된 대로 두 번째 레이아웃 패스를 거쳐야 한다.

이는 UA가 table-cell의 모든 직접 자식 속성에서 백분율 사용 여부를 추적해야 함을 의미한다는 점에 유의하라. 여기에는 가로 흐름에 대한 heightmin-height 속성과 세로 흐름에 대한 widthmin-width 속성이 포함되지만 이에 한정되지 않는다. 그렇지 않으면 모든 경우에 table-cell 콘텐츠에 대해 이 두 번째 레이아웃 패스를 수행해야 한다.

table-cell 콘텐츠에서 백분율 높이 해결: 높이 분배가 끝난 후 테이블과 행의 최종 크기가 결정되면, table-cell의 콘텐츠도 두 번째 레이아웃 패스를 거쳐야 한다. 여기서, 적절한 경우, 이번에는 백분율 기반 높이가 부모 셀의 사용 높이를 기준으로 해결된다.

table-cell의 직접 자식에서 백분율 높이를 해결하는 것이 적절하다는 것은 셀이 자신의 높이를 명시적으로 지정한 것으로 간주되거나 자식이 절대 위치 지정되었을 때이다. CSS 2를 참조하라.

호환성 이유로, 추가로 다음이 명확히 된다. 셀의 계산된 높이가 길이이거나, 그 table-root 조상의 계산된 높이가 길이 또는 백분율이면, 해당 백분율이 auto처럼 동작하는지 여부와 관계없이 셀은 자신의 높이를 명시적으로 지정한 것으로 간주된다.

앞의 문장을 명확히 하기 위해, 다음은 사용되는 값에 따른 결과 "A" div 높이를 나타내는 표이다:
<section style="height: var(--wrapper-height)">
  <table style="height: var(--table-height)">
    <tr>
      <td style="height: var(--table-cell-height)">

        <div style="height:100%; background:yellow">A</div>

      </td>
      <td style="height: var(--other-table-cell-height)">

        B<br>C

      </td>
    </tr>
  </table>
</section>
--table-cell-height --table-height 결과
<length> <any> 100%
<any> <length> 100%
<any> <percentage> 100%
auto auto auto
<percentage> auto auto

--other-table-cell-height--wrapper-height도 알고리즘의 결과에 영향을 주지 않는다는 점에 유의하라.

이 명세의 이전 버전은 테이블이 백분율 높이를 가질 때 --wrapper-height가 고려된다고 잘못 명시했지만, 구현이 배포되었을 때 호환성 문제가 나타났고, 그 동작은 이후 특별 처리되었다.

이 두 번째 레이아웃 패스(높이 백분율이 해결되는 곳)는 일부 셀 콘텐츠가 부모 셀을 overflow하게 만들 수 있다. 예를 들어 사용된 모든 백분율의 합이 100%보다 큰 경우이다. 이는 의도된 동작이다.
테스트

3.11. 셀, 캡션 및 기타 내부 테이블 박스의 위치 지정

테스트

visibility:collapse가 무엇을 하는지에 대한 결정이 필요하다. [Issue #478]

테이블 그리드의 각 열 너비와 각 행 높이가 결정되면, 알고리즘의 마지막 단계는 각 table-internal 박스에 최종 위치를 할당하는 것이다.

아래에서 계산되는 width/height/left/top은 CSS Layout Box의 치수를 정의한다. 이는 CSSOM-VIEW에 정의된 offset* 속성을 통해 접근 가능하다는 뜻이다 (현재는 대응하는 HTMLElement 참조를 얻을 수 있는 css 박스로 제한됨).

table-wrapper 박스는 모든 table-non-root 박스의 margin box와 table-root border-box를 포함하도록 크기가 정해진다.

여기서 정의된 위치는 table-wrapper를 위해 예약된 공간 내부에서의 자식 위치이며, 이 공간은 오직 그 margin만 제외한다. 이는 테이블의 캡션이 table-root의 border-box 영역 바깥에 배치되기 때문이다.

테이블 안에서 caption-side가 "top"인 임의의 table-caption의 위치는 다음과 같은 직사각형으로 정의된다:

테이블 안에서 임의의 table-cell, table-track 또는 table-track-group 박스의 위치는 다음과 같은 직사각형으로 정의된다:

알림: table-track 및 table-track-group 박스의 경우, 그룹화 방향의 반대 방향에 있는 모든 track은 span된 것으로 간주된다. 예를 들어 table-header-group은 모든 열을 span하는 것으로 간주되고, table-column-group은 모든 행을 span하는 것으로 간주된다.
위 공식은 border-spacing을 고려하며, 그 효과가 무엇인지 곧바로 명확하지 않을 수 있으므로, 이러한 공식의 몇 가지 성질을 여기에 둔다:

테이블 안에서 caption-side가 "bottom"인 임의의 table-caption의 위치는 다음과 같은 직사각형으로 정의된다:

셀 overflow: 테이블이 고정 모드로 레이아웃될 때, 어떤 셀의 콘텐츠가 두 번째 레이아웃 패스 중 그 셀보다 더 커졌거나 visible 셀이 span하는 일부 track이 visible이 아니라고 판단되면, 일부 셀의 콘텐츠가 사용 가능한 공간을 초과하여 overflow를 일으킬 수 있다. 이러한 overflow는 마치 그 셀이 자신의 inline-start block-start 모서리(일반적으로 왼쪽 위)에 상대적으로 콘텐츠를 제자리에 유지하기 위해 적절한 정렬이 적용된 절대 위치 지정 display:block 박스인 것과 정확히 같은 방식으로 동작해야 한다. !Testcase !Testcase Testcase
Visible tracks: 이 알고리즘의 목적상, 열 또는 행은 대응하는 table-track 및 그 table-track-group 부모(있다면) 중 어느 것도 visibilitycollapse로 설정되어 있지 않으면 visible track으로 간주된다.
위에 캡션이 있는 테이블로, 캡션 마진이 테이블 마진 안에 완전히 중첩되어 있지만 그럼에도 테이블의 border-box 바깥에 있음을 보여 준다.
위에 캡션이 있는 테이블의 도식.
~Testcase !!Testcase !!Testcase !!Testcase Testcase

4. 절대 위치 지정

4.1. table-root를 containing block으로 사용하는 경우

절대 위치 지정 요소의 containing blocktable-wrapper 박스에 의해 생성되는 경우, containing block은 테이블 마진이 적용되는 영역에 대응한다. 여기에는 테이블 테두리가 그려지는 영역과 모든 table-caption의 margin 영역이 포함된다. 그러면 offset 속성(top/right/bottom/left)은 일반적인 경우처럼 이 containing block의 대응하는 edge에서 안쪽으로의 offset을 나타낸다.

절대 위치 지정은 table 및 그 in-flow 콘텐츠의 레이아웃 이후에 발생하며, 어떤 table grid track의 크기 지정에도 기여하지 않고 테이블 그리드의 크기/구성에도 어떤 방식으로든 영향을 주지 않는다.

아래 그림은 테이블에 상대적으로 절대 위치 지정된 박스가 어떻게 렌더링되어야 하는지를 보여 준다.

노란색 영역은 테이블 content edge이고, 노란색 화살표는 테이블 마진이다.
초록색 영역은 테이블 캡션이고, 초록색 화살표는 캡션 마진이다.
파란색 영역은 테이블 배경 영역이며, 더 어두운 파란색 영역은 테이블 테두리 영역이다.
검은색 영역은 테이블에 상대적으로 위치 지정된 자손이고, 화살표는 top/left/bottom/right 변위를 나타낸다.
[see-caption-above]
테스트

4.2. table-internal을 containing block으로 사용하는 경우

절대 위치 지정 요소의 containing blocktable-internal에 의해 생성되는 경우, containing block은 레이아웃 중 박스에 할당될 영역의 왼쪽 위 모서리에서 시작하는 영역에 대응하지만, 그 크기는 모든 track이 visible로 간주되었을 때의 레이아웃 중 박스에 할당될 영역 중 하나로 계산된다(일부 박스에 visibility가 collapse로 설정되었는지 여부와 무관). 적절한 경우 borders 및 paddings는 포함하지 않는다.

이는 열을 숨기는 것이 절대 위치 지정 박스에서 레이아웃을 트리거하지 않도록 하고, 잘린 콘텐츠가 움직이는 것처럼 보이지 않게 하기 위해 수행된다. !!Testcase !!Testcase

offset 속성(top/right/bottom/left)은 일반적인 경우처럼 이 containing block의 대응하는 edge에서 안쪽으로의 offset을 나타낸다.

이는 Firefox에서만 동작한다. 하지만 향후 position:sticky를 구현하기 더 쉽게 만들 것이다. [Chrome bug] [Interop risk: Firefox bug] [Issue #858]

테스트

4.3. table-internal 박스를 non-containing block 부모로 사용하는 경우

절대 위치 지정 박스의 non-containing block 부모가 미치는 유일한 영향은 top+bottom 및/또는 left+right가 모두 auto가 되는 경우 그 static position을 정의하는 것이다.

table-cell의 경우, 절대 위치 지정 콘텐츠는 평소처럼 block layout 규칙에 따라 위치 지정된다.

table fixup 때문에, table-cell이 아닌 table-internal 박스의 자식인 절대 위치 지정 박스를 만드는 것은 불가능하다 (자세한 내용은 float 및 position에 대한 참고를 참조).

5. 렌더링

테스트

5.1. 셀의 페인트 순서

테이블 셀은 실제로 셀이 그려지게 되는 위치와 무관하게, 평소처럼 DOM 순서대로 table-root 안에서 페인트된다.

5.2. 빈 셀 렌더링(separated-borders 모드)

이름: empty-cells
값: show | hide
초깃값: show
적용 대상: table-cell 박스
상속: yes
백분율: n/a
계산값: 지정된 키워드
표준 순서: 문법 기준
애니메이션 타입: 불연속
테스트

collapsed-borders 모드에서는, 이 속성이 아무 효과도 없다.

separated-borders 모드에서, 이 속성의 값이 hide이면, empty cells의 주변/뒤에 어떤 테두리나 배경도 그려지지 않는다.

빈 셀은 다음을 포함하지 않는 table-cell이다:

empty-cells:hide를 단순화할 수 있는가? [Issue #605]

예를 들어, 다음 마크업과 css를 보자:

<table>
  <td><span></span></td>
  <td></td>
  <td><span></span></td>
</table>
table {
  width: 500px; height: 300px;
  empty-cells: hide;
}

table { background: black; border: 10px solid black; }
td { background: white; }

table { border-spacing: 0px; }
td { padding: 0; }

이 코드 조각의 올바른 렌더링은 여기에 묘사되어 있다:

[see-caption-below]
가운데 열이 empty-cells:hide로 숨겨진 세 열의 렌더링

5.3. 배경과 테두리 그리기

5.3.1. 테이블 배경과 테두리 그리기

다른 박스 타입과 달리, table 및 inline-table 박스는 자신의 전체 client rect 주변에 배경과 테두리를 페인트하지 않는다. 실제로 table caption은 시각적으로 테이블 마진과 테두리 사이에 위치해야 하며, 이는 table-root에 적용되는 다양한 효과의 그리기 영역을 수정할 필요가 있음을 의미한다.

페인팅 영역:

이는 absolute positioning 같은 이러한 개념의 다른 사용에는 영향을 주지 않는다.

!Testcase

테스트
5.3.1.1. collapsed-borders 모드에서의 변경

테이블이 collapsed-borders 모드로 레이아웃될 때, 그 테두리 및 table-cell의 테두리 렌더링은 수정된다. 다음 규칙은 그 방식이 어떠한지를 설명한다.

§ 5.3 배경과 테두리 그리기에 정의된 배경 및 테두리 페인팅 규칙은 재정의되지 않는 한 계속 적용된다.

테이블이 아닌 table-root의 테두리는 collapsed-borders 모드에서 페인트되지 않는다. 단, border-image 속성이 설정된 경우는 예외이다.

이 후자의 경우, 테두리는 테이블 테두리가 그 사용값이 지정하는 것보다 두 배 큰 것처럼, 그리고 그 초과분이 table-root의 padding 영역 안에 렌더링된 것처럼 그려진다.

테이블에 의해 그려지지 않더라도, 테이블 테두리는 여전히 레이아웃에서 그 공간을 차지한다. 셀은 그 공유 테두리를 렌더링한다.

테스트

5.3.2. 셀 배경 그리기

누락된 셀 수정 단계에 의해 추가된 익명 table-cell은 자신의 배경을 렌더링하지 않는다.

자신의 background 외에도, table-cell 박스는 자신이 속한 table-tracktable-track-group 박스의 배경도 렌더링한다. 이는 단순히 그 배경을 상속하는 것과는 실제로 다르다. 왜냐하면 background-originbackground-size 계산은 실제로 셀이 아닌 grouping 박스의 bounds에서 수행되기 때문이다.

각 테이블 셀의 배경을 찾는 목적상, 서로 다른 table 박스는 겹쳐진 여섯 개의 레이어 위에 있는 것으로 생각할 수 있다. 한 레이어에 설정된 배경은 그 위의 레이어들이 투명한 배경을 가질 때만 보인다.

[see-caption-below]
테이블 레이어의 도식.
  1. 테이블 배경은 테이블에 의해 렌더링되며, 셀 배경에 영향을 주지 않는다.
  2. 셀이 처음으로 그리는 배경은 그 셀의 originating table-column-group의 배경이다(있다면). background-positioning의 목적상, column group은 row/column grid에서 column group에서 originate하고 column group에 속하지 않는 어떤 열에도 들어가지 않으면서 단일 셀이 차지할 수 있는 가장 큰 가능한 영역을 차지할 것으로 기대된다.
  3. 셀이 두 번째로 그리는 배경은 그 셀의 originating table-column의 배경이다(있다면). background-positioning의 목적상, column은 row/column grid에서 column에서 originate하고 다른 어떤 열에도 들어가지 않으면서 단일 셀이 차지할 수 있는 가장 큰 가능한 영역을 차지할 것으로 기대된다.
  4. 셀이 세 번째로 그리는 배경은 그 셀의 originating table-row-group의 배경이다(있다면). background-positioning의 목적상, row group은 row/column grid에서 row group에서 originate하고 row group에 속하지 않는 어떤 행에도 들어가지 않으면서 단일 셀이 차지할 수 있는 가장 큰 가능한 영역을 차지할 것으로 기대된다.
  5. 셀이 네 번째로 그리는 배경은 그 셀의 originating table-row의 배경이다(있다면). background-positioning의 목적상, row는 row/column grid에서 row에서 originate하고 다른 어떤 행에도 들어가지 않으면서 단일 셀이 차지할 수 있는 가장 큰 가능한 영역을 차지할 것으로 기대된다.
  6. 셀이 다섯 번째로 그리는 배경은 자신의 배경이다. 이는 모든 배경이 렌더링된 뒤 맨 위에 나타나는 것이다.

위 그림이 보여 주듯이, 모든 행이 같은 수의 셀을 포함하더라도, 모든 셀이 지정된 콘텐츠를 가질 수 있는 것은 아니다. separated-borders 모드에서, 그들의 empty-cells 속성 값이 hide이면, 이러한 empty cells는 전혀 렌더링되지 않는다. 마치 visibility: hidden이 그들에게 지정된 것처럼 테이블 배경이 비쳐 보이게 한다.

테스트

5.3.3. 셀 테두리 그리기

separated-borders 모드에서 table cell의 테두리는 평소처럼 렌더링된다.

5.3.3.1. collapsed-borders 모드에서의 변경

table-cell의 테두리는 collapsed-borders 모드에서 셀 테두리가 그 사용값이 지정하는 것보다 두 배 큰 것처럼, 그리고 그 초과분이 셀의 margin 영역에 렌더링된 것처럼 렌더링된다. 추가 제약으로, 테이블 edge 중 하나에 위치하지 않는 테두리의 각 변에 대해, 그 테두리는 실제 사용값이 정의하는 border-box 그리기 영역으로 실제로 clip된다. 단, border-image 속성이 설정된 경우는 예외이다.

앞서 언급한 clipping 동작을 적용한 결과 테두리가 정수가 아닌 양의 device pixel 위에서 잘리게 되면, 브라우저는 clipping 영역의 x 및 y 값을 올림함으로써 대신 clipping 영역을 device pixel에 맞추기로 결정할 수 있다. 값을 올림하면 일반적인 writing mode에서, 여러 셀 사이에서 다투는 픽셀을 얻는 셀이 실제로 가장 왼쪽 위의 셀이 된다. 이 명세에 따르면 그 셀은 다른 셀보다 더 큰 명시도를 가진다. § 5.1 셀의 페인트 순서§ 3.7.1.1 병합된 테두리의 충돌 해결 알고리즘 참조.

테스트

5.3.4. 테두리 스타일(collapsed-borders 모드)

border-style 값 중 일부는 테이블이 collapsed-borders 모드에 있을 때 평소와 다른 의미를 가진다. 이러한 정의는 border-style 값에 대한 기본 동작을 재정의한다.

hidden

none과 같지만, 다른 모든 테두리도 억제한다(§ 3.7.1.3 테두리 스타일의 명시도 참조).

inset

ridge와 같다.

outset

groove와 같다.

5.4. visibility: collapse에 대한 렌더링

table part에 visibility: collapse가 설정되면, 렌더링은 그것이 table-cell, spanning table-cell, 또는 table-track/table-track-group에 있는지에 따라 다르게 처리된다.

테스트

5.4.1. visibility: collapse table cell 렌더링

CSS 2.2에서 말하듯이, table-cell의 visibility가 collapse로 설정되면, visibility: hidden이 설정된 것과 동일하게 렌더링된다.

이는 table-cell을 포함하는 table-row에 visibility:collapse를 설정할 때 발생한다. 행을 숨기되 다른 행에 걸치는 그 셀들을 계속 표시하려면, 해당 셀에 visibility:visible을 설정하여 그 값이 상속되지 않도록 하라.

table-cell이 하나보다 많은 table-track에 걸치고, 그 table-track 중 적어도 하나가 visibility: collapse로 설정되어 있다면, 콘텐츠를 table-cell의 border-box로 clip한다. 이는 셀이 걸치는 track 중 어느 것이 collapsed되었는지와 관계없이, 셀의 왼쪽 위(rtl에서는 오른쪽 위) 콘텐츠가 계속 보인다는 뜻이다.

5.4.2. visibility: collapse table-track 또는 table-track-group 렌더링

table-track 또는 table-track-groupvisibility: collapse가 있으면, 주어진 table-track 또는 table-track-group 안의 셀이 기여하는 모든 배경, 테두리 또는 outline은 완전히 collapsed되지 않은 셀에 계속 페인트된다 (그 셀들이 여러 track에 걸쳤기 때문이다).
테스트

6. 분할

6.1. fragmentainer 사이에서 나누기

테이블을 분할할 때, 사용자 에이전트는 그 행을 span하는 셀이 이후의 어떤 행도 span하지 않고, 그 높이가 fragmentainer의 높이와 너비 모두보다 적어도 두 배 작으면 테이블 행을 분할되지 않은 상태로 보존하려고 시도해야 한다. 다른 행은 자유롭게 분할 가능하다고 한다.

테이블이 fragmentainer 안에 완전히 들어가지 않고, 적어도 하나의 행은 fragmentainer 안에 완전히 들어갔으며, fragmentainer 안에 들어가지 않는 첫 번째 행이 자유롭게 분할 가능하지 않은 경우, 사용자 에이전트는 overflow 지점 이전과 그 지점에 있는 행 사이에 일정한 세로 간격을 삽입하여 두 행이 형제 fragmentainer에 분리되어 배치되도록 해야 한다. 분할에 header와 footer의 반복이 필요하고 footer가 반복되는 경우, footer는 fragmentainer의 마지막 행 바로 뒤에 와야 하며, 세로 간격은 반복된 footer 뒤에 삽입되어야 한다.

[see-caption-below]
두 페이지에 걸쳐 분할된 테이블의 예상 렌더링

현재 fragmentainer에 완전히 들어가는 행이 없거나 fragmentainer 안에 들어가지 않는 첫 번째 행이 자유롭게 분할 가능한 경우, 사용자 에이전트는 fragmentainer의 남은 높이를 모두 그 행의 셀들에 할당하고, 각 셀 안에 가능한 한 많은 콘텐츠를 독립적으로 맞춘 다음, 다음 fragment로 나누고 각 셀의 콘텐츠를 이전 fragment에서 중단된 위치부터 시작해야 한다 (계속되는 fragment에서는 위쪽 테두리를 다시 칠해서는 안 된다).

[see-caption-below]
두 페이지에 걸쳐 분할된 높은 행을 포함하는 테이블의 예상 렌더링

break-before 또는 break-aftertable-row-group 또는 table-row 박스에 적용되면, 사용자 에이전트는 나누기 지점의 앞과 뒤에 있는 행 사이에 일정한 세로 간격을 삽입하여 속성 값이 요구하는 대로 두 행이 형제 fragmentainer에 분리되어 배치되도록 해야 한다. 분할에 header와 footer의 반복이 필요하고 footer가 반복되는 경우, footer는 fragmentainer의 마지막 행 바로 뒤에 와야 하며, 세로 간격은 반복된 footer 뒤에 삽입되어야 한다.

6.2. 페이지 사이에서 header 반복

문서를 페이지 매체로 렌더링할 때, 사용자 에이전트는 페이지가 테이블의 fragmentainer이고, header/footer에 avoid break-inside가 적용되어 있으며, 이를 위해 필요한 높이가 페이지 높이의 2/4보다 작고 (header 행은 최대 1/4, footer 행은 최대 1/4), 그 페이지에서 어떤 행도 두 번 표시되지 않게 된다면, 테이블이 span하는 각 페이지에서 header 행footer 행을 반복해야 한다.

header 행이 반복될 때, 사용자 에이전트는 공간을 남겨 두고 필요한 경우 테이블 위쪽 테두리를 렌더링해야 한다. footer 행과 테이블 아래쪽 테두리에도 동일하게 적용된다.

[see-caption-below]
header와 footer가 있는 테이블이 두 페이지에 걸쳐 분할된 예상 렌더링

사용자 에이전트는 이 동작을 더 많은 분할 컨텍스트로 확장하기로 결정할 수 있다. 예를 들어 페이지뿐 아니라 열 사이에서도 header/row를 반복할 수 있다. 정적 문서를 렌더링하는 사용자 에이전트가 이러한 동작을 채택할 가능성이 더 높지만, 명세상 필수는 아니다.

7. 보안 고려 사항

CSS Tables를 사용해도 완화해야 할 보안 위험은 발생하지 않는다.

8. 개인정보 보호 고려 사항

CSS Tables를 사용해도 완화해야 할 개인정보 보호 위험은 발생하지 않는다.

9. 추적 중인 버그 목록

이 절은 규범적이지 않다.

10. 부록

10.1. CSS 및 HTML 속성 간 매핑

HTML4의 기본 스타일 시트는 그 모델이 css 속성과 값에 어떻게 매핑되는지를 보여 준다:

현재 CSS 구조로 매핑할 수 없는 제약을 위해 CSS에 대한 일부 확장이 사용되었다
table    { display: table }
thead    { display: table-header-group }
tbody    { display: table-row-group }
tfoot    { display: table-footer-group }
tr       { display: table-row }
td, th   { display: table-cell }
colgroup { display: table-column-group }
col      { display: table-column }
caption  { display: table-caption }
table, thead, tbody, tfoot, tr, td, th, colgroup, col, caption { box-sizing: border-box; }
thead, tfoot { break-inside: avoid }

table {
  box-sizing: border-box;
  border-spacing: 2px;
  border-collapse: separate;
  text-indent: initial;
}

thead, tbody, tfoot, table > tr { vertical-align: middle; }
tr, td, th { vertical-align: inherit; }

td, th { padding: 1px; }
th { font-weight: bold;  }

table, td, th { border-color: gray; }
thead, tbody, tfoot, tr { border-color: inherit; }



table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border: 1px solid inset;
}


table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) {
  border-collapse: collapse;
  border-style: hidden;
}

table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]),
table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border-color: black;
}

table[border=$border] /* if(parseInt($border) > 0) */ {
  border: /*(parseInt($border) * 1px)*/ outset rgb(128, 128, 128);
}
table[border=$border] > :is(thead,tbody,tfoot) > tr > :is(th,td) /* if(parseInt($border) > 0) */ {
  border: 1px inset rgb(128, 128, 128);
}

table[rules=all i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
}
table[rules=rows i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
  border-left: none;
  border-right: none;
}
table[rules=cols i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
  border-top: none;
  border-bottom: none;
}
table[rules=none i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: none;
}

table[rules=groups i] > :is(thead,tbody,tfoot) {
  border-top-width: 1px; border-top-style: solid;
  border-bottom-width: 1px; border-bottom-style: solid;
}
table[rules=groups i] > colgroup {
  border-left-width: 1px; border-left-style: solid;
  border-right-width: 1px; border-right-style: solid;
}

table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-style: outset;
}
table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-top-style: hidden;
}
table[frame=above i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-bottom-style: hidden;
}
table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
  border-left-style: hidden;
}
table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
  border-right-style: hidden;
}

table[cellpadding=$x] > :is(thead,tbody,tfoot) > tr > :is(th,td) /* if(parseInt($x)>0) */ {
  padding: /*(parseInt($x) * 1px)*/;
}
table[cellspacing=$x] /* if(parseInt($x)>0) */ {
  border-spacing: /*(parseInt($x) * 1px)*/;
}


table[width=$w] /* if(parseInt($w) > 0) */ {
  width: /*(parseInt($w) * 1px)*/;
}
table[width=$w] /* if($w matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
  width: /*(parseInt($w) * 1px)*/;
}
table[height=$h] /* if(parseInt($h) > 0) {
  height: /*(parseInt($h) * 1px)*/;
}
table[height=$h] /* if($h matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
  height: /*(parseInt($h) * 1px)*/;
}


table[bordercolor=$color] {
  border-color: /*parseHTMLColor($color)*/;
}
table[bordercolor] > :is(tbody, thead, tfoot, tr, colgroup, col),
table[bordercolor] > :is(tbody, thead, tfoot) > tr,
table[bordercolor] > :is(tbody, thead, tfoot) > tr > :is(td, th),
table[bordercolor] > tr > :is(td, th)
table[bordercolor] > colgroup > col
) {
  border-color: inherit;
}
table[bgcolor=$color] {
  background-color: /*parseHTMLColor($color)*/;
}
table[align=left i] {
  float: left;
}
table[align=right i] {
  float: right;
}
table[align=center i] {
  margin-left: auto;
  margin-right: auto;
}

caption[align=bottom i] { caption-side: bottom; }
:is(thead,tbody,tfoot,tr,td,th)[valign=top i] {
  vertical-align: top;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=middle i] {
  vertical-align: middle;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=bottom i] {
  vertical-align: bottom;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=baseline i] {
  vertical-align: baseline;
}

:is(thead,tbody,tfoot,tr,td,th)[align=absmiddle i] {
  text-align: center;
}

:is(colgroup,col,thead,tbody,tfoot,tr,td,th)[hidden] {
  visibility: collapse;
}

:is(td,th)[nowrap] { white-space: nowrap; }
:is(td,th)[nowrap][width=$w] /* if(quirksMode && parseInt($w) > 0) */ {
  white-space: normal;
}
테스트
여기의 일부 콘텐츠는 테이블의 HTML to CSS 매핑에 관한 WHATWG 명세에서 왔다. 그러나 여기에는 대부분의 브라우저에서 사실이 아닌 것도 포함되어 있으므로, 단순한 복사가 아니다. 따라서 한 출처에서 다른 출처로 병합할 때마다 각각의 병합에 대해 조사가 필요하다!

11. (누락된 절을 위한 링크 위치)

12. 변경 사항

2019년 7월 27일 작업 초안 이후의 중요한 변경 사항:

적합성

문서 규약

적합성 요구 사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 규범적 부분에서 사용하는 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 한다. 그러나 가독성을 위해, 이 명세에서는 이러한 단어가 모두 대문자로 나타나지는 않는다.

명시적으로 비규범이라고 표시된 절, 예제 및 참고를 제외한 이 명세의 모든 텍스트는 규범적이다. [RFC2119]

이 명세의 예제는 “for example”이라는 단어로 도입되거나 class="example"을 사용하여 규범적 텍스트와 구분된다. 다음과 같다:

이것은 정보성 예제의 예이다.

정보성 참고는 “Note”라는 단어로 시작하며 class="note"를 사용하여 규범적 텍스트와 구분된다. 다음과 같다:

참고, 이것은 정보성 참고이다.

Advisement는 특별한 주의를 환기하도록 스타일이 지정된 규범적 절이며, <strong class="advisement">를 사용하여 다른 규범적 텍스트와 구분된다. 다음과 같다: UA는 접근 가능한 대안을 제공해야 한다.

테스트

이 명세의 콘텐츠와 관련된 테스트는 이와 같은 “Tests” 블록에 문서화될 수 있다. 그러한 블록은 비규범적이다.


적합성 클래스

이 명세에 대한 적합성은 세 가지 적합성 클래스에 대해 정의된다:

스타일 시트
CSS 스타일 시트.
렌더러
스타일 시트의 의미를 해석하고 이를 사용하는 문서를 렌더링하는 UA.
저작 도구
스타일 시트를 작성하는 UA.

스타일 시트가 이 명세에 적합하려면, 이 모듈에서 정의한 구문을 사용하는 모든 문장이 일반 CSS 문법과 이 모듈에서 정의된 각 기능의 개별 문법에 따라 유효해야 한다.

렌더러가 이 명세에 적합하려면, 적절한 명세에 정의된 대로 스타일 시트를 해석하는 것에 더해, 이 명세가 정의한 모든 기능을 올바르게 구문 분석하고 문서를 그에 따라 렌더링함으로써 지원해야 한다. 그러나 장치의 제한 때문에 UA가 문서를 올바르게 렌더링할 수 없다고 해서 그 UA가 부적합해지는 것은 아니다. (예를 들어, UA는 단색 모니터에서 색상을 렌더링할 필요는 없다.)

저작 도구가 이 명세에 적합하려면, 일반 CSS 문법과 이 모듈의 각 기능에 대한 개별 문법에 따라 구문적으로 올바른 스타일 시트를 작성하고, 이 모듈에 설명된 스타일 시트의 다른 모든 적합성 요구 사항을 충족해야 한다.

부분 구현

작성자가 전방 호환 구문 분석 규칙을 활용하여 fallback 값을 할당할 수 있도록, CSS 렌더러는 사용 가능한 수준의 지원이 없는 모든 at-rule, 속성, 속성 값, 키워드 및 기타 구문 구조를 유효하지 않은 것으로 취급해야 하며(그리고 적절하게 무시해야 한다). 특히, 사용자 에이전트는 하나의 다중 값 속성 선언 안에서 지원하지 않는 구성 요소 값만 선택적으로 무시하고 지원되는 값은 존중해서는 안 된다. 어떤 값이든 유효하지 않은 것으로 간주되면 (지원되지 않는 값은 그렇게 간주되어야 하므로), CSS는 전체 선언이 무시될 것을 요구한다.

불안정 및 독점 기능의 구현

향후 안정적인 CSS 기능과의 충돌을 피하기 위해, CSSWG는 CSS의 불안정 기능 및 독점 확장 구현에 대해 모범 사례를 따를 것을 권장한다.

비실험적 구현

명세가 후보 권고안 단계에 도달하면 비실험적 구현이 가능하며, 구현자는 명세에 따라 올바르게 구현되었음을 입증할 수 있는 모든 CR 수준 기능에 대해 접두사 없는 구현을 공개해야 한다.

CSS 구현 간의 상호 운용성을 확립하고 유지하기 위해, CSS Working Group은 비실험적 CSS 렌더러가 어떤 CSS 기능의 접두사 없는 구현을 공개하기 전에 구현 보고서(필요한 경우 해당 구현 보고서에 사용된 테스트 케이스)를 W3C에 제출할 것을 요청한다. W3C에 제출된 테스트 케이스는 CSS Working Group의 검토와 수정을 받는다.

테스트 케이스와 구현 보고서 제출에 대한 추가 정보는 CSS Working Group 웹사이트 https://www.w3.org/Style/CSS/Test/에서 확인할 수 있다. 질문은 public-css-testsuite@w3.org 메일링 리스트로 보내야 한다.

색인

이 명세가 정의한 용어

참조에 의해 정의된 용어

참고 문헌

규범적 참고 문헌

[COMPOSITING-1]
Chris Harrelson. Compositing and Blending Level 1. 2024년 3월 21일. CRD. URL: https://www.w3.org/TR/compositing-1/
[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 2024년 3월 11일. CRD. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-BORDERS-4]
Elika Etemad; et al. CSS Borders and Box Decorations Module Level 4. 2025년 7월 22일. FPWD. URL: https://www.w3.org/TR/css-borders-4/
[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4. 2024년 8월 4일. WD. URL: https://www.w3.org/TR/css-box-4/
[CSS-BREAK-3]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 3. 2018년 12월 4일. CR. URL: https://www.w3.org/TR/css-break-3/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou. CSS Color Module Level 4. 2025년 4월 24일. CRD. URL: https://www.w3.org/TR/css-color-4/
[CSS-DISPLAY-4]
Elika Etemad; Tab Atkins Jr.. CSS Display Module Level 4. 2025년 11월 6일. WD. URL: https://www.w3.org/TR/css-display-4/
[CSS-GRID-2]
Tab Atkins Jr.; et al. CSS Grid Layout Module Level 2. 2025년 3월 26일. CRD. URL: https://www.w3.org/TR/css-grid-2/
[CSS-INLINE-3]
Elika Etemad. CSS Inline Layout Module Level 3. 2024년 12월 18일. WD. URL: https://www.w3.org/TR/css-inline-3/
[CSS-MASKING-1]
Dirk Schulze; Brian Birtles; Tab Atkins Jr.. CSS Masking Module Level 1. 2021년 8월 5일. CRD. URL: https://www.w3.org/TR/css-masking-1/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 2025년 10월 7일. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.. CSS Positioned Layout Module Level 3. 2025년 10월 7일. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad. CSS Box Sizing Module Level 3. 2021년 12월 17일. WD. URL: https://www.w3.org/TR/css-sizing-3/
[CSS-TEXT-4]
Elika Etemad; et al. CSS Text Module Level 4. 2024년 5월 29일. WD. URL: https://www.w3.org/TR/css-text-4/
[CSS-TRANSFORMS-1]
Simon Fraser; et al. CSS Transforms Module Level 1. 2019년 2월 14일. CR. URL: https://www.w3.org/TR/css-transforms-1/
[CSS-TRANSFORMS-2]
Tab Atkins Jr.; et al. CSS Transforms Module Level 2. 2021년 11월 9일. WD. URL: https://www.w3.org/TR/css-transforms-2/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 2024년 3월 22일. CRD. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 2024년 3월 12일. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 2011년 6월 7일. REC. URL: https://www.w3.org/TR/CSS2/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson. Filter Effects Module Level 1. 2018년 12월 18일. WD. URL: https://www.w3.org/TR/filter-effects-1/
[MEDIAQUERIES-5]
Dean Jackson; et al. Media Queries Level 5. 2021년 12월 18일. WD. URL: https://www.w3.org/TR/mediaqueries-5/
[RFC2119]
S. Bradner. RFC에서 요구 수준을 나타내는 데 사용하는 핵심 단어. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 2022년 11월 11일. WD. URL: https://www.w3.org/TR/selectors-4/

정보성 참고 문헌

[CSS-DISPLAY-3]
Elika Etemad; Tab Atkins Jr.. CSS Display Module Level 3. 2023년 3월 30일. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-TEXT-3]
Elika Etemad; Koji Ishii; Florian Rivoal. CSS Text Module Level 3. 2024년 9월 30일. CRD. URL: https://www.w3.org/TR/css-text-3/

속성 색인

이름 초깃값 적용 대상 상속 백분율 애니메이션 타입 표준 순서 계산값
border-collapse separate | collapse separate table grid 박스 yes n/a 불연속 문법 기준 지정된 키워드
border-spacing <length>{1,2} 0px 0px border-collapse가 separate인 table grid 박스 yes n/a 계산값 기준 문법 기준 두 개의 절대 길이
caption-side top | bottom top table-caption 박스 yes n/a 불연속 문법 기준 지정된 키워드
empty-cells show | hide show table-cell 박스 yes n/a 불연속 문법 기준 지정된 키워드
table-layout auto | fixed auto table grid 박스 no n/a 불연속 문법 기준 지정된 키워드

이슈 색인

2.1에서 온 border-collapsing의 breaking change [Issue #604]
collapsed border의 조화에서 명시도를 변경할 것인가? [Issue #606]
border collapsing 모드에서 intrinsic 오프셋 처리 [Issue #608]
EDITORIAL. colspanning 셀에서 너비를 분배하는 방식을 설명하는 이 방식은 잘못되었다. min-content 및 max-content 너비의 경우, intrinsic 너비 계산을 위한 초과 너비를 열에 분배하는 규칙을 참조해야 한다.
EDITORIAL. § 3.8.3 열 측정값 계산의 관련 절을 여기로 가져온다.
EDITORIAL. TODO. 현재 제안에 대해서는 § 3.10.5 분배 알고리즘으로 건너뛰라.
visibility:collapse가 무엇을 하는지에 대한 결정이 필요하다. [Issue #478]
이는 Firefox에서만 동작한다. 하지만 향후 position:sticky를 구현하기 더 쉽게 만들 것이다. [Chrome bug] [Interop risk: Firefox bug] [Issue #858]
empty-cells:hide를 단순화할 수 있는가? [Issue #605]
셀은 visibility:visible grouping 요소의 배경만 그린다고 말함으로써 row-group background를 숨겨야 하는가?