Houdini - CSS 이해하기

CSS가 처리하는 작업량에 대해 생각해 보셨나요? 속성 하나를 변경하자 갑자기 전체 웹사이트가 다른 레이아웃으로 표시됩니다. 일종의 마법입니다. 지금까지 웹 개발자 커뮤니티인 우리는 그 마법을 목격하고 관찰할 수밖에 없었습니다. 우리만의 마법을 구상해보면 어떨까요? 마술사가 되려면 어떻게 해야 할까요?

Houdini 들어오세요!

Houdini 태스크 포스는 Mozilla, Apple, Opera, Microsoft, HP, Intel, Google의 엔지니어로 구성되어 CSS 엔진의 특정 부분을 웹 개발자에게 노출합니다. 태스크포스는 W3C에서 실제 웹 표준이 되도록 하는 것을 목표로 초안 컬렉션을 작업하고 있습니다. 몇 가지 상위 목표를 설정하고 이를 사양 초안으로 바꾸어 지원하는 하위 수준의 사양 초안을 만들었습니다.

이러한 초안 컬렉션은 일반적으로 'Houdini'를 할 때 의미가 있습니다. 이 문서 작성 시점을 기준으로 초안 목록은 미완성 상태이며 일부 초안은 자리표시자에 불과합니다.

사양

Worklet (spec)

Worklet 자체는 그다지 유용하지 않습니다. 후반부의 많은 초안을 가능하게 하기 위해 도입된 개념입니다 'worklet'을 읽었을 때 웹 작업자를 떠올렸다면 틀린 것이 아닙니다. 이 둘은 개념적으로 많이 겹칩니다. 그렇다면 이미 작업자가 있는데 왜 새로운 것일까요?

Houdini의 목표는 웹 개발자가 자체 코드를 CSS 엔진과 주변 시스템에 연결할 수 있도록 새로운 API를 노출하는 것입니다. 이러한 코드 프래그먼트 중 일부가 every. 단일. frame을 실행해야 한다고 가정하는 것은 비현실적일 수 있습니다. 그 중 일부는 정의에 의해 그렇죠. Web Worker 사양 인용:

이는 웹 작업자가 Houdini가 계획하고 있는 작업을 실행할 수 없음을 의미합니다. 따라서 워크릿이 발명되었습니다. Worklet은 ES2015 클래스를 사용하여 메서드 모음을 정의합니다. 서명은 Worklet 유형에 따라 사전 정의됩니다. 가볍고 수명이 짧습니다.

CSS Paint API (spec)

Paint API는 Chrome 65에서 기본적으로 사용 설정되어 있습니다. 자세한 소개를 읽어보세요.

컴포지터 Worklet

여기에 설명된 API는 더 이상 사용되지 않습니다. 컴포지터 Worklet이 다시 설계되어 이제 'Animation Worklet'으로 제안됩니다. 현재 API 반복에 대해 자세히 알아보세요.

컴포지터 Worklet 사양은 WICG로 이전되어 계속 반복될 예정이지만, 가장 기대되는 사양은 바로 이 사양입니다. 일부 작업은 CSS 엔진에 의해 컴퓨터의 그래픽 카드로 아웃소싱되지만 일반적으로 그래픽 카드와 기기에 따라 달라집니다.

브라우저는 일반적으로 DOM 트리를 취하고 특정 기준에 따라 일부 브랜치와 하위 트리에 자체 레이어를 제공하기로 결정합니다. 이러한 하위 트리는 스스로 페인트를 사용합니다 (나중에 페인트 Worklet을 사용할 수 있음). 마지막 단계로, 이제 페인트된 이러한 모든 개별 레이어는 z-색인, 3D 변환 등을 고려하여 쌓이고 서로 위에 배치됩니다. 이를 통해 화면에 표시되는 최종 이미지가 생성됩니다. 이 프로세스를 합성이라고 하며 컴포지터에 의해 실행됩니다.

합성 프로세스의 장점은 페이지를 약간 스크롤할 때 모든 요소를 다시 그릴 필요가 없다는 것입니다. 대신 이전 프레임의 레이어를 재사용하고 업데이트된 스크롤 위치로 컴포지터를 다시 실행하면 됩니다. 따라서 작업 속도가 빨라집니다. 이를 통해 60fps에 도달할 수 있습니다.

컴포지터 Worklet.

이름에서 알 수 있듯이 컴포지터 워크렛을 사용하면 컴포지터에 연결하여 이미 페인트된 요소의 레이어가 다른 레이어 위에 배치되고 레이어되는 방식에 영향을 줄 수 있습니다.

좀 더 구체적으로 살펴보려면 특정 DOM 노드의 합성 프로세스에 연결하고 스크롤 위치, transform 또는 opacity와 같은 특정 속성에 대한 액세스를 요청할 수 있음을 브라우저에 알리면 됩니다. 이렇게 하면 이 요소가 자체 레이어에 강제 적용되어 각 프레임에서 코드가 호출됩니다. 레이어 변환을 조작하여 레이어를 이동하고 속성 (예: opacity)을 변경하면 60fps의 빠른 속도로 화려한 작업을 할 수 있습니다.

다음은 컴포지터 Worklet을 사용하여 시차 스크롤을 전체적으로 구현한 것입니다.

// main.js
window.compositorWorklet.import('worklet.js')
    .then(function() {
    var animator = new CompositorAnimator('parallax');
    animator.postMessage([
        new CompositorProxy($('.scroller'), ['scrollTop']),
        new CompositorProxy($('.parallax'), ['transform']),
    ]);
    });

// worklet.js
registerCompositorAnimator('parallax', class {
    tick(timestamp) {
    var t = self.parallax.transform;
    t.m42 = -0.1 * self.scroller.scrollTop;
    self.parallax.transform = t;
    }

    onmessage(e) {
    self.scroller = e.data[0];
    self.parallax = e.data[1];
    };
});

로버트 플랙이 컴포지터 워크렛의 polyfill을 작성했으므로 이를 시도해 볼 수 있습니다. 분명히 성능에 훨씬 큰 영향을 미칩니다.

레이아웃 Worklet (spec)

첫 번째 실제 사양 초안이 제안되었습니다. 한동안 구현할 수 있습니다.

다시 말씀드리지만, 사양은 사실상 비어 있지만 개념은 흥미로울 수 있습니다. 바로 레이아웃을 직접 작성하는 것입니다. 레이아웃 Worklet에서는 display: layout('myLayout')를 실행하고 자바스크립트를 실행하여 노드의 하위 요소를 노드 상자에 정렬할 수 있어야 합니다.

물론, CSS의 flex-box 레이아웃에서 전체 JavaScript 구현을 실행하는 것은 동등한 네이티브 구현을 실행하는 것보다 느리지만, 모서리를 잘라서 성능을 높일 수 있는 시나리오를 상상하기는 쉽습니다. Windows 10 또는 석조물 스타일 레이아웃과 같이 타일만으로 구성된 웹사이트를 가정해 보겠습니다. 절대 위치 및 고정 위치는 사용되지 않으며, z-index도 사용되지 않으며, 요소가 겹치거나 테두리 또는 오버플로가 발생하지 않습니다. 재레이아웃 시 이러한 모든 검사를 건너뛸 수 있으면 성능을 높일 수 있습니다.

registerLayout('random-layout', class {
    static get inputProperties() {
        return [];
    }
    static get childrenInputProperties() {
        return [];
    }
    layout(children, constraintSpace, styleMap) {
        const width = constraintSpace.width;
        const height = constraintSpace.height;
        for (let child of children) {
            const x = Math.random()*width;
            const y = Math.random()*height;
            const constraintSubSpace = new ConstraintSpace();
            constraintSubSpace.width = width-x;
            constraintSubSpace.height = height-y;
            const childFragment = child.doLayout(constraintSubSpace);
            childFragment.x = x;
            childFragment.y = y;
        }

        return {
            minContent: 0,
            maxContent: 0,
            width: width,
            height: height,
            fragments: [],
            unPositionedChildren: [],
            breakToken: null
        };
    }
});

유형이 지정된 CSSOM (spec)

유형이 지정된 CSSOM (CSS 객체 모델 또는 Cascading Style Sheets 객체 모델)은 우리 모두가 경험하고 방금 배웠던 문제를 해결합니다. JavaScript를 사용하여 설명해 보겠습니다.

    $('#someDiv').style.height = getRandomInt() + 'px';

여기서는 숫자를 문자열로 변환하여 단위를 추가합니다. 그러면 브라우저에서 해당 문자열을 파싱하고 CSS 엔진에서 사용할 수 있도록 다시 숫자로 변환합니다. 이는 자바스크립트로 변환을 조작하면 더욱 심해집니다. 더 이상 필요 없습니다. CSS에 직접 입력을 해야 합니다.

이 초안은 완성도가 더 높은 초안 중 하나이며 polyfill이 이미 작업 중입니다. (면책 조항: 폴리필을 사용하면 컴퓨팅 오버헤드가 훨씬 더 커집니다. 요점은 API가 얼마나 편리한지 보여주는 것입니다.)

문자열 대신 요소의 StylePropertyMap를 작업하게 되며, 이 경우 각 CSS 속성에는 자체 키와 해당 값 유형이 있습니다. width와 같은 속성의 값 유형은 LengthValue입니다. LengthValueem, rem, px, percent 등의 모든 CSS 단위의 사전입니다. height: calc(5px + 5%)를 설정하면 LengthValue{px: 5, percent: 5}이 발생합니다. box-sizing와 같은 일부 속성은 특정 키워드만 허용하므로 KeywordValue 값 유형을 포함합니다. 그런 다음 런타임 시 이러한 속성의 유효성을 검사할 수 있습니다.

<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
    [new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
    // => {em: 5, percent: 50}

속성 및 값

(spec)

CSS 맞춤 속성 (또는 비공식 별칭인 'CSS 변수')을 알고 계신가요? 이것은 유형이 있습니다. 지금까지는 변수는 문자열 값만 가질 수 있었으며 간단한 찾기 및 바꾸기 방식을 사용했습니다. 이 초안을 사용하면 변수의 유형만 지정할 뿐만 아니라 기본값을 정의하고 JavaScript API를 사용하여 상속 동작에 영향을 줄 수 있습니다. 기술적으로 이를 통해 맞춤 속성에 표준 CSS 전환 및 애니메이션도 적용할 수 있으며, 이 또한 고려 중입니다.

["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
    name: name,
    syntax: "<number>",
    inherits: false,
    initialValue: "1"
    });
});

글꼴 측정항목

글꼴 측정항목은 말 그대로입니다. Z 크기에서 글꼴 Y로 문자열 X를 렌더링할 때 경계 상자 (또는 경계 상자)는 무엇인가요? ruby 주석을 사용하면 어떻게 되나요? 많은 분들의 요청이 있었던 만큼 Houdini는 드디어 이 소망을 이루시게 되었습니다.

잠시만 기다려 주세요.

Houdini의 초안 목록에는 더 많은 사양이 있지만, 이러한 초안의 미래는 불확실하고 아이디어를 위한 자리표시자가 아닙니다. 예를 들어 맞춤 오버플로 동작, CSS 구문 확장 API, 네이티브 스크롤 동작 확장, 이와 유사하게 야심 찬 것들로 이전에는 불가능했던 일들을 웹 플랫폼에서 실현할 수 있습니다.

데모

데모용 코드(polyfill을 사용한 실시간 데모)를 오픈소스로 제공했습니다.