CSS 셀렉터가 성능에 미치는 영향을 알아봅니다.
아래 게시물의 번역입니다.
몇몇 CSS 셀렉터가 다른 것보다 빠르다는 말을 들어본 적이 있을 것입니다
그리고 아마 이 기사에서 더 빠른 셀렉터를 작성하는 방법을 배우길 기대하셨을 지 모릅니다.
비하인드 스토리 빠르게 살펴보기
- 클래스 `title`이 있는 상위 요소
- `section` 클래스가 있는 요소,
- 마지막으로 `wrapper` 클래스가 있는 요소를 찾습니다.
이 예는 브라우저 엔진이 이 긴 `.wrapper .section .title .link` 셀렉터를 일치시키는 것보다
`.link`만 일치시키는 것이 더 빠를 가능성이 있음을 보여줍니다.
브라우저가 확인할 사항이 적기 때문입니다
실제로도 이럴까요?
웹 페이지(프로젝트)에 따라, DOM 트리의 크기에 따라, CSS 규칙의 양 및 DOM이 자주 변경되는지 여부에 따라 크게 달라집니다.
불행히도 이에 대한 규칙은 없습니다.
따라서 앱에 적합하고 쉽게 읽고 유지 관리할 수 있는 방식으로 코드를 작성한 다음
중요한 사용자 시나리오의 실제 성능을 측정하세요.
직접 성능 측정해보기
저는 여기서 느낌이라는 단어를 강조하고 싶습니다.
사용자에 대한 공감대를 형성하고 가능한 경우 사용자가 실제로 사용하는 장치를 사용하십시오.
우리가 개발을 위해 사용하는 시스템은 사용자의 디바이스보다 훨씬 강력할 수 있습니다.
주요 시나리오를 측정하는 데 사용할 수 있는 도구를 사용하는 방법을 배우고
작업을 느리게 만드는 가장 큰 장애물을 식별하는 방법을 배웁tlek.
셀렉터 통계 활용하기
- 성능 도구를 엽니다.
- 오른쪽 상단 모서리에 있는 톱니 아이콘을 클릭하여 도구 설정을 엽니다.
- 고급 렌더링 도구 사용(느림) 옵션을 선택합니다.
- 기록을 클릭하고 개선하려는 웹 페이지에서 시나리오를 실행한 다음 중지를 클릭합니다.
- 기록된 프로필에서 개선하려는 긴 스타일 재계산을 식별하고 폭포 보기("메인" 섹션)에서 선택합니다.
- 하단 탭 표시줄에서 셀렉터 통계를 클릭합니다.
이제 DevTools는 이 재계산 작업 중에 브라우저 엔진에서 계산한 모든 CSS 셀렉터 목록을 제공합니다.
셀렉터를 처리하는 데 걸린 시간이나 셀렉터와 일치하는 DOM 갯수를 기준으로 정렬할 수 있습니다.
처리하는 데 오랜 시간이 걸리거나, 여러 번 매치된 셀렉터는 개선할 수 있는 좋은 후보가 될 수 있습니다.
셀렉터를 단순화할 수 있습니까? 더 구체적으로 만들 수 있습니까?
사례 연구
위 설명을 좀 더 실용적으로 만들기 위해 실제 웹 페이지를 개선해 보겠습니다.
이를 위해 아래와 같이 데모용으로 구축된 사진 갤러리 페이지를 사용할 것입니다.
이 페이지 상단에는 카메라 모델, 조리개 크기, 노출 시간 등으로 사진을 필터링하는 도구 모음이 있으며
카메라 모델 간 전환이 지금은 약간 느리게 느껴집니다.
- 데모 페이지를 로드하고 필터가 준비될 때까지 기다립니다.
- 카메라 모델 필터를 다른 값으로 전환하고 성능 측정을 시작합니다.
- 모든 카메라 모델로 다시 전환하고 녹화를 중지합니다.
모든 카메라 모델로 다시 전환하는 속도가 느리기 때문에, 해당 부분만 측정합니다.
강력한 개발 환경에서보다 사용자에게 더 가까운 결과를 얻기 위해 CPU 속도를 4배로 낮출 것입니다.
기록이 준비되면 프로파일에서 긴 스타일 재계산 블록을 쉽게 볼 수 있으며
제 경우에는 900밀리초 이상의 작업에 해당합니다.
이 블록을 클릭하고 Selector Stats 창을 연 다음 경과 시간별로 정렬해 보겠습니다.
셀렉터를 DOM과 매칭하는데 데 더 많은 작업이 필요하고 일치하는 횟수가 많을수록
이 셀렉터를 개선하여 더 많은 잠재적인 승리를 얻을 수 있습니다.
다음 셀렉터들은 흥미로워 보입니다.
-
.gallery .photo .meta ::selection
-
.gallery .photo .meta li strong:empty
-
[class*=" gallery-icon--"]::before
-
.gallery .photo .meta li
-
*
-
html[dir="rtl"] .gallery .photo .meta li button
::selection 셀렉터 개선하기
이 특정 케이스는 코드의 버그 때문에 실제로 문제가 됩니다.
셀렉터는 대신 `.gallery .photo .meta::selection`이어야 합니다.
즉, `.meta`와 `::selection` 사이에 공백이 없어야 합니다.
::empty 셀렉터 개선하기
셀렉터 `.gallery .photo .meta li strong:empty`는 얼핏 보기에 수상해 보입니다.
`:empty` 의사 셀렉터는 `strong` 요소에 내용이 없을 때만 셀렉터가 일치함을 의미합니다.
이렇게 하려면 엔진이 요소의 태그 이름을 확인하는 것보다 약간 더 많은 작업을 수행해야 하지만 매우 유용합니다.
그러나 이와 유사한 다른 CSS 규칙을 보면 다음을 볼 수 있습니다.
.gallery .photo .meta li strong:empty {
padding: .125rem 2rem;
margin-left: .125rem;
background: var(--dim-bg-color);
}
html[dir="rtl"] .gallery .photo .meta li strong:empty {
margin-left: unset;
margin-right: .125rem;
}
이를 개선하기 위해 CSS logical properties을 사용할 수 있습니다.
물리적인 마진 방향을 지정하는 대신 아래와 같이 모든 텍스트 방향에 적용되는 논리적 마진을 사용할 수 있습니다.
.gallery .photo .meta li strong:empty {
padding: .125rem 2rem;
margin-inline-start: .125rem;
background: var(--dim-bg-color);
}
[class*=" gallery-icon--"] 셀렉터 개선
다음 셀렉터는 복잡해 보이는 속성 셀렉터인 `[class*=" gallery-icon--"]::before`입니다.
속성 셀렉터는 매우 유용할 수 있으므로 제거하기 전에 실제로 부정적인 영향을 미치고 있는지 확인하세요!
[class*=" gallery-icon--"]::before {
content: '';
display: block;
width: 1rem;
height: 1rem;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
filter: contrast(0);
}
.gallery-icon--camera::before { background-image: url(...); }
.gallery-icon--aperture::before { background-image: url(...); }
.gallery-icon--exposure::before { background-image: url(...); }
...
이것은 편리한 기능이지만 엔진에 클래스 값을 읽고 서브스트링 문자열 검색을 수행하도록 요청하고 있습니다.
다음은 엔진이 덜 일하도록 도울 수 있는 한 가지 방법입니다.
.gallery-icon::before {
content: '';
display: block;
width: 1rem;
height: 1rem;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
filter: contrast(0);
}
.gallery-icon.camera::before { background-image: url(...); }
.gallery-icon.aperture::before { background-image: url(...); }
.gallery-icon.exposure::before { background-image: url(...); }
.gallery .photo .meta li 셀렉터 개선
.photo-meta {
display: flex;
align-items: center;
gap: .5rem;
height: 1.5rem;
}
* 셀렉터 개선
`*` 기호는 모든 요소와 일치하는 CSS의 범용 셀렉터로 사용됩니다.
무엇이든 일치시키는 이 기능은 엔진이 모든 요소에 관련 규칙을 적용해야 함을 의미합니다.
성능 기록에서 볼 수 있듯이 이 선택기는 실제로 여러 번 매칭합니다.
CSS 규칙이 실제로 무엇을 하는지 살펴볼 가치가 있습니다.
우리의 경우에는 특정 `box-sizing` 값을 적용합니다.
* {
box-sizing: border-box;
}
성능 개선 결과
결론
추가로 볼 만한 자료
https://yceffort.kr/2021/03/improve-css-performance
'FrontEnd' 카테고리의 다른 글
[번역] 집합론으로 이해하는 타입스크립트 (0) | 2023.01.31 |
---|---|
Javascript로 Python range 함수 구현하기 (0) | 2023.01.31 |
[Vue3] 2023년, Vue3은 어떻게 달라질 것인가? (0) | 2023.01.29 |
리액트 이벤트 리스너는 어떻게 등록되고 처리되는가 (0) | 2023.01.28 |
멀티쓰레드 자바스크립트 : 메세지 패싱 추상화 패턴 (0) | 2023.01.27 |