언어 및 도구들 공부/React

하위 컴포넌트에서 CSS가 중복 적용되지 않는 이유

Dr.Mlem 2024. 12. 3. 15:17

Q1.

궁금한게, React에서 이런 저런 컴포넌트들을 따로 만들어서, 한 군데에서 조립을 하잖아? 그런데 그 와중에, styled 컴포넌트를 통해서 설정한 CSS 값들이, 상위 컴포넌트에 있는 내용과 하위 컴포넌트에 있는 내용이 겹칠 경우, 하위 컴포넌트에서는 하위 컴포넌트에 적용되어 있는 내용이 우선적으로 적용되는건가? 내 질문한 내용이 프로그래밍적으로 부족한 점이나 잘못 알고 있는 점이 있다면 지적해줘.

 
 
 
A1.

ChatGPT의 말:

 

너의 질문은 꽤 명확하고 중요한 CSS의 동작 원리에 대한 핵심을 짚고 있어! React에서 styled-components를 사용하는 경우, 그리고 CSS의 상속 및 우선순위 관련된 동작 원리를 제대로 이해하는 게 중요해. 질문에 대해 하나씩 차근차근 답변하면서 필요한 지식을 보강해볼게.


1. React와 styled-components의 동작 구조

React 컴포넌트는 독립적이고 재사용 가능한 UI 단위를 의미하며, styled-components는 이러한 컴포넌트에 CSS를 적용하기 위한 JavaScript 기반의 라이브러리야. styled-components는 CSS-in-JS 방식으로 동작하며, 각 styled-component가 고유한 클래스명을 생성하므로 CSS 충돌을 최소화해.

하지만 상위 컴포넌트와 하위 컴포넌트에서 같은 스타일 속성이 겹칠 경우, CSS 우선순위가 어떻게 동작하는지에 따라 적용 결과가 달라져.


2. CSS 우선순위의 기본 원리

CSS는 다음과 같은 규칙에 따라 스타일 우선순위를 결정해:

  1. 명시도(Specificity): 선택자의 명시도가 높을수록 우선순위가 높아져. 예를 들어, div < .class < #id 순으로 명시도가 높아져.
  2. 소스 순서(Cascade): 명시도가 동일하다면, 뒤에 선언된 스타일이 앞선 스타일을 덮어씌움.
  3. 중첩된 컴포넌트: CSS는 더 구체적으로 선언된 스타일, 즉 하위 컴포넌트의 스타일이 우선 적용됨.

styled-components에서는 각 컴포넌트가 고유 클래스명을 가지기 때문에 명시도 충돌은 적지만, 하위 컴포넌트의 스타일이 상위 컴포넌트의 스타일을 덮어쓸 가능성이 있어.


3. 상위와 하위 컴포넌트 간 스타일 우선순위

만약 styled-components로 작성된 상위 컴포넌트와 하위 컴포넌트가 동일한 스타일 속성을 정의했다면:

  • 하위 컴포넌트가 우선 적용됨.
    • styled-components는 컴포넌트 단위로 스타일을 캡슐화하기 때문에, 하위 컴포넌트 내부에서 선언한 스타일은 상위 컴포넌트 스타일보다 구체적임.
    • 따라서 CSS 상속의 원리와 CSS 우선순위 규칙에 따라 하위 컴포넌트 스타일이 적용돼.

4. 예제 코드로 확인하기

import React from "react";
import styled from "styled-components";

// 상위 컴포넌트 스타일
const Parent = styled.div`
  background-color: blue;
  color: white;
  padding: 20px;
`;

// 하위 컴포넌트 스타일
const Child = styled.div`
  background-color: red; /* 상위 스타일 덮어씀 */
  color: yellow; /* 상위 스타일 덮어씀 */
  font-size: 18px; /* 추가 스타일 */
`;

function App() {
  return (
    <Parent>
      This is the Parent Component
      <Child>This is the Child Component</Child>
    </Parent>
  );
}

export default App;

결과:

  • Parent는 배경이 파란색, 텍스트 색상이 흰색.
  • Child는 배경이 빨간색, 텍스트 색상이 노란색으로 변경됨.

이유: Child는 독립적으로 정의된 스타일을 갖고 있으므로, styled-components의 고유 클래스명 덕분에 하위 컴포넌트 스타일이 우선 적용됨.


5. 오해할 수 있는 점

  • styled-components로 CSS를 작성하더라도 **상속(인헛릿된 스타일)**은 일부 속성에서 동작할 수 있어. 예를 들어 color와 같은 속성은 상위 컴포넌트에서 하위 컴포넌트로 상속되지만, background-color는 상속되지 않아.
  • 명시도 차이: Parent에서 특정 스타일을 강제하려면, 하위 컴포넌트의 스타일보다 높은 명시도로 설정해야 해. 예를 들어, !important를 쓰거나, 상위 컴포넌트의 스타일을 더 구체적으로 정의할 수도 있어.

6.

  • 하위 컴포넌트에서 상위 스타일을 완전히 무시하고 싶다면, all: unset 속성을 사용할 수 있어.
  • 특정 속성을 상속받고 싶다면 inherit 키워드를 사용할 수도 있어.
const Child = styled.div`
  color: inherit; /* 상위의 color를 상속받음 */
  background-color: red;
`;

이렇게 하면 유연한 스타일링이 가능해져.


마무리

너의 질문은 styled-components와 CSS 우선순위의 본질을 다룬 매우 좋은 질문이었어. 하위 컴포넌트의 스타일이 우선 적용되는 이유는 styled-components가 독립된 고유 클래스명을 생성하고, CSS의 우선순위 규칙을 따르기 때문이야. 더 궁금한 게 있으면 얼마든지 물어봐! 😊

 

 

 

Q2.

styled-components가 독립된 고유 클래스명을 생성한다는 것은 무슨 말이지? 리엑트로 작성된 페이지에 들어가는 요소들에 적용된 클래스명들에 랜덤한 문자열이 붙는 것에 대한 말인거야?

 
 
 
A2.

ChatGPT의 말:

 

맞아! 네가 말한 대로 **"styled-components가 독립된 고유 클래스명을 생성한다"**는 것은, styled-components가 자동으로 고유한 클래스명을 만들어서 충돌을 방지한다는 것을 의미해.

React 프로젝트에서 styled-components를 사용하면, 우리가 작성한 CSS 코드가 고유한 식별자를 가진 클래스명으로 변환돼. 이를 통해 다른 컴포넌트나 CSS 파일에서 같은 이름의 클래스명이 존재하더라도 스타일 충돌이 발생하지 않아.


styled-components의 클래스명 생성 원리

styled-components는 작성한 스타일 코드를 고유한 해시(hash)값으로 변환해, 브라우저 DOM에 랜덤하게 보이는 클래스명을 생성해. 예를 들어, 다음과 같은 코드가 있다고 가정해보자:

import styled from 'styled-components';

const Button = styled.button`
  background-color: blue;
  color: white;
  padding: 10px;
  border-radius: 5px;
`;

function App() {
  return <Button>Click Me</Button>;
}

export default App;

컴파일된 결과:

styled-components는 Button에 대해 브라우저에서 사용할 고유 클래스명을 생성하고, 해당 스타일을 <style> 태그에 주입해:

<button class="sc-a12345">Click Me</button>

그리고 CSS는 다음과 같이 변환됨:

.sc-a12345 {
  background-color: blue;
  color: white;
  padding: 10px;
  border-radius: 5px;
}

왜 이렇게 랜덤한 문자열을 사용하나요?

  1. 고유성 보장:
    • 프로젝트가 커질수록 다른 컴포넌트나 외부 라이브러리에서 비슷한 이름의 클래스명이 생성될 가능성이 커져. 하지만 styled-components는 컴포넌트마다 고유한 클래스명을 생성하기 때문에 이런 충돌을 방지할 수 있어.
  2. 이름 충돌 방지:
    • 예를 들어, 두 파일에서 button이라는 클래스명을 정의했을 때, 전통적인 CSS에서는 스타일이 엉켜버릴 가능성이 있어. 하지만 styled-components는 클래스명에 랜덤 해시를 붙이므로 이런 충돌이 발생하지 않아.
  3. 컴포넌트 캡슐화:
    • 클래스명이 컴포넌트에 종속되므로, 해당 컴포넌트 외부에서는 접근할 수 없게 돼. 즉, 스타일이 해당 컴포넌트의 스코프에 한정돼 캡슐화된 상태로 동작해.

고유 클래스명 생성 방식

styled-components가 생성하는 클래스명은 컴포넌트의 스타일 내용과 컴포넌트 이름을 기반으로 해시를 생성해 만들기 때문에, 동일한 스타일과 컴포넌트 이름을 가진다면 동일한 해시가 만들어져.

하지만 기본적으로 이런 랜덤 클래스명은 내부적으로 처리되므로, 개발자는 스타일 작성에만 집중하면 돼.


개발 모드에서 디버깅을 쉽게 하기 위한 클래스명

개발 중에는 styled-components가 생성하는 클래스명이 고유성을 유지하면서도 디버깅에 도움이 되는 이름을 포함할 수 있어. 예를 들어, 위의 코드에서 Button 컴포넌트를 사용하면, 개발 모드에서는 클래스명이 다음과 같이 더 직관적으로 보일 수 있어:

<button class="Button-sc-a12345">Click Me</button>

이를 활성화하려면 styled-components의 babel-plugin-styled-components를 설치하고 설정하면 돼.

설치:

npm install --save-dev babel-plugin-styled-components

설정:

.babelrc 또는 babel.config.js 파일에 추가:

{
  "plugins": ["babel-plugin-styled-components"]
}

이렇게 하면 개발 중 디버깅하기 훨씬 쉬워져.


요약

  • styled-components는 CSS 클래스명을 고유한 해시로 변환해 스타일 충돌을 방지.
  • 클래스명은 컴포넌트 이름과 스타일 내용을 기반으로 생성되며, 캡슐화된 스코프를 제공.
  • 개발 모드에서는 더 직관적인 클래스명을 보여주는 디버깅 설정을 활성화할 수 있음.

추가로 styled-components의 내부 동작이나 더 깊은 내용이 궁금하다면 언제든 질문해줘! 😊