CSS 지역 및 제외가 포함된 잡지와 유사한 웹용 레이아웃

Christian Cantrell
Christian Cantrell

소개

웹은 텍스트를 위한 매우 강력한 플랫폼으로, Adobe는 이 분야에서 많은 경험과 전문성을 보유하고 있습니다. 따라서 Adobe는 웹을 발전시키는 데 도움이 되는 방법을 모색할 때 웹의 텍스트 기능을 더욱 발전시키는 것이 가장 먼저 시작해야 할 일이라고 생각했습니다. 웹은 일반적으로 텍스트의 열이 하나이고 세로 방향이라고 가정합니다. 그래픽 주위에 텍스트를 흐르게 하고 CSS로 텍스트를 여러 열로 형식 지정할 수도 있지만 웹에서 진정한 잡지와 같은 레이아웃을 구현하는 것은 여전히 매우 어렵습니다. Adobe는 CSS 영역CSS 제외를 통해 데스크톱 출판의 강력한 기능을 최신 브라우저에 제공하기 위한 노력을 주도하고 있습니다. 예를 들어 아래 스크린샷에서는 CSS 제외를 사용하여 산의 윤곽선을 따라 텍스트를 흐르게 하고 있습니다.

CSS 제외가 적용된 예
작동 중인 CSS 제외의 예

아래 스크린샷의 문서에서는 CSS 제외를 사용하여 텍스트가 이미지의 도형을 감싸도록 하고 CSS 영역을 사용하여 텍스트를 열로, 그리고 발췌문 주위에 서식을 지정합니다.

CSS 영역이 적용된 예
작동 중인 CSS 리전의 예

CSS 리전

CSS 리전에 대해 자세히 알아보기 전에 Google Chrome에서 리전을 사용 설정하는 방법을 알아보겠습니다. CSS 지역을 사용 설정한 후 이 도움말에 언급된 샘플을 사용해 보고 나만의 샘플을 만들 수 있습니다.

Chrome에서 CSS 영역 사용 설정

Chrome 버전 20 (정확히는 버전 20.0.1132.57)부터 CSS 영역이 chrome://flags 인터페이스를 통해 사용 설정됩니다. CSS 영역을 사용 설정하려면 다음 단계를 따르세요.

  1. Chrome에서 새 탭 또는 창을 엽니다.
  2. 위치 표시줄에 chrome://flags를 입력합니다.
  3. 페이지에서 찾기 (control/command + f)를 사용하고 '실험용 웹 플랫폼 기능' 섹션을 검색합니다.
  4. 사용 설정 링크를 클릭합니다.
  5. 하단의 지금 다시 실행 버튼을 클릭합니다.

Chrome 플래그에 관한 자세한 내용은 Chrome 플래그에 대한 모든 정보에 관한 블로그 게시물을 참고하세요.

브라우저를 다시 실행하면 CSS 영역을 자유롭게 실험할 수 있습니다.

CSS 영역 개요

CSS 영역을 사용하면 의미론적 마크업을 적용한 텍스트 블록이 '상자' (현재는 요소)로 자동으로 흐를 수 있습니다. 아래 다이어그램은 텍스트 (흐름)와 상자 (텍스트가 흐르는 영역)의 분리를 보여줍니다.

콘텐츠가 지정된 지역으로 흐름
정의된 지역으로 콘텐츠 흐름

실제 CSS Regions 사용 사례를 살펴보겠습니다. 저는 Adobe의 개발자이자 공상과학 소설 작가입니다. 저는 Creative Commons 라이선스에 따라 온라인에 저작물을 자주 게시하며, 최대한 많은 기기와 브라우저에서 작동하도록 하기 위해 다음과 같이 매우 간단한 형식을 자주 사용합니다.

스타일이 지정되지 않은 인간 유산 프로젝트 예
스타일이 지정되지 않은 인류 유산 프로젝트 예시

CSS 영역을 사용하면 탐색이 더 쉽고 읽기 더 편안해 시각적으로 더 흥미롭고 훨씬 더 기능적인 환경을 만들 수 있었습니다.

지역을 보여주는 인류 유산 프로젝트
지역이 있는 인적 자산 프로젝트

데모 목적으로 이 프로토타입에 CSS 영역을 표시하는 기능을 추가했습니다. 아래 스크린샷은 그래픽과 중앙의 풀커트 주위를 둘러싸는 열처럼 보이도록 영역이 배치된 방식을 보여줍니다.

리전을 보여주는 인간 유산 프로젝트
지역을 보여주는 인적 자원 기존 프로젝트

여기에서 이 프로토타입을 실험하고 소스 코드를 볼 수 있습니다. 화살표 키를 사용하여 이동하고 Esc 키를 눌러 지역을 표시합니다. 이전 프로토타입은 여기에서 확인할 수 있습니다.

이름이 지정된 흐름 만들기

텍스트 블록이 영역을 통해 흐르도록 하는 데 필요한 CSS는 매우 간단합니다. 아래 스니펫은 ID가 'content'인 div에 'article'이라는 이름의 흐름을 할당하고 동일한 'article'이라는 이름의 흐름을 클래스가 'region'인 모든 요소에 할당합니다. 그 결과 'content' 요소 내에 포함된 텍스트가 'region' 클래스가 있는 모든 요소를 통해 자동으로 흐르게 됩니다.

<!DOCTYPE html>
<html>
<head>
    <style>
    #content {
        { % mixin flow-into: article; % }
    }

    .region {
        { % mixin flow-from: article; % }
        box-sizing: border-box;
        position: absolute;
        width: 200px;
        height: 200px;
        padding: 10px;
    }

    #box-a {
        border: 1px solid red;
        top: 10px;
        left: 10px;
    }

    #box-b {
        border: 1px solid green;
        top: 210px;
        left: 210px;
    }

    #box-c {
        border: 1px solid blue;
        top: 410px;
        left: 410px;
    }
    </style>
</head>
<body>
    <div id="box-a" class="region"></div>
    <div id="box-b" class="region"></div>
    <div id="box-c" class="region"></div>
    <div id="content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eleifend dapibus felis, a consectetur nisl aliquam at. Aliquam quam augue, molestie a scelerisque nec, accumsan non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin cursus euismod nisi, a egestas sem rhoncus eget. Mauris non tortor arcu. Pellentesque in odio at leo volutpat consequat....
    </div>
</body>
</html>

결과는 다음과 같습니다.

위 코드의 결과
위 코드의 결과

'content' div 내의 텍스트는 텍스트의 표현에 관해 알지 못합니다. 즉, 다양한 지역을 통과하면서도 의미상 완전히 온전하게 유지될 수 있습니다. 또한 지역은 요소에 불과하므로 다른 요소와 마찬가지로 CSS를 사용하여 위치를 지정하고 크기를 조절할 수 있으므로 반응형 디자인 원칙과 완벽하게 호환됩니다. 요소를 이름이 지정된 흐름의 일부로 지정한다는 것은 지정된 텍스트가 요소를 통해 자동으로 흐른다는 의미입니다.

CSS 객체 모델

CSS 객체 모델(CSSOM)은 CSS 작업을 위한 JavaScript API를 정의합니다. 다음은 CSS 리전과 관련된 새 API 목록입니다.

  • document.webkitGetNamedFlows(): 문서에서 사용할 수 있는 이름이 지정된 흐름 모음을 반환하는 함수입니다.
  • document.webkitGetNamedFlows().namedItem("article"): 특정 이름이 지정된 흐름에 대한 참조를 반환하는 함수입니다. 이 인수는 flow-intofrom-from CSS 속성의 값으로 지정된 이름에 해당합니다. 위의 코드 스니펫에 지정된 이름이 지정된 흐름의 참조를 가져오려면 'article' 문자열을 전달합니다.
  • WebKitNamedFlow: 다음과 같은 속성과 함수가 있는 이름이 지정된 플로의 객체 표현입니다.
    • firstEmptyRegionIndex: 이름이 지정된 흐름과 연결된 첫 번째 빈 영역의 색인을 가리키는 정수 값입니다. 지역 모음을 가져오는 방법은 아래 getRegions()를 참고하세요.
    • name: 흐름의 이름이 포함된 문자열 값입니다.
    • overset: 다음과 같은 부울 속성입니다.
      • 이름이 지정된 흐름의 콘텐츠가 연결된 지역에 적합한 경우 false
      • true: 콘텐츠가 표시되지 않고 더 많은 영역이 필요하여 모든 콘텐츠를 포함할 수 없는 경우
    • getContent(): 이름이 지정된 흐름으로 전달되는 노드 참조가 포함된 컬렉션을 반환하는 함수입니다.
    • getRegions(): 이름이 지정된 흐름의 콘텐츠를 보유하는 영역에 대한 참조가 포함된 컬렉션을 반환하는 함수입니다.
    • getRegionsByContentNode(node): 지정된 노드가 포함된 영역의 참조를 반환하는 함수입니다. 이는 이름이 지정된 앵커와 같은 항목이 포함된 영역을 찾는 데 특히 유용합니다.
  • webkitregionoversetchange 이벤트. 이 이벤트는 어떠한 이유로든 (콘텐츠가 추가 또는 삭제되거나, 글꼴 크기가 변경되거나, 영역의 모양이 변경되는 등) 연결된 콘텐츠의 레이아웃이 변경될 때마다 WebkitNamedFlow에서 트리거되며 영역의 webkitRegionOverset 속성이 변경됩니다. 이 이벤트는 대략적인 레이아웃 변경사항을 수신 대기할 때 유용합니다. 중요한 일이 발생하여 레이아웃에 문제가 있을 수 있음을 나타냅니다(예: 더 많은 지역이 필요하거나 일부 지역이 비어 있을 수 있음).
  • webkitregionfragmentchange 이벤트. 이 수정사항이 적용될 때는 구현되지 않았습니다. 이 이벤트는 webkitregionoversetchange와 마찬가지로 연결된 콘텐츠의 레이아웃이 어떤 이유로든 변경될 때마다 WebkitNamedFlow에서 트리거되지만 webkitRegionOverset 속성의 변경사항과는 관계없이 트리거됩니다. 이 이벤트는 이름이 지정된 흐름의 전체 레이아웃에 반드시 영향을 주지 않는 세밀한 레이아웃 변경사항을 리슨하는 데 유용합니다. 예를 들어 콘텐츠가 한 영역에서 다른 영역으로 이동하지만 전체 콘텐츠가 여전히 모든 영역에 들어맞는 경우를 들 수 있습니다.
  • Element.webkitRegionOverset: 요소에 flow-from CSS 속성이 할당되면 요소가 영역이 됩니다. 이러한 요소에는 webkitRegionOverset 속성이 있으며, 이 속성은 이름이 지정된 흐름의 일부인 경우 흐름의 콘텐츠가 영역을 벗어나는지 여부를 나타냅니다. webkitRegionOverset의 가능한 값은 다음과 같습니다.
    • 리전에서 보관할 수 있는 콘텐츠보다 많은 경우 '오버플로'
    • 콘텐츠가 영역 끝 전에 중지되는 경우 'fit'
    • 콘텐츠가 지역에 도달하지 않은 경우 '비어 있음'

CSSOM의 주요 용도 중 하나는 webkitregionoversetchange 이벤트를 수신 대기하고 다양한 양의 텍스트를 수용하기 위해 영역을 동적으로 추가하거나 삭제하는 것입니다. 예를 들어 형식이 지정될 텍스트의 양을 예측할 수 없는 경우 (사용자가 생성했을 수 있음), 브라우저 창의 크기가 조절되거나 글꼴 크기가 변경되는 경우 흐름의 변경사항을 수용하기 위해 영역을 추가하거나 삭제해야 할 수 있습니다. 또한 콘텐츠를 페이지로 구성하려면 DOM과 리전을 동적으로 수정하는 메커니즘이 필요합니다.

다음 JavaScript 코드 스니펫은 CSSOM을 사용하여 필요에 따라 영역을 동적으로 추가하는 방법을 보여줍니다. 단순성을 위해 이 예에서는 영역 삭제 또는 영역의 크기 및 위치 정의는 처리하지 않습니다. 이 예는 데모 목적으로만 제공됩니다.

var flow = document.webkitGetNamedFlows().namedItem("article")
flow.addEventListener("webkitregionoversetchange", onLayoutUpdate);

function onLayoutUpdate(event) {
    var flow = event.target;
    
    // The content does not fit
    if (flow.overset === true) {
    addRegion();
    } else {
    regionLayoutComplete();
    }
}

function addRegion() {
    var region = document.createElement("div");
    region.style = "flow-from: article";
    document.body.appendChild(region);
}

function regionLayoutComplete() {
    // Finish up your layout.
}

CSS Regions 샘플 페이지에서 더 많은 데모를 확인할 수 있습니다.

CSS 페이지 템플릿

CSSOM을 활용하는 것이 페이징 및 반응형 레이아웃과 같은 항목을 구현하는 가장 강력하고 유연한 방법일 수 있지만, Adobe는 오랫동안 텍스트 및 데스크톱 출판 도구를 사용해 왔기 때문에 디자이너와 개발자도 상대적으로 일반적인 페이징 기능을 더 쉽게 얻을 수 있는 방법을 원한다는 것을 알고 있습니다. 따라서 페이징 동작을 완전히 선언적으로 정의할 수 있는 CSS 페이지 템플릿이라는 제안서를 준비하고 있습니다.

CSS 페이지 템플릿의 일반적인 사용 사례를 살펴보겠습니다. 아래 코드 스니펫은 CSS를 사용하여 'article-flow' 및 'timeline-flow'라는 두 개의 이름이 지정된 흐름을 만드는 방법을 보여줍니다. 또한 두 개의 흐름이 포함될 'combined-articles'라는 세 번째 선택기를 정의합니다. overflow-style 속성을 'combined-articles' 선택기에 간단히 포함하면 콘텐츠가 x축을 따라 또는 가로로 자동 페이지로 나뉘어야 함을 나타냅니다.

<style>
    #article {
    { % mixin flow-into: article-flow; % }
    }

    #timeline {
    { % mixin flow-into: timeline-flow; % }
    }

    #combined-articles {
    overflow-style: paged-x;
    }
</style>

이제 흐름이 정의되고 원하는 오버플로 동작이 지정되었으므로 페이지 템플릿 자체를 만들 수 있습니다.

@template {
    @slot left {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }

    @slot time {
    width: 25%;
    float: left;
    { % mixin flow-from: timeline-flow; % }
    }

    @slot right {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }
}

페이지 템플릿은 새 'at' 문법을 사용하여 정의됩니다. 위의 코드 스니펫에서는 각각 열에 해당하는 세 개의 슬롯을 정의합니다. 'article-flow'의 텍스트는 왼쪽과 오른쪽 열을 통해 흐르고 'timeline-flow'의 텍스트는 가운데 열에 채워집니다. 결과는 다음과 같이 표시될 수 있습니다.

페이지 템플릿 예
페이지 템플릿 예

기사 텍스트(왼쪽 및 오른쪽 열의 텍스트)는 영어이고 가운데의 타임라인은 독일어입니다. 또한 JavaScript 코드 없이 문서 페이지를 가로로 스크롤할 수 있습니다. 모든 작업은 CSS에서 완전히 선언적으로 이루어졌습니다.

CSS 페이지 템플릿은 아직 제안사항이지만 지금 바로 실험해 볼 수 있도록 JavaScript '시임' (다른 이름: 폴리필)을 사용하는 프로토타입이 있습니다.

CSS 영역에 관한 일반적인 내용은 html.adobe.com의 CSS 영역 페이지를 참고하세요.

CSS 제외

실제 잡지와 같은 레이아웃을 구현하려면 영역을 통해 텍스트를 흐르게 하는 것만으로는 충분하지 않습니다. 고품질의 시각적으로 흥미로운 데스크톱 출판의 핵심 요소는 불규칙한 그래픽과 도형 주위 또는 내부로 텍스트를 흐르게 하는 기능입니다. CSS 제외는 이러한 수준의 프로덕션 품질을 웹에 제공합니다.

아래 스크린샷은 CSS 제외 프로토타입의 스크린샷으로, 큰 암석 형상의 윤곽선과 일치하는 경로를 따라 동적으로 흐르는 텍스트를 보여줍니다.

CSS 제외가 적용된 예
작동 중인 CSS 제외의 예

다음 스크린샷은 그 반대의 예를 보여줍니다. 불규칙한 모양의 다각형 내부로 텍스트가 흐르고 있습니다.

불규칙한 모양의 다각형으로 흐르는 텍스트
불규칙한 모양의 다각형으로 흐르는 텍스트

임의 도형의 주변이나 내부에서 텍스트를 흐르게 하려면 먼저 필요한 알고리즘을 개발하고 최적화해야 합니다. Adobe는 현재 WebKit에 직접 기여할 구현을 연구하고 있습니다. 이러한 알고리즘이 최적화되면 나머지 CSS 제외가 빌드되는 기반이 됩니다.

CSS 제외에 관한 자세한 내용은 html.adobe.com의 CSS 제외 페이지를 참고하고, CSS 제외의 기본 기술에 관한 Adobe의 작업을 자세히 알아보려면 한스 뮬러의 블로그 게시물인 가로 상자: CSS 제외의 다각형 교차를 참고하세요.

CSS 영역 및 CSS 제외의 현재 상태

CSS 영역 및 CSS 제외를 처음으로 공개적으로 언급한 것은 Google I/O 2011의 Adobe 개발자 포드에서였습니다. 당시에는 자체 맞춤 프로토타입 브라우저에서 데모를 보여주고 있었습니다. 반응은 매우 열광적이었지만, 내가 보여주는 기능 중 아직 주요 브라우저에서 사용할 수 있는 기능이 없다는 것을 관람객들이 알게 되자 실망감이 역력했습니다.

올해 (2012년) Google I/O에 다시 참석했습니다. 이번에는 동료인 빈센트 하디와 Google의 알렉스 다닐로와 함께 발표자로 참석했습니다 (여기에서 프레젠테이션을 시청하실 수 있습니다). 불과 1년 후, CSS 영역 사양의 약 80% 가 WebKit에 구현되었으며 이미 최신 버전의 Google Chrome에 포함되어 있습니다 (현재 CSS 영역은 chrome://flags를 통해 사용 설정해야 함). CSS 영역에 대한 예비 지원은 Android용 Chrome에도 제공됩니다.

Android용 Chrome의 지역
Android용 Chrome의 지역

또한 CSS 영역과 CSS 제외는 모두 Internet Explorer 10 미리보기에서 구현되었으며 현재 Mozilla의 Firefox 2012 로드맵에 있습니다. Safari의 다음 주요 버전은 CSS Regions 사양의 대부분을 지원해야 하며 후속 업데이트에는 나머지가 포함되어야 합니다.

다음은 2011년 4월 W3C에 제안한 이후 CSS 영역 및 CSS 제외와 관련하여 이루어진 진행 상황을 자세히 보여주는 타임라인입니다.

지역 및 제외 진행률
지역 및 제외 진행 상황

결론

Adobe는 InDesign과 같은 도구를 통해 텍스트, 글꼴, 데스크톱 출판에 대한 풍부한 경험을 보유하고 있습니다. 웹은 이미 매우 강력한 텍스트 플랫폼이지만, Google은 Google의 지식과 경험을 바탕으로 텍스트 표현을 한층 더 발전시키고자 합니다. CSS 영역 및 CSS 제외를 사용하면 콘텐츠가 의미론적으로 구조화된 상태로 유지되는 동시에 실제 잡지와 같은 레이아웃을 지원할 수 있으며 궁극적으로 훨씬 더 표현력이 뛰어난 웹을 만들 수 있습니다.