◆ CSS파싱
■ 특징
- 문맥 자유 문법이다. = 규칙이 딱 정해져 있다. = 파서(상향식 또는 하향식)를 통해서 파싱이 가능하다.
- 웹킷은 CSS 문법 파일로부터 자동으로 파서 생성을 위해 플렉스와 바이슨 파서 생성기를 활용한다.
- 파이어 폭스는 직접 작성한 하향식 파서를 사용한다.
- CSS 규칙 객체는 선택자와 선언 객체 그리고 CSS 문법과 일치하는 다른 객체를 포함한다.
■ 스크립트와 스타일 시트 진행 순서
- 스크립트 : 이전 글 브라우저의 동작 원리에서 설명한 것과 같이, <script> 태그를 만나면 문서의 파싱은 중단된다. 네트워크로부터 자원을 가져오는 단계 또한 실시간으로 처리(동기)되고 자원 받을 때까지 파싱은 중단된다. 비동기로 처리하기 위해서는 async, defer옵션을 적절히 사용한다.
- 예측 파싱 : 웹킷와 파이어 폭스는 예측 파싱과 같은 최적화를 지원한다. 스크립트 실행하는 동안 다른 스레드는 네트워크로부터 다른 자원을 찾아 내려받고 문서의 나머지 부분을 파싱한다. 자원 병렬로 연결하여 받을 수 있으며 속도 개선을 할 수 있다.예측 파서는 DOM 트리를 수정하지 않고 메인 파서의 일로 넘긴다. 예측 파서는 외부 스크립트, 스타일 시트, 이미지와 같이 참조된 외부 자원을 파싱할 뿐이다.
- 스타일 시트 : 이상적으로는 DOM 트리를 변경하지 않기 때문에 문서 파싱을 기다리거나 중단할 이유가 없다. 하지만, 스크립트가 문서 파싱하는 동안 스타일 정보를 요청하는 경우는 문제가 된다. 파이어폭스는 로딩 중이거나 파싱 중인 스타일 시트가 있는 경우 모든 스크립트 실행 중단. 웹킷은 로드되지 않은 스타일 시트 가운데 문제 될만한 속성이 있을 때에만 스크립트 중단.
■ 렌더 트리 구축
DOM트리가 구축되는 동안 브라우저는 렌더 트리를 구축한다.
파이어폭스 : 형상(frames) = 웹킷 : 렌더러(Renderer) or 렌더 객체(Render Object)
렌더러는 자신과 자식 요소를 어떻게 배치하고 그려야하는지에 대한 정보를 담고 있다.
- 웹킷 렌더러의 RenderObject 클래스
class RenderObject { virtual
void layout(); virtual
void paint(PaintInfo); virtual
void rect repaintRect();
Node * node; //the DOM node
RenderStyle * style; // the computed style
RenderLayer * containgLayer; //the containing z-index layer
}
렌더러는 너비, 높이, 위치 같은 기하학적(시각적) 정보를 포함한다.
■ DOM 트리와 렌더 트리의 관계(Renderer= RenderObject)
Renderer는 DOM 요소에 대응되지만, 1:1로 대응되지는 않는다. 예로, head요소와 같은 비 시각적 DOM 요소는 렌더 트리에 추가되지 않는다. 또한, display 속성이 'none'이어도 트리에 나타나지 않는다.(visibility가 hidden인 것은 나타난다.)
여러 시각 객체에 대응하는 DOM도 있다. 예로. 'select' : "표시영역, 드롭다운 목록, 버튼" 표시를 위한 3개 렌더러가 있다.또한, 한 줄에 표시할 수 없는 문자가 여러 줄로 바뀔 때, 새 줄은 별도의 렌더러로 추가된다.
어떤 렌더 객체는 DOM 노드에 대응하지만 트리의 동일한 위치에 있지 않다. float 처리된 요소 또는 position 속성 값이 absolute로 처리된 요소는 흐름에서 벗어나 트리의 다른 곳에 배치된 상태로 형상이 그려진다.
■ 트리 구축 과정(DOM트리 + CSSOM(=스타일))
- 파이어폭스 : 프레젠테이션은 DOM 업데이트를 위한 리스너로 등록된다. 프레젠테이션은 형상 만들기를 FrameConstructor에 위임하고 FrameConstructor는 스타일(스타일 계산 참고)을 결정하고 형상을 만든다.
- 웹킷 : "어태치먼트(attachment)" 라고 부른다. 모든 DOM 노드에는 "attach" 메서드가 있다. 어태치먼트는 동기적인데 DOM 트리에 노드를 추가하면 새 노드의 "attach" 메서드를 호출한다.
html 태그와 body 태그를 처리함으로써 렌더 트리 루트를 구성한다. 루트 렌더 객체는 CSS 명세에서 포함 블록(다른 모든 블록을 포함하는 최상위 블록)이라고 부르는 것과 일치한다. 파이어폭스는 ViewPortFrame이라 부르고 웹킷은 RenderView라고 부른다. document 가리키는 렌더 객체다. 트리의 나머지 부분은 DOM 노드를 추가함으로써 구축된다.
■ 스타일 계산
렌더트리를 구축하기 위해서는 각 렌더 객체에 시각적 속성(위치, 크기 등) 에 대한 계산이 필요하다.이것은 각 요소의 스타일 속성을 계산함으로써 처리된다.
▽ 스타일 계산 이슈
1. 스타일 데이터 구성이 매우 광범위하고, 수 많은 스타일 속성을 수용하면서 메모리 문제 야기할 수 있음.
2. 각 요소에 할당된 규칙을 찾는 것은 성능 문제를 야기할 수 있다.
3. 규칙 적용은 계층 구조를 파악해야하는 복잡한 다단계 규칙을 수반한다.
▲ 스타일 정보 공유
웹킷 노드는 스타일 객체(RenderStyle)를 참조하며, 이 객체는 일정 조건 아래 공유할 수 있다. 노드가 형제이거나 사촌일 때 공유하며 다음 조건일 때 공유할 수 있다.
- 동일한 마우스 반응 상태를 가진 요소여야 한다. 예를 들어 한 요소가 :hover 상태가 될 수 없는데 다른 요소는 :hover가 될 수 있다면 동일한 마우스 상태가 아니다.
- 아이디가 없는 요소.
- 태그 이름이 일치해야 한다.
- 클래스 속성이 일치해야 한다.
- 지정된 속성이 일치해야 한다.
- 링크(link) 상태가 일치해야 한다.
- 초점(focus) 상태가 일치해야 한다.
- 문서 전체에서 속성 선택자의 영향을 받는 요소가 없어야 한다. 여기서 영향이라 함은 속성 선택자를 사용한 경우를 말한다(속성 선택자 예 input[type=text]{...})
- 요소에 인라인 스타일 속성이 없어야 한다(인라인 스타일 예 <p style="...">...</p>).
- 문서 전체에서 형제 선택자를 사용하지 않아야 한다. 웹 코어는 형제 선택자를 만나면 전역 스위치를 열고 전체 문서의 스타일 공유를 중단한다. 형제 선택자는 + 선택자와 :first-child 그리고 :last-child를 포함한다.
선 또는 색상과 같은 종류의 스타일 정보를 포함한다. 구조체 속성 중 재설정(reset)하지 않은 것들은 부모로부터 상속된다.
하위 노드에 구조체를 위한 속성 선언이 없다면 저장된 상위 노드의 구조체 속성을 그대로 받아서 사용한다.
스타일 시트 파싱 후 CSS 규칙은 선택자에 따라 여러 해시 맵 중 하나에 추가 된다.
아이디, 클래스명, 태그명을 사용한 맵이 있고, 이런 분류에 맞지 않는 것을 위한 일반적인 맵이 있다.
p.error {color:red} : 클래스 맵
#messageDiv {height:50px} : 아이디 맵
div {margin:5px} : 태그 맵
■ 다단계(cascade) 순서에 따라 규칙 적용하기
스타일 속성 선언은 하나의 파일에서 여러번 나타날 수 있다.
여기서 어떤 스타일을 적용할 것인가? = 아래의 우선순위에 따라.
1. 브라우저 선언(browser declarations)
2. 사용자 일반 선언(user normal declarations)
3. 저작자 일반 선언(author normal declarations)
4. 저작자 중요 선언(author important declarations)
5. 사용자 중요 선언(user important declarations)
브라우저 선언의 중요도가 가장 낮으며 사용자 중요 선언의 중요도가 가장 높다.
특정 요소에 어떤 CSS 속성을 적용할 것인가는 특정성(Specificity)라는 것에 의해 결정된다. 좀 더 구체적인 속성이 적용된다는 의미! p{...} 보다는 .clas{...}가 더 구체적이므로, 클래스 속성이 적용됨. (Specificity Calculator)
InLine, 아이디, 클래스, 요소
Highest lowest
-------------------------------->
(특정성에 대한 참고 : Speciticity : https://www.youtube.com/watch?v=B0uYbAe4YY8)
or important keyword(= !important) : 좋은 습관은 아니니, 되도록이면 쓰지 말자. 최후의 수단일 뿐이다.
'브라우저' 카테고리의 다른 글
[브라우저] 다중 프로세스 아키텍처(feat. Chrome) (1) | 2023.03.01 |
---|---|
[브라우저] 배치(Layout), Paint(feat 더티비트) (0) | 2023.02.27 |
[브라우저] HTML 파서 - 마크업 → 파싱트리(문맥 자유 문법x) (0) | 2023.02.26 |
[브라우저] 파싱이란?(Parsing이란?) - 파싱의 과정(어휘 분석, 구문 분석) (0) | 2023.02.26 |
[브라우저] 브라우저의 동작 원리 (2) | 2023.02.26 |
댓글