이야기에 앞서
엘리멘터(Elementor)의 위젯은 페이지에 다양한 기능을 애드온 형태로 제공하는 엘리멘터의 핵심 모듈 시스템입니다. 단순히 글 제목 하나 적는데에도 위젯이 필요하기 때문에 위젯은 엘리멘터의 처음과 끝 그 자체라 할 수 있습니다. 그리고 이러한 위젯들을 하나의 컨테이너로 묶어 페이지 여러 곳에서 재사용할 수 있는 템플릿으로 저장할 수도 있습니다.
위젯과 템플릿의 실행 성능을 개선하고 재사용성을 높이려면 HTML Widget
과 Custom CSS
필드, 그리고 전역 위젯(Global Widget
)의 작동 원리를 이해하는 것이 중요합니다. 이를 적절히 혼합하면 자동으로 생성되는 중복 리소스의 양을 획기적으로 줄이고, 복제된 위젯 사본의 모양새를 일괄적으로 관리할 수 있습니다.
엘리멘터가 CSS를 페이지에 추가하는 형태 보기
- 위젯의 컨트롤 패널 값을 변경 : 위젯에서 제공하는 각종 컨트롤러의 값은 압축 된 CSS 형태로 외부 리소스로 등록.
post-14481.css
HTML Widget
: 문서상에서 위젯이 위치한 곳에 압축되지 않고<style>
태그를 통해 인라인 형태로 추가.Custom CSS
: 위젯의 Custom CSS 필드에 입력한 스타일은 압축 되지 않은 형태로 외부 리소스로 등록.Loop Item
: Loop Item 템플릿 내부의 위젯 스타일(컨트롤 패널 값과 Custom CSS 모두 포함)은 모두<style>
태그를 통해 인라인 형태로 추가되고 서로 공유.
- 블로그 본문에서는 경어 대신 평어체를 사용합니다.
엘리멘터 위젯이 CSS를 다루는 방법 이해하기
위젯의 컨트롤 패널은 스타일을 공유하지 않는다
정확히는, 위젯에서 제공하는 컨트롤 패널을 통해 생성된 스타일은 공유되지 않는다. 모든 위젯은 고유의 클래스를 가지며, 컨트롤 패널에 입력한 값은 고유 클래스에 선언되므로 똑같은 설정의 위젯을 3개 복사하면 CSS의 양은 3배로 늘어난다.
코드에서 보듯이 Container
위젯 패널의 padding
필드의 값을 20px
로 설정한 값이 모두 고유한 클래스를 통해 중복으로 선언되었다. 패널의 필드에 값을 넣지 않은 기본값 상태는 아무런 스타일도 추가되지 않지만, 값이 설정되면 스타일이 추가된다. 따라서, 여러 필드에 값을 넣고 위젯을 복제하게되면 다량의 중복 코드가 발생한다.
Custom CSS 필드의 내용도 중복된다
위젯을 복제하면 해당 위젯의 Custom CSS
필드 내용도 복제되어 중복된다. 따라서 필드에 너무 많은 양의 CSS 코드를 입력하면 위젯이 복제될 때마다 엄청난 양의 중복 코드가 발생할 수 있다.
Custom CSS 필드에서 ‘selector’ 선택자는 스타일을 공유하지 않는다
엘리멘터 위젯의 Custom CSS
필드는 selector
라는 특수한 prefix를 제공한다. 위젯에 별도의 클래스를 추가하지 않고도 해당 위젯의 최상위 DOM 요소를 선택할 수 있다. 이 선택자는 위젯의 CSS Classes
필드에 사용자가 지정한 클래스가 아닌, 위젯 생성 당시 자동으로 명시되는 고유 클래스를 선택하므로, 같은 클래스 이름을 가진 다른 위젯들과 스타일을 공유하지 않는다.
selector
선택자는 같은 클래스 이름을 가진 위젯 사이에서 특별히 고유한 스타일 정의가 필요할 때 사용하는 것이 좋다.
전역 위젯(Global Widget) 사용에 유의하기
전역 위젯은 컨테이너형 위젯을 제외한 일반 위젯을 공용 템플릿으로 저장한 후 여러 페이지에서 재사용하기 위한 엘리멘터 모듈 시스템이다. 페이지 어느 곳에서든 전역 위젯으로 등록 된 위젯의 설정을 변경하면, 모든 페이지의 해당 위젯이 변경된 내용을 로드하므로 자주 사용되는 위젯을 중앙집중식으로 관리할 수 있다.
하지만 여기에는 큰 문제가 하나 있는데, 전역 위젯은 상속을 할 수 없는 격리된 템플릿이라는 점이다. 원본 위젯과 조금이라도 다른 설정의 사본이 필요하면 Unlink
를 통해 전역 위젯에서 분리시켜야 한다. 분리 된 사본은 더이상 전역 위젯이 아니므로 원본을 수정해도 영향을 받지 않아 일일이 찾아 수정하든지 아니면 그대로 방치하는 수 밖에 없다.
따라서 엘리멘터의 전역 위젯은 진정한 의미의 재사용과는 거리가 있다. 그 어떤 설정도 상속하지 않는 불변한 요소에만 제한적으로 사용하게 되는 것이다.
그리고 전역 위젯의 컨트롤 패널에서 설정한 필드 값을 통해 자동 생성된 CSS 코드는 위젯이 재사용될 때마다 중복되지 않고 스타일을 공유하는 장점이 있지만, 전역 위젯의 Custom CSS 필드에 입력한 코드는 위젯이 복제될 때마다 중복된다. 한 페이지에서 여러 번 재사용되는 전역 위젯은 Custom CSS 필드에 많은 코드를 사용하는 것은 바람직하지 않다.
아래에서 더 자세히 다루겠지만, 전역 위젯이 빛을 발하는 경우가 있는데, 바로 HTML Widget
을 전역으로 설정하는 것이다. HTML 위젯은 HTML, 자바스크립트, CSS 코드를 담을 수 있고 이 위젯을 전역 위젯으로 만들면 마치 외부 라이브러리처럼 활용할 수 있다.
엘리멘터 위젯이 CSS 코드를 원시적으로 처리하는 문제
보통 기본 위젯의 모양새를 그대로 쓰는 경우는 거의 없으므로 사용자는 컨트롤 패널의 필드 값을 수정하거나 Custom CSS 필드를 활용해 위젯을 수정한다. 그리고나서 복사/붙이기 방식으로 복제하여 사용하게 되는데, 앞서 말한바와 같이 복제될 때 마다 다량의 CSS 코드를 반복해서 생성한다.
하지만 이것은 엘리멘터의 높은 사용성을 위해 충분히 희생할 가치가 있고, 딱히 대안도 없으니 자연스럽게 사용하면 된다.
하지만 일반적으로 우리는 동일한 스타일이 반복되면 class
를 사용해 중복을 피한다. 위젯의 CSS Classes
필드에 클래스를 명시하고 어딘가에서 데코레이션을 한다면, 같은 클래스 이름을 가진 모든 위젯이 중복 코드를 생성하지 않고도 동일한 모양새를 공유할 수 있다. 다만 이를 위해서는 컨트롤 패널의 모든 필드 값을 기본 상태로 두고, 변경할 스타일을 모두 위젯 내부에 이미 명시되어 있는 클래스를 선택해 일일이 재정의해야 한다. 그래야만 코드의 중복 생성 없이 복제된 위젯들이 하나의 스타일을 공유할 수 있다.
따라서 위젯의 기본값을 변경하는 것은 모양새 변경점이 많으면서 한 페이지내에 반복 사용 횟수가 너무 높은 위젯의 경우가 아니라면 전혀 고려할 필요가 없다.
NHN Cloud의 서비스 페이지는 4개의 탭을 통해 총 27개의 동일한 리스트 박스 콤포넌트가 표시된다. 이것을 엘리멘터로 구현한다면 1개의 템플릿 혹은 위젯을 만들어 모양새를 변경한 후 스물 여섯 번 복제한다. 여기서 문제가 발생하는데, 자동 생성된 CSS 코드의 양도 27배가 된다. 실제 엘리멘터에서 동일한 템플릿을 만들어 보자.
Compute
- Instance
- Ephemeral Storage Instance
- GPU Instance
이런 형태의 컴포넌트를 만들기 위해 다음의 위젯들이 사용되었다. 해당 컴포넌트는 Jetcraft의 리스트박스 템플릿에서 자세히 확인할 수 있다.
- 2개의 Container Widget
- 1개의 Icon Widget
- 1개의 Heading Widget
- 1개의 Icon List Widget
이 컴포넌트는 대략 150
줄 가량의 코드 길이를 가진 980 bytes
용량의 CSS를 생성한다. 그리고 위젯을 26회 복제하면 약 4000
줄이 넘는 길이의 5.4kb
용량으로 늘어난다. 단순한 컴포넌트 1개가 웬만한 CSS 라이브러리를 넘어서는 수준이다.
이런 식으로 페이지에는 사이트맵과 푸터의 리스트들, 메가메뉴의 메뉴 리스트처럼 반복이 잦은 요소가 생각보다 많은 것을 생각한다면 엘리멘터 위젯이 CSS를 처리하는 방법이 매우 비효율적이라는 것을 알 수 있다.
현재 Elementor 웹 사이트의 Roadmap 페이지를 보면 이 부분에 대한 개선 가능성이 보이는 CSS Selector
항목이 있다.
엘리멘터 위젯의 재사용성을 높이는 방법
위젯의 재사용성을 높인다는 것은 위젯이 생성하는 HTML
, CSS
등의 정적 자원을 줄여 렌더링 비용을 절감하는 한편, 동일한 모양새가 유지되어야 하는 위젯에 대해 전역 클래스를 선언해 스타일 중복을 피하는 행위이다.
보통 이러한 노력들은 일반적인 엘리멘터 사이트에서 TTFB
, FCP
관련해 눈에 띄는 성능 향상을 보이지는 않는다. 엘리멘터 위젯은 내부적으로 캐싱과 코드 압축기능을 가지고 있어 자동으로 생성하는 코드를 효과적으로 렌더링한다.
하지만 페이지 레이아웃이 복잡하거나 대규모 트래픽이 발생하는 사이트, 동일한 위젯의 반복 사용이 많은 페이지, 그리고 관리자의 라이브 편집환경에서는 하술할 내용들이 페이지 성능과 사용성 개선에 좋은 영향을 줄 수 있다.
대체 가능한 위젯이 있는지 살펴보기
앞서 만든 컴포넌트는 여러 위젯을 조합하여 하나의 형태를 만들었다. 각 위젯은 모두 저마다의 래퍼 DOM 요소와 콘트롤러를 가지고 있으니 단일 위젯보다 많은 자원을 사용하며, 특히 편집 화면의 로딩 속도나 반응을 매우 느리게 한다. 같은 기능을 수행할 수 있는 대체 가능한 위젯이 있는지 먼저 살펴보는 것 만으로도 페이지에 좋은 영향을 줄 수 있다.
상기 컴포넌트는 사실 엘리멘터 기본 위젯인 Accordion Widget
하나로 대체할 수 있는데, 생성되는 CSS의 양도 훨씬 적고 기능도 더욱 풍부하다. 원본과 다른 점은 Accordion Widget
은 타이틀 부분을 토글할 수 있기 때문에 이것을 원치 않는다면 Custom CSS
필드에 해당 DOM 요소를 선택한 후 pointer-events: none
만 명시하면 해결된다.
컨테이너 위젯의 레이아웃과 너비 결정하기
Container Widget
, Grid Widget
은 주로 레이아웃에 관여하므로 페이지에서 가장 많이 사용되는 대표적인 컨테이너형 위젯이다. 자주 사용되는 만큼 설정에 따라 자동생성되는 DOM 래퍼 요소와 CSS의 양도 많은 만큼 위젯을 생성할 때 염두해 두어야 할 부분이 있다. 이에 대해서는 엘리멘터 사이트 속도를 높이는 최적화 방법 게시물에서 자세히 다루고 있다.
컨테이너형 위젯의 기본 값 변경
컨테이너형 위젯은 padding: 10px
, gap: 20px
이 기본값으로 잡혀있는데, 보통 불필요한 여백인 경우가 많아 0
으로 변경해 사용한다. 엘리멘터 편집화면의 컨테이너 프리셋 상자를 이용해 기본적인 컨테이너 하나를 추가하고 컨트롤 패널에서 padding
과 gap
의 값을 0으로 변경하면 외부 CSS 파일에 다량의 코드가 생성된다.
이제 아래의 방법대로 컨테이너 위젯을 생성해 보자.
- 편집화면의 좌측 상단 햄버거 메뉴를 클릭하여 Site Settings → Layout에서
Container Padding
과Gaps
필드에0
을 입력한다. 이제부터 모든 컨테이너 위젯은 이 설정을 따르므로 각 위젯에서 따로 초기화 하지 않아도 된다. 그리고 더이상 관련 CSS 코드도 생성하지 않는다. - 컨테이너 프리셋 상자를 사용하지 않고, 편집화면 왼 편의 위젯 사이드바에서
Container
위젯을 클릭해 생성한다. 그러면flex-direction
필드의 값을 수정하지 않는 이상 불필요한 flexbox 관련 기본 CSS 출력을 줄일 수 있다.
이렇게 기본값을 전역에서 설정한 경우와 그렇지 않은 경우를 각각 10개의 컨테이너를 생성해 비교하면 자동으로 생성되는 코드의 양이 49 line
과 159 line
으로 약 3배 가량의 차이가 난다. 별도의 노력 없이 모든 페이지를 항시 3배 가량 적은 코드로 렌더링 하는 것이다.
컨테이너 레벨에서 기본값을 설정하는 방법
전역 설정이 되어있지 않거나 다른 값으로 설정된 사이트로 컨테이너를 복사하게 되면 각 컨테이너는 해당 사이트 설정에 영향을 받을 수 있다. 이런 경우는 최상위 컨테이너의 Custom CSS
필드에 다음의 코드를 넣어 하위 컨테이너에 대해 기본값을 유지할 수 있다. 아래 코드처럼 지역변수를 사용하지 않고 padding
속성으로 명시하게 되면 위젯 컨트롤 패널의 필드 값을 수정해도 반영되지 않는 명시도 문제가 생기니 주의해야 한다.
복잡한 레이아웃과 디자인으로 구성 된 컨테이너의 기본값을 초기화하면 다른 사용자가 템플릿을 사용할 때 정적 리소스를 획기적으로 줄일 수 있으므로 스킨 제작자라면 알아 둘 필요가 있겠다.
위젯이 공유하는 전역 클래스 데코레이션
엘리멘터는 각 위젯마다 고유의 클래스를 생성하므로 스타일을 공유하지 않는다고 하였다. 다른 위젯의 스타일에 간섭받지 않고 페이지 이곳저곳으로 옮기기 쉬운 장점이 있는 한편, 스타일이 공유되지 않기에 복제된 위젯의 모양새를 일괄적으로 변경하려면 일일이 찾아 개별적으로 변경해야 하는 단점이 있다.
엘리멘터의 로드맵에 따르면, 위젯의 Advanced
탭을 Class
탭으로 합병하여 전역 클래스를 선언하고 여러 위젯에서 공유할 수 있는 기능을 준비중에 있는 것으로 보인다. 일단 해당 기능이 언제 공개될지는 알 수 없으므로, 다른 대안을 생각해야 하겠다.
일단, 동일한 모양새를 원하는 위젯마다 Advanced
탭의 CSS Classes
필드에 클래스 이름을 명시하고 어딘가에서 치장을 하는 것이 기본이다. 이때 위젯의 Custom CSS
필드나 전역 위젯(Global Widget)으로 등록했을 때 생기는 문제에 대해서는 이미 짚고 넘어갔으니 곧바로 HTML Widget
을 사용한 선언에 대해 이야기 해보자.
HTML Widget에 전역 클래스 선언
HTML Widget
의 Content
탭 필드에 코드를 작성하면 2개의 래퍼 DOM 요소가 생성되고, 코드는 HTML 위젯의 문서상 위치와 동일한 곳에 Inline
형태로 출력된다. 하지만 HTML 위젯의 Custom CSS
에 스타일을 작성하면 어떠한 DOM 요소도 생성하지 않고 코드만 외부 리소스로 등록한다.
이제 jetcraft-ws-listbox
라는 클래스를 가진 모든 위젯은 HTML Widget
의 스타일을 상속한다. 따라서 HTML Widget
은 자신의 스타일을 상속하는 위젯이 사용되는 곳에는 항상 함께 따라다녀야 한다. 이 부분이 거슬릴 것으로 생각되지만, 실제 사용해보면 중도에 스타일을 바꿔야해서 위젯들을 페이지마다 일일이 찾으러 다니는 고생보다 훨씬 효율적이다.
HTML Widget을 전역 위젯(Global Widget)으로 등록
이제 HTML Widget
을 전역 위젯으로 등록하면 위젯 전체에 대해 일괄 변경이 필요할 때 HTMl Widget
내부의 스타일을 수정하면 모든 페이지에 반영되므로 스타일을 상속하는 모든 위젯의 모양새를 한번에 변경할 수 있다.
엘리멘터 무료 버전 사용자는 전역 위젯 기능을 사용할 수 없으므로 이 혜택을 받을 수 없는데, Elementor Addon Components 플러그인을 설치하면 프로 버전의 전역 위젯 기능을 사용할 수 있다. 이 애드온은 프로 버전의 전역 위젯 기능을 Unlock하므로 훗날 엘리멘터 프로를 구입해서 해당 플러그인을 삭제해도 문제가 없다.
다만 이 플러그인은 엘리멘터가 유료로 서비스하는 영역을 의도적으로 침해하고 있기 때문에 지적재산권, 라이선스 문제가 발생할 수 있으니 테스트 용도 혹은 일시적인 사용으로 제한하는 것이 좋다.
개별적인 모양새 변경이 필요한 위젯의 스타일링
이제 HTML Widget
의 스타일을 상속받는 위젯은 모두 같은 모양새를 유지한다. 가끔 특정 위젯의 모양새를 변경해야 하는 경우가 있는데, 해당 위젯의 컨트롤 패널의 필드값을 수정하거나 Custom CSS
필드에서 스타일을 오버라이딩하면 된다. .jetcraft-ws-list
처럼 대표 클래스를 그대로 덮어쓰지 말고 엘리멘터에서 제공하는 selector
접두사를 사용하면 이후에 위치한 같은 위젯의 스타일로 상속을 전파하지 않고 자신만 안전하게 오버라이딩할 수 있다.
컨트롤 패널의 필드 키와 일치하는 클래스 선택하기
앞서 소개한 코드는 위젯의 CSS Classes
필드에 명시된 .jetcraft-ws-listbox
라는, 위젯의 최상위 DOM 요소에 margin: 10px
로 오버라이딩하고 있다. 그런데 실제로 해당 위젯의 컨트롤 패널에서 margin
필드의 값에 20px
을 입력하면 기존 10px
인 여백이 20px
로 변경되는 것이 아니라, 20px
이 기존 값에 추가되어 총 30px
의 여백이 발생한다.
엘리멘터 위젯에서 제공하는 Advanced
탭의 margin
필드 키는 사실 최상위 DOM 요소가 아니라 바로 그 아래에 있는 .elementor-widget-container
에 연결되어 있기 때문이다. 따라서 위젯의 margin
을 제대로 오버라이딩하려면 코드를 다음과 같이 변경해야 한다.
하지만 엘리멘터 버전 3.26에서 실험적 기능으로 추가된 Optimized Markup
기능을 활성화 시키면 .elementor-widget-container
요소가 더이상 DOM에 추가되지 않으므로 앞서 소개한 코드를 그대로 사용하는 것이 장기적인 측면에서 더 좋다.
위젯의 기본 값 변경하기
글의 초반부에 언급했듯이 위젯을 외부에 배포하는 수준으로 만들 것이 아니라면 하술 할 내용은 무시하도록 한다. 위젯의 기본 값을 제대로 변경하면 따로 필드 값을 조정하지 않아도 원하는 모양새로 안전하게 오버라이딩하면서 자동 생성되는 코드의 양도 획기적으로 줄일 수 있지만, 콘트롤 패널이 사용하는 클래스를 찾기 위해 일일이 각 필드 값을 설정한 후 웹 브라우저의 Inspector
를 통해 클래스가 어떻게 명시되어 있는지 살펴야 한다.
또한 사용자 정의 클래스가 위젯의 컨트롤 패널에서 생성하는 스타일보다 높은 명시도를 가지게 되면 본래 엘리멘터 위젯의 가장 큰 장점인 사용성에 문제가 생긴다. 패널의 값을 변경해도 반영이 안되는 것 만큼 큰 일이 없는 것이다. 따라서 필드 키와 맞는 클래스를 선택하고 명시도에 문제가 없는지도 확인해야 한다.
이러한 노력에도 불구하고 엘리멘터가 업데이트 되면서 위젯 내부의 클래스 이름이 변경되거나 하면 쉽게 다시 버그 픽스를 해야한다. 지속적인 업데이트 모니터링과 CSS 마크업에 대한 충분한 이해가 없다면 위젯의 기본값 변경은 명시도 무시하고 개인이 사용하는 선에서 만족하는 것이 좋다.
위젯이 제공하는 지역 변수 사용하기
정확한 클래스 선택과 명시도 문제를 동시에 해결하기 가장 안전한 방법은 해당 위젯이 제공하는 지역 변수를 오버라이딩 하는 것이다. 웹 브라우저의 개발자 도구를 통해 위젯의 최상위 DOM 요소를 선택하고 어떤 지역 변수가 선언되었는지 확인한다.
제공되는 클래스와 동일한 명시도를 갖도록 하면서 위젯의 CSS Classes
필드에 선언한 클래스명으로 변경한 후, 오버라이딩을 원하는 속성만 따로 HTML Widget
의 Custom CSS
필드에 명시한다.
이렇게 하면 위젯의 기본 값 → HTML Widget에 정의한 스타일 → 위젯의 컨트롤 패널에 입력한 값 순으로 명시도가 높아져 의도한 대로 작동하게 된다.
명시도가 의도대로 작동하지 않는 경우
보통 위젯의 최초 기본 스타일은 페이지 <header>
에 로드된다. 그런데 간혹 특정 위젯이 페이지의 <body>
요소 하단에 로드되는 경우가 있다. 그러면 사용자 정의 스타일보다 위젯 기본값이 더 나중에 로드되므로 명시도에 문제가 생긴다. 이것은 엘리멘터의 버그이므로 그런 위젯들은 문제가 해결될 때 까지 기본 값 변경을 자제하는 것이 좋다.
마치며
지금까지 진행한 내용을 바탕으로 컨트롤 패널만 사용한 경우, 위젯의 기본 값을 오버라이딩한 경우, 대체 가능한 위젯으로 구현한 경우를 모두 포함한 예시 템플릿은 여기를 클릭해서 확인할 수 있다.
엘리멘터의 위젯이 CSS 자원을 관리하는 방법이 비효율적이긴 하나 정적 자원에 대한 렌더링이 뛰어난 엘리멘터에서 무리하게 클래스를 오버라이딩 하는 것은 매 업데이트마다 스트레스를 가져올 수 있다. 한 페이지 내에서 반복이 심한 위젯에 한해 제한적으로만 고려해도 충분하며 앞으로 엘리멘터의 로드맵에 포함된 새로운 클래스 공유 기능을 기대해 보는 것이 좋겠다.