안녕하세요 ![]()
기본 개념
목표는 하드코딩된 스켈레톤 템플릿에 의존하는 대신, 실제 Discourse UI에서 생성된 스켈레톤 로더를 구축하는 것이었습니다.
빌더는 관리자가 페이지에서 실제 요소를 선택하여 스켈레톤 영역으로 변환할 수 있도록 합니다.
예를 들어:
.title
.avatar
.topic-excerpt
.btn
.category-breadcrumb
컴포넌트는 이러한 셀렉터를 사용하여 런타임에 스켈레톤을 생성합니다.
스켈레톤 미리보기
흥미로운 점은 관리자가 셀렉터를 수동으로 작성할 필요가 없다는 것입니다. 빌더는 선택된 요소를 분석하여 여러 후보 셀렉터를 생성합니다.
유용한 셀렉터 생성은 예상보다 어려웠습니다
제가 직면한 첫 번째 문제 중 하나는 셀렉터 생성이었습니다.
나이가(초보적인) 구현은 쉽게 다음과 같은 것을 생성할 수 있습니다:
.container.list-container.--topic-list .row.full-width .contents ...
기술적으로는 유효하지만, 재사용 가능한 스켈레톤 구성에는 지나치게 구체적입니다.
아이콘의 경우, 생성된 셀렉터에 SVG 관련 클래스와 같은 구현 세부 사항이 포함될 수 있어 상황이 더 나빠질 수 있습니다.
저는 실제로는 다음과 같은 것에 더 가까운 것을 원했습니다:
.badge-category__name
또는:
.badge-category__wrapper .d-icon
전체 DOM 경로를 설명하는 셀렉터 대신에 말입니다.
따라서 빌더는 이제 여러 후보를 생성하고 다음 요소들을 기준으로 점수를 매깁니다:
- 셀렉터 깊이
- 클래스 수
- 반복 매칭
- 상태 관련 클래스
- 기술적 SVG/아이콘 클래스
- 셀렉터가 여전히 선택된 요소와 매칭되는지 여부
그 결과, 관리자가 선택하거나 수동으로 편집할 수 있는 권장 셀렉터 목록이 생성됩니다.
숨겨진 요소
스켈레톤이 표시되는 동안 단순히 사라져야 하는 요소를 위한 별도의 피커도 있습니다.
예를 들어:
.alert.alert-info
이는 공지 배너나 임시 알림과 같은, 빌드/테스트 중에 존재하지만 스켈레톤 레이아웃에 영향을 주지 않아야 하는 요소에 유용한 것으로 드러났습니다.
여기서 흥미로운 문제는 요소를 숨길 때 빈 공간이 남지 않아야 한다는 것입니다.
따라서 제외된 요소는 단순히 display: none 목록으로 처리되지 않으며, 기하학적 계산도 해당 요소가 최종 레이아웃의 일부가 아니라는 점을 이해해야 합니다.
스켈레톤 미리보기
내비게이션
아마도 가장 큰 도전은 내비게이션이었을 것입니다.
원하는 동작은 다음과 같았습니다:
클릭
↓
즉시 스켈레톤 표시
↓
Discourse가 라우트 변경
↓
목적지 DOM 표시
↓
스켈레톤 숨김
유혹적인 해결책은 내비게이션 라이프사이클에 깊게 후킹하여 DOM이 완전히 안정될 때까지 기다리는 것이었습니다.
하지만 그것은 잘못된 접근임이 밝혀졌습니다.
어느 시점에서 실제 콘텐츠가 이미 표시된 후에도 스켈레톤이 몇 초 동안 표시되는 문제가 발생했습니다.
교훈은 단순했습니다:
스켈레톤은 DOM 준비 완료 게이트가 되어서는 안 됩니다.
c> 목적지가 인수를 넘겨받을 수 있을 만큼 충분한 실제 콘텐츠를 갖게 되면, 스켈레톤은 길을 비켜야 합니다.
이는 내비게이션의 지각된 속도에 큰 차이를 만들었습니다.
뷰포트
Discourse에는 이미 반응형 뷰포트 시스템이 있으므로, 컴포넌트는 이제 동일한 브레이크포인트 추상화를 사용합니다:
xs
sm
md
lg
xl
2xl
스켈레톤 구성은 추가로 다음과 같이 그룹화될 수 있습니다:
모바일 → xs / sm
태블릿 → md
데스크톱 → lg / xl / 2xl
전체 → 모든 것
이는 컴포넌트가 실제 픽셀 값을 전혀 알 필요가 없다는 것을 의미합니다.
Discourse가 브레이크포인트 값을 변경하더라도, 스켈레톤 컴포넌트는 새로운 하드코딩된 숫자를 중심으로 다시 작성될 필요가 없습니다.
기하학 캐싱
셀렉터는 무엇이 렌더링되어야 하는지를 알려주지만, 스켈레톤 모양이 정확히 어디에 나타나는지는 알려주지 않습니다.
이를 위해 기하학 캡처를 추가했습니다.
빌더는 실제 렌더링된 영역을 측정하고 그 기하학을 저장하여, SPA 내비게이션 중에 로더가 즉시 목적지 스켈레톤을 렌더링할 수 있도록 합니다.
나중에 방문할 때 기준 기하학이 계속 변경되는 것을 원하지 않는 경우를 위한 명시적인 기하학 잠금 옵션도 있습니다.
이것은 또 다른 중요한 구별이었습니다:
셀렉터 정의와 렌더링된 기하학은 두 가지 다른 것입니다.
초안
필요해진 또 다른 것은 초안 상태였습니다.
다음과 같은 워크플로를 원하지 않았습니다:
빌더 열기
→ 10분 동안 구성
→ 빌더 닫기
→ 모든 것이 사라짐
따라서 빌더는 실제 테마 설정과 별도로 진행 중인 초안을 유지합니다.
초안은 페이지/라우트/뷰포트 조합에 범위가 지정되므로, 예를 들어:
topic-list / lg
topic-list / md
topic-list / xs
이 서로를 우연히 덮어쓰지 않습니다.
빌더를 닫는다고 작업이 파괴되지 않습니다.
되돌리기(Undo)
빌더가 더 인터랙티브해지면서, 되돌리기 시스템은 거의 피할 수 없게 되었습니다.
빌더는 DOM 작업의 히스토리를 유지하려는 대신 구성 상태의 스냅샷을 저장합니다:
{
"regions": \[\],
"excludes": \[\]
}
이는 되돌리기 시스템을 훨씬 쉽게 추론할 수 있게 해주며, 실제 페이지 DOM에서 독립적으로 유지합니다.
이 프로젝트는 활성 개발 단계에 있습니다. hopefully 곧 테마 컴포넌트로 준비될 것입니다! ![]()




