저는 약 15년의 경력을 가진 프론트엔드 개발자로서 웹 개발의 발전을 직접 목격했습니다. 저에게는 FTP를 통해 수정된 파일을 업로드하던 시대(예, GitHub는 15년 전에 출시되었지만 2011년에야 발견했습니다)부터 반응형 인터페이스, UI 라이브러리 및 직접 생성된 웹 사이트의 현대 시대까지 많은 발전을 이루었습니다. 피그마.
그러나 나는 여전히 다음과 같은 중첩 스타일을 사용하는 프로젝트를 접합니다.
.some-class ul li div a { /* some style */ }
또는,
#nav .nav-link svg { /* some style */ }
충격적으로 보일 수도 있지만 이러한 코딩 방식은 수백만 달러 규모의 빠르게 성장하는 프로젝트부터 초라한 스타트업에 이르기까지 모든 분야에 널리 퍼져 있습니다.
이 접근 방식이 왜 문제를 일으킬 수 있는지 살펴보겠습니다.
깊게 중첩된 스타일은 특히 대규모 프로젝트의 경우 스타일 충돌로 이어지는 경우가 많습니다. CSS는 계단식 스타일 시트로서 계단식으로 배열되어 해당 요소의 특이성에 따라 요소에 적용됩니다. 깊게 중첩된 스타일은 특정성으로 인해 의도치 않게 다른 스타일을 재정의할 수 있습니다.
다음 예를 고려하십시오.
.some-class ul li div a { color: red; } ... .some-class a { color: blue; }
.some-class
의 모든 링크가 파란색일 것으로 예상할 수 있습니다. 그러나 첫 번째 규칙의 더 큰 특수성으로 인해 ul > li > div
내에 중첩된 모든 링크는 파란색이 아닌 빨간색이 됩니다. 이로 인해 예상치 못한 시각적 불일치가 발생하고 디버깅에 많은 시간이 낭비될 수 있습니다.
CSS의 특정성(또는 스타일의 '가중치') 개념을 이해하는 것은 왜 깊은 중첩이 문제가 될 수 있는지 이해하는 데 중요합니다. 구체성은 여러 규칙이 단일 요소에 대해 경쟁하는 경우 적용되는 CSS 규칙을 결정합니다. 선택기의 유형과 수량을 기준으로 계산됩니다.
특이성은 4가지 범주 가중치 시스템을 기반으로 계산됩니다.
여기서 규칙을 고려하십시오.
body #content .data img:hover { /* some style */ }
특이도는 0 1 2 2 입니다. 이는 하나의 ID( #content ), 두 개의 클래스( .data 및 :hover ), 두 개의 요소( body 및 img )입니다.
이제 다음 규칙을 고려해보세요.
#nav .nav-link svg { /* some style */ }
여기서 특이성은 0 1 1 1 입니다. 이는 하나의 ID( #nav
), 하나의 클래스( .nav-link
) 및 하나의 요소( svg
)입니다.
특이성은 전통적인 십진수와 같은 "이월" 시스템에서는 작동하지 않습니다. 예를 들어, 0 1 0 11 의 특이성을 갖는 선택자는 비록 십진법에서는 11 과 1+ 1이 동일하더라도 0 1 1 1 의 특이성과 동일하지 않습니다.
마지막으로, 범용 선택자( *
), 결합자( +
, >
, ~
, ' ') 및 부정 의사 클래스( :not()
)는 특이성에 영향을 미치지 않습니다. 그러나 :not()
인수 내에서는 선택자가 평소대로 계산됩니다.
시각적 학습자에게는 CSS 특이성에 관한 이 비디오를 추천합니다.
CSS 특이성과 계산 방법을 이해하면 CSS를 더 잘, 더 예측 가능하게 작성하고 스타일이 예상대로 적용되지 않을 때 발생하는 문제를 디버깅할 수 있습니다.
!important
규칙과 특이성 때때로 개발자는 CSS 특정 충돌로 인해 어려움을 겪을 때 !important
규칙을 사용합니다. 이 규칙은 CSS 속성을 매우 구체적으로 만듭니다. 즉, 거의 모든 다른 선언을 재정의합니다.
예를 들어:
#nav .nav-link svg { color: blue; } .nav-link svg { color: red !important; }
ID 선택기로 인해 첫 번째 규칙의 특이성이 더 높음에도 불구하고 두 번째 규칙의 !important
로 인해 svg
의 색상이 빨간색이 됩니다.
!important
특정성 문제로 어려움을 겪을 때 빠른 수정이 될 수 있지만 광범위하게 사용하는 것은 권장되지 않습니다. 과도하게 사용하면 유지 관리 가능성, 예측 가능성 및 성능에 영향을 미칠 수 있습니다. 대규모 프로젝트에서 !important
과도하게 사용하면 CSS 특정성을 관리하는 데 어려움을 겪는 경우가 많습니다. !important
에 의존하는 것보다 CSS를 리팩토링하고 지나치게 구체적인 선택기의 사용을 줄이는 데 시간을 투자하는 것이 더 나은 경우가 많습니다.
지금 바로 제품을 확인하실 수 있습니다 🙂. 나는 내 것을 확인했습니다 :
!important
빠른 수정이 필요할 수 있습니다. 그것은 호두를 깨기 위해 큰 망치를 사용하는 것과 같습니다. 보다 유지 관리하기 쉬운 접근 방식은 선택기를 최대한 단순하고 단순하게 유지하는 것입니다. 이렇게 하면 향후 CSS를 더 쉽게 이해하고 관리하고 확장할 수 있습니다. 그리고 !important
전쟁에서 승리하는 가장 좋은 방법은 처음부터 전쟁을 시작하지 않는 것임을 기억하십시오.
깊이 중첩된 스타일의 또 다른 문제는 브라우저 렌더링에 대한 성능 영향입니다. 브라우저가 요소에 스타일을 적용할 때 DOM을 오른쪽에서 왼쪽으로 순회하며 키 선택기(예: a
및 svg
)부터 시작하여 일치하는 항목을 찾거나 맨 위에 도달할 때까지 조상을 통해 이동합니다. 스타일이 많이 중첩될수록 이 순회 시간이 길어지고 잠재적으로 대규모 프로젝트에서 성능에 영향을 미치고 페이지 로드 시간이 느려집니다.
다음과 같이 CSS 규칙을 지정할 때:
.some-class ul li a { /* some style */ }
이 규칙은 트리의 맨 아래( a
태그에서)부터 시작하여 트리를 통해( li
, ul
및 .some-class
통해) 작동하는 방식을 시각화할 수 있습니다.
브라우저는 먼저 모든 (모든 것을 의미합니다) a
요소를 찾은 다음 이러한 a
태그가 li
요소 안에 있는지 확인합니다. 그런 다음, 이러한 li
요소가 ul
내부에 있는지 확인하고 마지막으로 이러한 ul
.some-class
클래스의 요소 내부에 있는지 확인합니다.
이것이 브라우저가 CSS 선택자를 읽는 방법이며 복잡한 선택기로 인해 페이지 렌더링 속도가 느려질 수 있는 이유입니다. 브라우저는 각 요소가 지정된 규칙에 맞는지 확인하기 위해 여러 번 검사해야 합니다. 규칙이 깊어질수록 브라우저에서 더 많은 확인을 수행해야 하므로 성능에 영향을 줄 수 있습니다.
CSS 모듈을 사용 하면 작업 중인 구성 요소에 대해 로컬 범위가 지정된 개별 모듈에 CSS를 작성할 수 있습니다. 즉, CSS 모듈의 스타일은 해당 특정 모듈에만 적용 가능하며 누출되거나 페이지의 다른 요소에 영향을 주지 않습니다.
CSS 모듈이 해시된 클래스 이름을 사용하여 스타일 캡슐화를 보장하는 방법을 살펴보겠습니다. CSS 모듈을 사용하면 CSS 파일에 정의한 클래스 이름이 컴파일 타임에 해시됩니다. 이 해시는 구성 요소에 해당하는 고유한 클래스 이름을 생성합니다. 예를 살펴보겠습니다.
다음과 같이 정의된 CSS 모듈이 있다고 가정합니다.
/* Button.module.css */ .button { color: white; background-color: blue; }
그리고 이를 구성 요소에서 다음과 같이 사용합니다(저는 styles
대신 s
로 스타일 개체를 가져오는 것을 선호합니다. 이는 입력 시간을 절약하고 코딩 효율성을 높이는 빠른 팁입니다).
import React from 'react'; import s from './Button.module.css'; const Button = () => { return ( <button className={s.button}>Click me</button> ); }; export default Button;
애플리케이션이 컴파일되면 렌더링된 HTML은 다음과 같을 수 있습니다.
<button class="Button_button__3FQ9Z">Click me</button>
이 경우 Button_button__3FQ9Z
CSS 모듈에서 생성된 해시된 클래스 이름입니다. 해시의 정확한 구조와 길이는 프로젝트 구성에 따라 달라질 수 있습니다.
이 고유한 클래스 이름은 Button.module.css
에 정의한 스타일이 이 버튼에만 적용되고 애플리케이션의 다른 요소에는 영향을 미치지 않도록 합니다. 또한 해시된 클래스 이름을 명시적으로 대상으로 지정하지 않는 한 다른 스타일이 이 버튼에 영향을 줄 수 없도록 합니다. 이러한 스타일 캡슐화는 CSS 모듈의 주요 이점 중 하나입니다.
CSS를 처리하는 또 다른 인기 있는 방법은 styled-Components 또는 Emotion 과 같은 CSS-in-JS 라이브러리를 사용하는 것입니다. 이러한 라이브러리를 사용하면 JavaScript 내에서 CSS를 직접 작성할 수 있으며 이는 여러 가지 이점이 있습니다.
다음은 React 애플리케이션에서 스타일 구성 요소를 사용하는 방법에 대한 예입니다.
import React from 'react'; import styled from 'styled-components'; const Button = styled.button` color: white; background-color: ${(props) => props.primary ? 'blue' : 'gray'}; `; const App = () => { return ( <div> <Button primary>Primary Button</Button> <Button>Secondary Button</Button> </div> ); }; export default App;
이 예에서 Button
구성 요소에는 primary
소품에 따라 변경되는 동적 스타일이 있습니다.
CSS 모듈 또는 이와 유사한 것을 지원하는 JavaScript 프레임워크로 작업하지 않는 경우에도 BEM(블록, 요소, 수정자)과 같은 명명 방법을 사용하여 CSS를 효과적으로 관리할 수 있습니다.
BEM은 "Block Element Modifier"의 약자이며 CSS에서 재사용 가능한 구성 요소 및 코드 공유를 만드는 데 도움이 되는 방법론입니다. BEM을 사용하여 CSS를 구성하는 방법은 다음과 같습니다.
/* Block */ .top-menu { } /* Element */ .top-menu__item { } /* Modifier */ .top-menu__item_active { }
BEM에서 '블록'은 그 자체로 의미가 있는 독립형 엔터티이고, '요소'는 독립형 의미가 없고 의미상 해당 블록과 연결된 블록의 일부이며, '수정자'는 플래그입니다. 모양이나 동작을 변경하는 데 사용되는 블록 또는 요소입니다.
BEM과 같은 일관된 방법론을 사용하면 특히 대규모 프로젝트에서 CSS를 더 쉽게 이해하고 유지 관리할 수 있습니다.
CSS 모듈 및 CSS-in-JS 라이브러리부터 BEM과 같은 명명 방법론에 이르기까지 대규모 프로젝트에서 CSS를 관리하는 방법에는 여러 가지가 있습니다. 중요한 것은 팀과 프로젝트에 잘 맞는 접근 방식을 찾고 이를 일관되게 적용하는 것입니다. CSS를 작성하는 것은 이해하고 유지 관리할 수 있는 코드를 작성하는 것만큼이나 효율적이고 성능이 뛰어난 코드를 작성하는 것과 관련이 있다는 것을 기억하세요.
즐거운 코딩하세요!