RenderingNG 심층 분석: LayoutNG 블록 조각화

이제 LayoutNG의 블록 단편화가 완료되었습니다. 이 도움말에서 작동 원리와 중요한 이유에 대해 알아보세요.

Morten Stenshorne
Morten Stenshorne

저는 Google Blink 렌더링 팀의 레이아웃 엔지니어인 Morten Stenshorne입니다. 저는 2000년대 초부터 브라우저 엔진 개발에 참여한 경험이 있고, Presto 엔진 (Opera 12 이하)에서 acid2 테스트를 통과하도록 돕고 다른 브라우저를 리버스 엔지니어링하여 Presto에서 테이블 레이아웃을 수정하는 등 즐거운 시간을 보냈습니다. 나는 또한 블록 단편화, 특히 Presto, WebKit, Blink의 multicol에 대해 인정하고 싶은 것보다 더 많은 시간을 보냈습니다. 지난 몇 년 동안 저는 Google에서 주로 LayoutNG에 블록 파편화 지원을 추가하는 작업을 주도해 왔습니다. 이번이 블록 조각화를 구현하는 마지막 때가 될 수 있으므로, 블록 조각화 구현에 대해 자세히 알아보세요. :)

블록 조각화란 무엇인가요?

블록 조각화는 CSS 블록 수준 상자 (예: 섹션 또는 단락)가 프래그먼트 컨테이너라는 하나의 프래그먼트 컨테이너 내부에 전체가 들어가지 않을 때 여러 프래그먼트로 분할하는 것입니다. 프래그먼트(Fragmentainer)는 요소가 아니지만 다중 열 레이아웃의 열 또는 페이징된 미디어의 페이지를 나타냅니다. 단편화가 발생하려면 콘텐츠가 프래그먼트 컨텍스트 내에 있어야 합니다. 단편화 컨텍스트는 일반적으로 다중 열 컨테이너 (콘텐츠가 열로 분할됨) 또는 인쇄 시 (콘텐츠가 페이지로 분할됨) 설정됩니다. 행이 여러 개인 긴 단락은 여러 프래그먼트로 분할하여 첫 번째 줄이 첫 번째 프래그먼트에 배치되고 나머지 행은 후속 프래그먼트에 배치되어야 할 수 있습니다.

두 개의 열로 구분된 텍스트 단락입니다.
이 예에서는 다중 열 레이아웃을 사용하여 단락을 두 개의 열로 분할했습니다. 각 열은 프래그먼트화된 흐름의 프래그먼트를 나타냅니다.

블록 단편화는 잘 알려진 또 다른 유형의 단편화, 즉 '줄 바꿈'이라고도 하는 선 단편화와 유사합니다. 둘 이상의 단어 (모든 텍스트 노드, 모든 <a> 요소 등)로 구성되고 줄바꿈을 허용하는 인라인 요소는 여러 프래그먼트로 분할될 수 있습니다. 각 프래그먼트는 서로 다른 행 상자에 배치됩니다. 행 상자는 열 및 페이지의 프래그먼트와 동일한 인라인 분할입니다.

LayoutNG 블록 파편화란 무엇인가요?

LayoutNGBlockFragmentation은 LayoutNG의 프래그먼트화 엔진을 재작성한 것으로, 수년간의 작업 끝에 올해 초 Chrome 102에서 첫 번째 부분이 마침내 출시되었습니다. 덕분에 '기존' 엔진에서는 근본적으로 해결할 수 없었던 오래된 문제가 해결되었습니다. 데이터 구조 측면에서 여러 NG 이전의 데이터 구조를 프래그먼트 트리에 직접 표시되는 NG 프래그먼트로 대체합니다.

예를 들어 이제 'break-before' 및 'break-after' CSS 속성의 'avoid' 값이 지원되므로 작성자는 헤더 바로 뒤에 나누기를 방지할 수 있습니다. 섹션의 콘텐츠가 다음 페이지에서 시작하는 반면 페이지에 마지막으로 배치된 항목이 헤더인 경우 일반적으로 보기 좋게 표시되지 않습니다. 대신 헤더 앞에 나누는 것이 좋습니다. 아래 그림의 예를 참고하세요.

첫 번째 예는 페이지 하단의 제목을 보여주고, 두 번째 예에서는 연결된 콘텐츠와 함께 다음 페이지의 상단에 제목을 표시합니다.

Chrome 102는 단편화 오버플로도 지원하므로 모놀리식 (깨지지 않는) 콘텐츠가 여러 열로 분할되지 않고 그림자 및 변형과 같은 페인트 효과가 올바르게 적용됩니다.

이제 LayoutNG의 블록 단편화가 완료됨

이 글을 작성하는 시점에는 LayoutNG에서 완전한 블록 파편화 지원을 완료했습니다. Chrome 102에서 제공되는 핵심 단편화 (줄 레이아웃, 부동 소수점 수, 흐름 외의 위치 지정을 포함한 블록 컨테이너) 가변 및 그리드 파편화는 Chrome 103에서, 테이블 파편화는 Chrome 106에서 출시되었습니다. 마지막으로 Chrome 108에서 인쇄가 출시되었습니다. 블록 조각화는 레이아웃을 실행하기 위해 기존 엔진에 의존하는 마지막 기능이었습니다. 즉, Chrome 108부터는 더 이상 레이아웃을 실행하는 데 기존 엔진을 사용하지 않습니다.

LayoutNG 데이터 구조는 실제로 콘텐츠를 배치하는 것 외에도 페인팅 및 히트 테스트를 지원하지만 offsetLeftoffsetTop와 같은 레이아웃 정보를 읽는 JavaScript API에는 여전히 일부 기존 데이터 구조를 사용합니다.

NG를 사용하여 모든 것을 배치하면 CSS 컨테이너 쿼리, 앵커 배치, MathML, 맞춤 레이아웃(Houdini)과 같이 LayoutNG 구현만 있고 레거시 엔진에 대응되지 않는 새로운 기능을 구현하고 제공할 수 있습니다. 컨테이너 쿼리의 경우 Google은 인쇄가 아직 지원되지 않는다는 경고를 개발자에게 미리 경고했습니다.

우리는 2019년에 LayoutNG의 첫 번째 부분을 출시했습니다. 이 파트는 일반 블록 컨테이너 레이아웃, 인라인 레이아웃, 부동 소수점 수, 흐름 외부 배치로 구성되었지만, flex, 그리드 또는 테이블을 지원하지 않고 블록 단편화를 전혀 지원하지 않습니다. Flex, 그리드, 테이블 및 블록 조각화와 관련된 모든 작업에 기존 레이아웃 엔진을 사용하는 방식으로 대체됩니다. 이는 단편화된 콘텐츠 내 블록, 인라인, 플로팅 및 out-of-flow 요소에도 해당되었습니다. 여기서 볼 수 있듯이 복잡한 레이아웃 엔진을 제자리에서 업그레이드하는 것은 매우 섬세한 작업입니다.

게다가 믿거나 말거나 2019년 중반이 되면 대부분의 LayoutNG 블록 단편화 레이아웃의 핵심 기능이 (플래그 뒤에서) 이미 구현되었습니다. 그렇다면 배송에 왜 이렇게 오래 걸렸을까요? 간단히 말해서 파편화는 시스템의 다양한 기존 부분과 올바르게 공존해야 하며, 모든 종속 항목이 업그레이드될 때까지 삭제하거나 업그레이드할 수 없습니다. 자세한 내용은 다음 세부정보를 참조하세요.

기존 엔진 상호작용

레거시 데이터 구조는 여전히 레이아웃 정보를 읽는 JavaScript API를 담당하므로, 레거시 엔진이 이해하는 방식으로 데이터를 레거시 엔진에 다시 작성해야 합니다. 여기에는 LayoutMultiColumnFlowThread와 같은 기존 다중 열 데이터 구조를 올바르게 업데이트하는 작업이 포함됩니다.

기존 엔진 대체 감지 및 처리

LayoutNG 블록 파편화로 처리할 수 없는 콘텐츠가 내부에 있을 때 레거시 레이아웃 엔진으로 대체해야 했습니다. 출하 당시 코어 LayoutNG의 블록 단편화 (2022년 봄)에는 Flex, 그리드, 테이블, 출력되는 모든 항목이 포함되었습니다. 이 작업은 특히 까다로웠습니다. 레이아웃 트리에서 객체를 만들기 전에 레거시 대체의 필요성을 감지해야 했기 때문입니다. 예를 들어 다중 열 컨테이너 상위 항목이 있는지, 그리고 어떤 DOM 노드가 형식 지정 컨텍스트가 될지 파악하기 전에 먼저 감지해야 했습니다. 완벽한 해결책은 없지만 오탐이 거짓양성 (실제로 필요하지 않은 레거시로 대체)이라면 문제가 없습니다. 레이아웃 동작의 모든 버그는 Chromium이 새로운 것이 아니라 이미 있는 버그이기 때문입니다.

미리 페인트칠한 나무 산책

사전 페인트는 레이아웃 이후, 페인트 전에 하는 작업입니다. 중요한 문제는 여전히 레이아웃 객체 트리를 살펴보아야 하지만 이제 NG 프래그먼트가 있다는 것입니다. 그렇다면 이를 어떻게 처리해야 할까요? 레이아웃 객체와 NG 프래그먼트 트리를 동시에 걸어 봅니다. 이는 매우 복잡합니다. 두 트리 간의 매핑이 간단하지 않기 때문입니다. 레이아웃 객체 트리 구조는 DOM 트리의 구조와 매우 흡사하지만 프래그먼트 트리는 레이아웃의 입력이 아니라 레이아웃의 출력입니다. 프래그먼트 트리는 인라인 조각화 (줄 조각) 및 블록 조각화 (열 또는 페이지 조각)를 비롯한 모든 단편화의 영향을 실제로 반영하는 것 외에도 포함하는 블록과 이 프래그먼트를 포함 블록으로 가진 DOM 하위 요소 간에 직접적인 상위-하위 관계가 있습니다. 예를 들어 프래그먼트 트리에서 절대 위치로 배치된 요소에 의해 생성된 프래그먼트는 흐름이 벗어난 하위 요소 및 포함하는 블록 사이에 상위 체인에 다른 노드가 있는 경우에도 포함된 블록 프래그먼트의 직접 하위 요소입니다.

단편화 내부에 흐름이 벗어난 위치에 배치된 요소가 있으면 더 복잡해집니다. 흐름에서 벗어난 프래그먼트가 fragmentainer의 직접 하위 요소가 되고 CSS에서 포함 블록이라고 생각하는 하위 요소의 하위 요소가 되지 않기 때문입니다. 안타깝게도 이 문제는 큰 문제 없이 기존 엔진과 공존하기 위해 해결해야 했던 문제였습니다. LayoutNG는 모든 최신 레이아웃 모드를 유연하게 지원하도록 설계되었기 때문에, 앞으로 이 코드의 많은 부분을 단순화할 수 있을 것입니다.

기존 단편화 엔진의 문제

초기 웹의 시대에 설계된 레거시 엔진에는 그 당시에 인쇄를 지원하기 위해 단편화가 기술적으로 존재했더라도 실제로 단편화 개념이 없습니다. 단편화 지원은 단순히 위에 고정 (인쇄)되거나 재구성 (다중 열)된 것이었습니다.

분할 가능한 콘텐츠를 배치할 때 레거시 엔진은 너비가 열이나 페이지의 인라인 크기이고 높이는 콘텐츠를 포함하는 데 필요한 만큼의 긴 스트립에 모든 항목을 배치합니다. 이렇게 긴 스트립은 페이지에 렌더링되지 않습니다. 가상 페이지를 렌더링하고 최종 디스플레이를 위해 다시 배열되는 것으로 생각하면 됩니다. 이는 신문 기사 전체를 하나의 열로 인쇄한 다음 2단계로 가위를 사용해 여러 개로 자른 것과 같은 개념입니다. (예전에는 일부 신문에서 이와 유사한 기법을 사용했습니다.)

기존 엔진은 스트립에 있는 가상의 페이지 또는 열 경계를 추적합니다. 따라서 경계를 벗어나는 콘텐츠를 다음 페이지나 열로 조금씩 이동할 수 있습니다. 예를 들어 엔진에서 현재 페이지라고 생각하는 부분에 라인의 위쪽 절반만 들어맞을 경우 '페이지 매기기 스트럿'을 삽입하여 엔진이 다음 페이지 상단이 있다고 가정하는 위치까지 아래로 밀어냅니다. 그런 다음, 대부분의 실제 단편화 작업('가위로 잘라내고 배치')은 사전 페인트 또는 긴 페이지의 콘텐츠를 스트립핑 (스트립팅)하는 동안 레이아웃 후에 진행됩니다. 이로 인해 변환 적용 및 분할 이후의 상대 위치 지정 (사양에 필요한 사항)과 같은 몇 가지 작업이 기본적으로 불가능했습니다. 또한 레거시 엔진에서는 테이블 조각화를 위한 지원이 어느 정도 있지만 가변 또는 그리드 조각화는 전혀 지원되지 않습니다.

다음은 가위, 배치, 접착제를 사용하기 전에 기존 엔진에서 3열 레이아웃이 내부적으로 어떻게 표현되는지를 보여주는 그림입니다. 4줄만 들어가도록 높이를 지정했지만 하단에 불필요한 공간이 있습니다.

콘텐츠가 분할되는 페이지로 나누기 스트러트가 있는 1개의 열로 표현되고 화면상의 표현은 3개의 열로 표시됩니다.

기존 레이아웃 엔진은 레이아웃 중에 실제로 콘텐츠를 조각하지 않기 때문에 상대 위치 및 변환이 잘못 적용되고 상자 그림자가 열 가장자리에서 잘리는 등 이상한 아티팩트가 많이 있습니다.

다음은 텍스트 그림자를 사용한 간단한 예입니다.

기존 엔진은 이를 제대로 처리하지 못합니다.

두 번째 열에 잘린 텍스트 그림자를 배치합니다.

첫 번째 열의 줄에서 나오는 텍스트 그림자가 어떻게 잘리고 대신 두 번째 열의 맨 위에 배치되는지 보이십니까? 기존 레이아웃 엔진이 단편화를 이해하지 못하기 때문입니다.

다음과 같아야 합니다 (NG에서는 다음과 같음).

그림자가 올바르게 표시되는 텍스트 열 2개

이제 변환과 상자 그림자를 사용하여 좀 더 복잡하게 만들어 보겠습니다. 기존 엔진에서는 클리핑 및 컬럼 블리드가 잘못된 것을 확인할 수 있습니다. 그 이유는 변환은 사양에 따라 레이아웃 후, 사후 조각화 효과로 적용되어야 하기 때문입니다. LayoutNG 단편화를 사용하면 둘 다 올바르게 작동합니다. 이는 Firefox와의 상호운용성을 높입니다. Firefox는 한동안 우수한 단편화를 지원했으며 이 영역의 대부분의 테스트도 통과합니다.

상자가 두 열로 잘못 구분되어 있습니다.

레거시 엔진에는 세로로 긴 모놀리식 콘텐츠에도 문제가 있습니다. 여러 프래그먼트로 분할할 수 없는 경우 콘텐츠는 모놀리식입니다. 오버플로 스크롤이 있는 요소는 모놀리식입니다. 사용자가 직사각형이 아닌 영역에서 스크롤하는 것은 적합하지 않기 때문입니다. 모놀리식 콘텐츠의 다른 예로는 선 상자와 이미지가 있습니다. 예를 들면 다음과 같습니다.

모놀리식 콘텐츠의 조각이 너무 길어서 열 안에 들어가지 못하면 레거시 엔진이 무자비하게 잘라내며 스크롤 가능한 컨테이너를 스크롤하려고 할 때 매우 '흥미로운' 동작을 초래합니다.

LayoutNG 블록 조각화의 경우처럼 첫 번째 열을 오버플로하는 대신 다음을 사용합니다.

ALT_TEXT_HERE

기존 엔진은 강제 중단을 지원합니다. 예를 들어 <div style="break-before:page;">는 DIV 앞에 페이지 나누기를 삽입합니다. 하지만 최적의 강제 나누기를 찾는 기능은 제한적으로만 지원됩니다. break-inside:avoid분리된 항목과 연결된 여성을 지원하지만, 예를 들어 break-before:avoid를 통해 요청된 경우 블록 간 중단을 피하는 기능은 지원되지 않습니다. 다음 예를 살펴보세요.

텍스트가 열 2개로 분할되었습니다.

여기서 #multicol 요소는 각 열에 5줄을 위한 공간이 있으므로 (높이가 100px이고 행 높이가 20px이므로) 모든 #firstchild이 첫 번째 열에 들어갈 수 있습니다. 그러나 동위 #secondchild에는 break-before:avoid가 있습니다. 즉, 콘텐츠는 둘 사이에 브레이크가 발생하지 않기를 원합니다. widows 값이 2이므로 모든 광고 중단 회피 요청을 적용하려면 #firstchild의 두 줄을 두 번째 열에 푸시해야 합니다. Chromium은 이러한 기능 조합을 완벽하게 지원하는 최초의 브라우저 엔진입니다.

NG 단편화의 작동 방식

일반적으로 NG 레이아웃 엔진은 CSS 상자 트리 깊이부터 순회하여 문서를 배치합니다. 노드의 모든 하위 요소가 배치되면 NGPhysicalFragment를 생성하고 상위 레이아웃 알고리즘으로 반환하여 해당 노드의 레이아웃을 완료할 수 있습니다. 이 알고리즘은 하위 프래그먼트 목록에 프래그먼트를 추가하며, 모든 하위 프래그먼트가 완료되면 모든 하위 프래그먼트가 안에 포함된 프래그먼트를 자체적으로 생성합니다. 이 메서드를 통해 전체 문서의 프래그먼트 트리를 만들 수 있습니다. 하지만 이는 지나치게 단순화된 것입니다. 예를 들어, 흐름에서 벗어난 위치에 배치된 요소는 배치되기 전에 DOM 트리의 위치에서 포함 블록으로 위로 올라와야 합니다. 편의상 이 고급 세부정보는 무시합니다.

LayoutNG는 CSS 상자 자체와 함께 레이아웃 알고리즘에 제약 조건 공간을 제공합니다. 이를 통해 레이아웃에 사용 가능한 공간, 새 서식 지정 컨텍스트의 설정 여부, 이전 콘텐츠에서 중간 여백 축소 결과 등의 정보를 알고리즘에 제공합니다. 제약 조건 공간은 Fragmentainer의 배치된 블록 크기와 프레그먼트에 들어가는 현재 블록 오프셋도 알고 있습니다. 줄바꿈 위치를 나타냅니다.

블록 단편화가 관련되면 하위 요소의 레이아웃이 중단되는 시점에 중지해야 합니다. 페이지 또는 열의 공간이 부족하거나 강제 종료하는 경우 오류가 발생합니다. 그런 다음 방문한 노드의 프래그먼트를 생성하고 단편화 컨텍스트 루트 (멀티컬 컨테이너 또는 인쇄의 경우 문서 루트)까지 반환합니다. 그런 다음 단편화 컨텍스트 루트에서 새 Fragmentainer를 준비하고 다시 트리로 내려가 중단 전에 중단한 부분부터 다시 시작합니다.

중단 후 레이아웃을 재개하는 수단을 제공하는 데 중요한 데이터 구조를 NGBlockBreakToken이라고 합니다. 다음 Fragment에서 레이아웃을 올바르게 재개하는 데 필요한 모든 정보가 포함되어 있습니다. NGBlockBreakToken은 노드와 연결되며 NGBlockBreakToken 트리를 형성합니다. 그러면 재개해야 하는 각 노드가 표시됩니다. NGBlockBreakToken은 내부에서 손상된 노드용으로 생성된 NGPhysicalBoxFragment에 연결됩니다. 시점 토큰은 상위 요소에 전파되어 시점 토큰 트리를 형성합니다. 노드 내부가 아닌 앞에 중단해야 하는 경우 프래그먼트가 생성되지 않지만 상위 노드는 여전히 노드에 대한 '브레이킹 전' 중단 토큰을 만들어야 합니다. 그러면 다음 Fragmentainer의 노드 트리에서 동일한 위치에 도달하면 이를 배치할 수 있습니다.

중단은 Fragmentainer 공간이 부족하거나 (강제 중단), 강제 종료가 요청될 때 삽입됩니다.

사양에는 최적의 강제 종료 시점을 위한 규칙이 있으며 공간이 부족한 곳에 정확하게 광고 시점을 삽입하는 것이 항상 올바른 방법은 아닙니다. 예를 들어 광고 시점 위치 선택에 영향을 주는 다양한 CSS 속성(예: break-before)이 있습니다. 따라서 레이아웃 중에 강제 중단 사양 섹션을 올바르게 구현하려면 좋은 중단점을 추적해야 합니다. 이 레코드는 중단 회피 요청을 위반하는 지점 (예: break-before:avoid 또는 orphans:7)에 공간이 부족할 경우 지금까지 발견된 최선의 중단점으로 돌아가서 사용할 수 있음을 의미합니다. 가능한 각 중단점에는 '최후의 수단으로만 사용'부터 '완벽한 휴식 위치'에 이르는 다양한 점수가 부여됩니다. 광고 시점이 '완벽'하다고 점수를 받았다면 휴식 시간에서 어긋날 경우 규정을 위반하지 않는다는 의미입니다 (정확히 공간이 부족한 지점에 이 점수를 얻으면 이전으로는 더 이상 돌아볼 필요가 없습니다). 점수가 '마지막 수단'인 경우 중단점이 유효한 것이 아니지만, 더 나은 결과를 찾지 못한 경우 프래그먼트에서 프래그먼트를 중단하여 프래그먼트 오버플로를 방지할 수 있습니다.

유효한 중단점은 일반적으로 동위 요소 (줄 상자 또는 블록) 사이에만 발생하며, 예를 들어 상위 요소와 첫 번째 하위 요소 사이에서만 발생하지 않습니다 (클래스 C 중단점은 예외이지만 여기서는 이에 대해 다루지 않습니다). 예를 들어 break-before:avoid가 있는 블록 동위 블록 앞에 유효한 중단점이 있지만 'perfect'와 'last-resort' 사이에 있습니다.

레이아웃 중에 NGEarlyBreak라는 구조에서 지금까지 찾은 최적의 중단점을 추적합니다. 조기 중단은 블록 노드 앞이나 내부 또는 선 (블록 컨테이너 라인 또는 가변 선) 앞에 가능한 중단점입니다. 가장 좋은 중단점이 공간이 부족할 때 이전에 걸었던 부분의 깊은 어딘가에 있는 경우 NGEarlyBreak 객체의 체인이나 경로를 형성할 수 있습니다. 예를 들면 다음과 같습니다.

여기서는 #second 바로 앞에 공간이 부족하지만 'break-before:avoid'가 있으므로 광고 시점 위치 점수인 'vioating break 배포'가 발생합니다. 이때 'perfect'가 있는 'inside #outer > 내부 #middle > #inner 내부 > 'line 3' 앞에 NGEarlyBreak 체인이 있습니다. 따라서 여기서 중단하는 것이 좋습니다. 따라서 #outer 시작 부분부터 레이아웃을 다시 실행하고 다시 실행해야 합니다 (이번에는 찾은 NGEarlyBreak를 전달함). 그러면 #inner의 3번째 줄 전에 브레이크할 수 있습니다. widows:4를 준수하기 위해 나머지 4개 행이 다음 Fragmentainer에 포함되도록 '3행' 앞에 줄바꿈을 넣습니다.

알고리즘은 일부 규칙을 충족할 수 없는 경우 올바른 순서로 삭제함으로써 spec에 정의된 대로 가능한 한 최적의 중단점에서 항상 중단되도록 설계되었습니다. 레이아웃은 프래그먼트 흐름당 최대 한 번만 수행하면 됩니다. 두 번째 레이아웃 패스에 있을 때는 최적의 광고 시점 위치가 이미 레이아웃 알고리즘에 전달되었습니다. 이는 첫 번째 레이아웃 패스에서 발견되어 해당 라운드에서 레이아웃 출력의 일부로 제공된 광고 시점 위치입니다. 두 번째 레이아웃 패스에서는 공간이 부족할 때까지 배치하지 않습니다. 실제로는 공간이 부족할 것으로 예상되지 않습니다(실제로는 오류임). 왜냐하면 불필요한 규칙을 위반하지 않기 위해 조기에 휴식을 삽입할 수 있는 매우 달콤한 공간이 제공되었기 때문입니다. 그래서 그 지점까지만 배치하고 중단합니다.

이 점에 유의하여 Fragmentainer 오버플로를 방지하는 데 도움이 된다면 일부 중단 회피 요청을 위반해야 할 수도 있습니다. 예:

여기서는 #second 직전에 공간이 부족하지만 'break-before:avoid'가 있습니다. 그것은 마지막 예와 같이 "위반 브레이크 회피"로 번역됩니다. 'vioating orphans and widows' (#first 내부 > 'line 2' 앞)가 있는 NGEarlyBreak도 있습니다. 이 역시 완벽하지는 않지만 'vioating break 없애기'보다는 낫습니다. 따라서 '두 번째 줄' 전에 중단되어 고아 또는 미망인 요청을 위반하게 됩니다. 이 사양은 4.4. 강제 종료되지 않은 중단: 프래그먼트 세이너 오버플로를 방지하기에 중단점이 충분하지 않은 경우 먼저 무시되는 중단 규칙을 정의합니다.

요약

LayoutNG 블록 조각화 프로젝트의 주요 기능 목표는 버그 수정 외에 기존 엔진이 지원하는 모든 것을 LayoutNG 아키텍처 지원 구현을 제공하는 것이었습니다. 여기서 주요 예외는 더 나은 중단 방지 지원 (예: break-before:avoid)입니다. 조각화 엔진의 핵심 부분이므로 처음부터 추가해야 했기 때문입니다. 나중에 추가하면 또 다른 재작성이 발생하게 되기 때문입니다.

이제 LayoutNG 블록 조각화가 완료되었으므로 인쇄 시 혼합된 페이지 크기 지원, 인쇄 시 @page 여백 상자, box-decoration-break:clone 등 새로운 기능을 추가할 수 있습니다. 또한 LayoutNG와 마찬가지로 시간이 지남에 따라 새 시스템의 버그 비율과 유지보수 부담이 크게 감소할 것으로 예상됩니다.

읽어주셔서 감사합니다.

감사의 말