붉은거위 노트 (redgoose note)

CSS 속성 오버라이딩에 대하여..

Nest
Development
Category
html/css
Hit
30
Star
0

css 클래스 이름이 중복되어 속성이 덮어씌어지는 현상들(충돌이라고도 한다)은 css 작성을 해보면 언제가 겪게되는 문제들이다.
경험적으로 겪어보고 나름대로 대응해오고 있었는데 이것에 대하여 포스트를 작성해보고자 작성한다.

과거에 엘리먼트 셀렉터에 관한 포스트를 정리해둔적이 있었다.
https://note.redgoose.me/article/1756/

선택자에 의하여 스타일시트 속성이 덮어씌어지고 적용되는 현상은 자연스러운 일이다.
하지만 웹 개발의 방식이 복잡해지고, 효율화에 의하여 html 요소를 모듈화로 사용하는 경향이 많이 늘어났다. 그러다보니 원치않은 셀렉터가 겹치면서 속성 오버라이딩 문제를 많이 겪게된다.

처음 html/css 로 코드를 작성하기 시작하는 시절에는 그저 적당히 이름을 피하는데 급급했고, 셀렉터를 일부러 깊이 들어가고 재사용을 하는 요소들이 적은 편이었다. 그저 클래스 이름이나 아이디를 복잡하게 붙여 서로 충돌을 피하는 수밖에 없었고, 어떤 셀렉터가 우선인지와 !important 키워드를 많이 사용하였다.
정말로 다음과 같은 모습으로 css를 작성해왔다.

.head-area .table td b { display: block; font-size: 14px; font-weight: 800;  }
.head-area .table td span { display: block; font-size: 12px; }

시간이 흐르면서 이를 해소하기 위한 생태계의 노력은 지속적으로 이루어지고 이에대한 기술은 몇가지 사용해보게 되었다.

프리픽스 (prefix)

클래스 모듈 앞에다 대표적인 글자를 앞에다 붙이는 방식이다.

.fix-grid {}
.fix-table {}

위와같이 name-를 붙이는데 보통 제작자의 상징화하는 별명같은걸 주로 붙이며 길어질수록 전체적인 라인수나 바이트수가 늘어나기 때문에 최대한 짧게 만든다.
과거에 나도 .rg-table {} 같은 형식으로 만들어 사용했었다.

외부에서 중복으로 사용될 가능성을 낮추기위한 작은 편법 중 하나일 뿐이다.

클래스 이름의 모듈화 (BEM)

예제로 이해하는 BEM
https://naradesign.github.io/bem-by-example.html

css 클래스 이름 네이밍 기법중 하나인데 우연히 알게되었고 다른 방식과 비교하여 마음에 들어 현재까지 버릇같이 사용하는 방식이다.

.(블록)__(엘리먼트)--(모디파이어) 형식으로 사용하는 BEM 방식은 요소를 모듈화 시키는 방식에서는 대단히 어울린다. 모듈의 이름이 되는 블록, 그 하위의 요소는 엘리먼트, 요소의 개성을 표현하는 모디파이어로 상당히 합리적으로 네이밍을 할 수 있었다.
이렇게 대표적인 블록 이름을 시작하여 셀렉터가 .block .element.modifier 형태같이 깊이 들어가지 않아도 하나의 셀렉터로 속성을 넣을 수 있다. 이렇게 --, __ 같은 문자를 결합하여 단독으로 사용할 수 있는 셀렉터 이름의 가짓수를 많이 늘릴 수 있게되었다.

<!-- 'menu'와 'list' 단어를 사용한다. -->
<nav class="menu">
  <ul class="list"></ul>
</nav>
<style>
.menu {}
.menu .list {}
</style>

<!-- 'menu'만 사용함으로써 다른곳에서 'list' 단어를 사용할 수 있다. -->
<nav class="menu">
  <ul class="menu__list"></ul>
</nav>
<style>
.menu {}
.menu__list {}
</style>

위 예제처럼 사용하는 키워드 수를 줄임으로써 다른 키워드 사용에 대한 부담을 줄일 수 있다.

scoped

최초에 어디에서 만들어졌는지는 모르겠지만 vue, svelte 를 사용하면서 알게된 방식이다. vue는 <style scoped>를 사용하면 활성화되고, svelte는 기본으로 사용한다.

각 프레임워크마다 변환하는 모습이 다르지만 scoped css 로 작성하면 다음과 같이 독립적인 스타일시트 선택자를 만들어 중복 사용을 원천적으로 차단한다.

vue로 사용했을때의 예제

<!-- source -->
<p class="text">message</p>
<style scoped>
.text {}
</style>

<!-- result -->
<p class="text" data-v-f3f3fdk>message</div>
<style>
.text[data-v-f3f3fdk] {}
</style>

소스와 결과물의 차이를 보면 속성에 data-v-{RANDOM} 형식의 값을 붙이고 선택자를 [data-v-{RANDOM}] 모습으로 사용하고 있다.
이것으로 강력한 셀렉터를 사용할 수 있게 되었지만 이 방식을 사용하려면 트랜스파일러를 통하거나 자바스크립트로 변환과 해석이 꼭 필요해진다.

custom elements

마지막으로 커스터마이즈한 html 엘리먼트를 직접 만들어 사용할 수 있는데 자바스크립트 class 로 만든다.

선택사항이지만 엘리먼트를 폐쇄적으로 만들 수 있다. 폐쇄적이라함은 커스텀 엘리먼트의 내부에다 스타일시트 선택자로 접근할 수 없기 때문에 클래스 내부에서 스타일 속성을 조정할 수 있다.

지나치게 폐쇄적이라서 UI 커스터마이즈가 불가능해져 유연한 모듈을 만들 수 없을까 생각했지만 아주 방법이 없는것은 아니었다.
css variable로 속성값을 오버라이딩 할 수 있음을 알게된 이후로 내부에서 특정 값을 받아들일 준비를 해두고 css 변수값으로 속성을 제어하는 방식으로 사용하고 있다.

대략적이인 예제는 다음과 같다.

<custom-element>
  <p class="message"></p>
  <style>
  .message { color: var(--color, red); }
  </style>
</custom-element>

<style>
custom-element { --color: blue }
</style>

커스텀 엘리먼트를 처음 접할때는 대단히 폐쇄적이라서 많이 당황했지만 조금씩 활용법을 알아가면서 조금씩 활용하기 시작했다.
하지만 개발과 배포의 문제에서 여전히 좋은 해법을 못찾고 있다는것이 아쉬울 따름이다.

마무리

주로 html/css 작업을 많이 해오다보니 많은 시행착오를 겪어보는 부분이긴한데 점점 더 좋은 방법이 등장하면서 마크업의 난이도가 낮아지는듯 하면서 복잡해지고 있는듯한 인상을 많이 받는다.

점점 css를 자바스크립트와 결합시키는 방법론이 많이 생기고 있다.
이것이 좋은지는 명확하게 판단은 안되고 개인적으로 한계가 분명하게 느껴지고 코드 가동성이 취향에 안맞아서 관심을 안두는 결정적인 이유이기도 하다.

왠만하면 여전히 순수한 HTML/CSS 모습에서 코드를 작성하는것을 선호하기에..