Frontend 에 익숙하지않은 많은 개발자들이 과제 이상의 어느정도 규모있는 Frontend 를 작업하게 되면 HTML 과 CSS 의 구조에 대해 놀라는 경향이 있다.

 

HTML 과 CSS 는 생각보다 정교한 구조를 이루고 있고, 초보 수준 이상의 Frontend 실력을 갖기 위해서는 필수적으로 구조에 대해 이해하고 어떻게 브라우저가 웹(Web)을 스타일링하는 지 알아야 한다.

 

이해해야할 잘 갖춰진 Frontend 의 특징 중 하나로, "HTML 문서의 모든 프로퍼티(properties) 들은 상속가능하다" 는 점이 있다.

 

계층적으로 구조화된 DOM 모델에서 한 Element 는 Parent Element 의 속성을 지니며, 모든 element 들의 root parent 는 <html> 이 된다.

HTML 태그의 DOM 모델들 간 상속은 다른 포스팅에서 다루도록 하고, 본 포스팅에서는 CSS 의 상속에 대해 다루기로 한다.

 

복잡한 종류의 UI 를 구조할 때, 비슷한 CSS 스타일링을 중복해서 사용하게 되는 경우가 많이 있다.

가령, 웹페이지 전체의 UI 는 어느정도 일관성이 있어야 하기 때문에, 검색을 위한 검색바(Bar)와 검색 추천을 위한 표시바(Bar) 가 있는데 이 둘의 스타일을 비슷하게 가져가되 하이라이트 컬러 정도만 바꾸고자 한다고 해보자.

 

이 때, 세세하게 작업된 모든 디자인 스타일을 복사해서 사용하는 것은 비효율적인 일이다.

 

이럴 때에는 다음과 같이 CSS 상속을 이용해 쉽게 해결할 수 있다.

 

위의 코드에서 bar-focus 라는 CSS 스타일은 bar 스타일을 차용하되 background-color 에 특징을 입힌다.

위의 마크업은 다음과 같은 페이지를 나타내게 된다.

 

색배합이 끔찍하지만, 스타일을 재활용할 수 있다는 점정도는 쉽게 알 수 있다.

 

쉽지않은가? 이런식으로 스타일의 재활용을 통해 노가다로 여겨질 수 있는 Frontend 의 디자인 코드를 확연하게 정리할 수 있다.

 

하지만 CSS 의 상속과 관련되어 알아야할 성질들은 조금 더 있다.

 

먼저 브라우저가 상속을 처리하는 순서이다.

브라우저는 CSS 상속을 Inline > Internal > External 순서로 처리한다.

 

여기서 Inline, Internal, External 은 CSS를 정의하는 방법에 대한 분류를 말하며, 다음과 같다.

 - Inline : 해당 태그 안에 style=”” 속성을 통해 정의

 - Internal : 해당 파일 안에 <css> </css> 태그를 작성하고 해당 Scope 내에 정의

 - External : 별도의 파일로 CSS 를 분리하고 해당 파일을 HTML 에서 import

 

즉, CSS를 적용할 때에 위의 순서를 유의해야 해당 스타일이 반영될 수 있다.

 

또 당신이 프론트엔드 개발자라면 주의해야할 사항으로 태그의 속성 관리 부분이 있다.

 

만약, CSS 가 적용된 태그의 속성이 "float" 을 가지고 있는 경우 해당 DOM 은 상속관계 및 레이아웃에 영향을 받지않는 붕-뜬 상태가 된다. 

해당 요소에 상속성을 적용시키기 위해서는 overflow 속성의 적용이 필요하다.

 




웹 페이지를 구성하는 DOM Element 노드들은 트리 모양의 계층 구조를 갖고 있으며 DOM Element 와 연결된 Javascript 내부 동작 역시 이 구조에 대한 로직이 고려되어 있다.


이벤트 버블링과 캡쳐링은 Javascript 에서 주로 사용되는 Event Delegation Pattern 을 이해하는 기본적인 개념이다.


- 이벤트 버블링(Event Bubbling) 


웹페이지 내의 한 엘리먼트에서 이벤트가 감지되었을 때, 해당 엘리먼트의 계층구조를 따라 올라가면서 Root Element 까지 이벤트가 전달되는 것을 Event Bubbling 이라 한다.


이해를 돕기 위해 다음 코드를 확인해보자.


<div class="col-sm-1" onclick="alert('c')">
<div onclick="alert('b')">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


위의 코드를 웹 페이지에서 확인해보면, HELLO 를 감싸고 있는 DOM 엘리먼트를 클릭하면 a - b - c 순서대로 3개의 Alert 창을 확인해볼 수 있다.


이처럼 이벤트 버블링(Bubbling)이란, 이벤트가 발생하는 가장 안쪽부터 바깥쪽, 하위 노드에서 상위노드로 이벤트가 전파(Propagation)되는 과정인 것이다.


하위 DOM Element 부터 전파되는 이벤트는 최종적으로 Document 객체까지 전달되며, 상위 Element 에서 이벤트 핸들러를 재정의해서 전파를 제어할 수 있다.


가령, 다음과 같은 코드에서 이벤트는 두번째 div 이상으로 전파되지 않는다.



<div class="col-sm-1" onclick="alert('c')">
<div onclick="event.stopPropagation()">
<div onclick="alert('a')">
HELLO
</div>
</div>
</div>


전파되지 않는 이유는 이벤트가 발생한 target Element 의 상위 Element 에서 onclick 메서드를 재구현하는데, event.stopPropagation() 함수를 이용해서 전파를 중단했기 때문이다.


이렇게 전파를 제어하는 것을 Stop Bubbling 이라고 한다.



- 이벤트 캡쳐링(Event Capturing)


이벤트 캡쳐링은 이벤트 버블링과 반대방향으로 이벤트가 전달된다.


다음 코드를 통해 이해해보자.


<div id="parent">
<div id="child">
HELLO
</div>
</div>
<script>
var parent = document.querySelector('#parent');
var child = document.querySelector('#child');
parent.addEventListener('click', function(){
alert("Parent clicked");
},true);
child.addEventListener('click', function(){
alert("Child clicked");
});
</script>


똑같이 계층 구조로 Element 들이 배치되어 있지만 이번에는 Parent 노드부터 이벤트가 전달된다.


이처럼 이벤트 캡쳐링(Event Capturing)이란, 상위노드부터 하위노드로 이벤트가 전달되는 형태를 말한다.


이 경우에 이벤트는 window 객체부터 차례로 아래 노드로 전파되며 addEventListener 의 3번째 인자로 capture 플래그를 두어 탐색 방향을 맞출 수 있다.


이벤트 캡쳐링의 경우 버블링보다는 덜 사용된다.



이벤트 버블링(Event Bubbling) 과 이벤트 캡쳐링(Event Capturing) 의 개념은 간단하지만, 이해하고 있지 않으면 은근히 프론트엔드 개발 시 삽질을 할 수 있는 부분이다.


잘 이해해두어 복잡한 UI 이벤트 처리 시에 헷갈리는 일이 없도록 하자.





본 포스팅에서는 현직 개발자에게도 생소하기 쉬운 쓰로틀링(Throttling)과 디바운싱(Debouncing) 테크닉에 대해 설명하고자 한다.


본래 Throttling 이란 주로 모바일 기기에서 많이 사용되는 용어로 성능을 위한 오버클럭(Overclock)이 디바이스에 무리를 주는 것을 방지하기 위해 고의로 성능을 낮추는 조절 방식을 말한다.


소프트웨어 적인 의미로도 Throttling 은 언급이 되곤 한다.


이 때에는 주로 트랜잭션을 처리하는 Middleware 나 네트워크 트래픽을 제어하는 ISP 에서 언급이 되며 UI 처리를 담당하는 프론트엔드(Frontend)에서도 사용된다.


프론트엔드(Frontend) 에서 쓰로틀링과 디바운싱은 어떤 경우에 사용될까?


가령 웹페이지를 구성하는데 해당 사이트는 다시 방문시 사용자가 읽던 포스트의 위치를 기억하고 그 페이지를 보여준다고 생각해보자.

페이지를 나눌 단위가 없으므로 스크롤 단위로 페이지 좌표를 서버에 기록하고자 한다면, 가장 단순한 방법은 Javascript 의 Scroll 이벤트를 이용해서 좌표를 저장하고 기록하는 방식이다.


이 경우 사용자의 스크롤링마다 이벤트를 발생시키면... 서버에도 클라이언트에도 매우 큰 부하가 발생되게 된다.

최악의 경우 페이지의 세로 좌표만큼 이벤트가 발생될 것이다.


예시는 최악의 구조와 최악의 경우를 가정한 것이지만, 중요한 점은 "이벤트의 오버클럭(Overclock)이 소프트웨어에 손상을 가져온다는 점" 이다.


이런 경우의 처리를 위해서도 쓰로틀링과 디바운싱 이라는 개념이 똑같이 적용되어 사용된다.


먼저 쓰로틀링(Throttling) 테크닉을 알아보자

쓰로틀링(Throttling) 을 이용하면 발생되는 이벤트 중간에 Delay 를 포함시킨다.


즉, Delay 이내로 연속적으로 발생된 이벤트에 대해서는 무시한다.


다음 코드를 보면 쉽게 이해될 것이다.




이런 종류의 테크닉은 특히 애니메이션을 구현하는 코드 등에서 많이 확인해볼 수 있다.


다음으로 디바운싱(Debouncing) 역시 쓰로틀링과 비슷하게 소프트웨어적인 오버클럭을 조절하는 테크닉이다.


하지만 쓰로틀링(Throttling) 과는 조금 다른 방법을 사용하는데, 쓰로틀링이 필터링(Filtering)의 방법을 사용한다면,


디바운싱(Debouncing)은 그루핑(Grouping)의 방법을 사용한다.


즉, 이벤트 핸들러가 주기적으로 여러 개의 발생한 이벤트를 하나로 묶어서 처리하는 방식이다.


이때, 먼저 발생한 이벤트가 처리를 대기하며, 대기하는 도중 새 이벤트가 발생하면 이전 이벤트의 대기를 취소(Cancel)하고, 해당 이벤트를 기준으로 다시 처리(Process)를 대기한다.

이렇게 특정 시간 동안 처리(Process)는 대기하게 되며 결과적으로는 일정한 시간 동안 연속적으로 발생한 이벤트는 마지막으로 발생한 이벤트 기준으로 처리된다.


여기서 Leading Edge 라는 디바운싱 테크닉을 이용하면 이 처리를 앞의 이벤트 기준으로 변경할 수 있으며 이 경우엔 쓰로틀링과 유사하게 동작하게 된다.

(나중에 발생하는 이벤트를 무시하는 방식은 같지만 첫 이벤트 처리가 딜레이 된다.)


다음 코드를 참조해보자.



쓰로틀링과 디바운싱은 생소하지만 알고보면 많은 이벤트 처리에 사용되고 있는 테크닉이다.

특히 UI를 처리하는 부분은 입력의 오버클럭을 감당하기 위해 없어서는 안되며 많은 라이브러리나 프레임워크에 이미 내장된 경우가 많으므로 잘 숙지해두는 것이 좋다.



좀 더 자세한 예시는 다음 링크가 가장 잘 되어 있는 듯 하다.

 : https://css-tricks.com/debouncing-throttling-explained-examples/


추가로 본 포스팅에선 이해를 돕기 위해 간단한 파이썬 코드로 예시를 작성했지만 실제 Javascript 에서 사용되는 코드의 예시는 다음을 참조해보자.

 : https://codeburst.io/throttling-and-debouncing-in-javascript-646d076d0a44


+ Recent posts