cascade가 뭔가 ? twMerge는 뭘 해결해주는가?
왜 "px-2 py-2 p-3" 은 px-2 py-2를 먼저 적용시키는가?
=> 명시도 때문. 셀렉터가 가리키는것이 명확할수록 우선순위를 높게 준다. 모호하게 여러개를 가리키는 셀렉터보다 보다 적은 범위를 명확하게 가리키는 셀렉터 스타일의 우선순위가 높다. 여기에서는 p-3은 top bottom left right를 일괄로 지정하고, px-2 py-2는 top과 bottom과 left right를 골라서 지정한다. 그러면 후자가 더 명확하게 가리키고 있다고 할 수 있을것이다.
그러면 p-2 p-4라면? p-4가 적용된다.
=> 왜냐? 코드 순서 우선순위 때문. 우선순위의 마지막 요소가 코드 순서인데, 가장 마지막에 등장한 속성을 최우선으로 적용한다는 것이다. 위에서는 상위 우선순위의 비교 결과가 같았으므로 그 다음 우선순위를 비교하는데, p-4가 더 뒤에 적혀있기 때문에 p-4가 적용된다.(하 ㅅㅂ 이것도 아님 attribute 내에서 순서가 중요한게 아니고 테일윈드가 css파일 내부에서 만드는 순서랑 상관있는거임 p-4 p-2 p-3을 하면? p-3이 적용될 것 같지? p-2가 적용됨 ㅋㅋ 왜냐고? 잘 모르겠음 그냥 오름차순도 아니고 무슨기준인지를 모르겠음 pl-4 pl-8 pl-2 pl-6 하면 ? pl-2가 적용됨. 2를 빼면? 8이 적용됨. p-4 p-3은? p-4가 적용됨 p-3 p-4는? 이것도 p-4가 적용됨. 어쩌라는건지 ㅠ 파일이 남아있어서 그런건가.. 그리고 px보단 py가 먼저고 py px보단 p가 먼저다. pl보단 px가 먼저다. where a more specific style will always win out over a less specific one.
CSS Structure and Rules
! important Rules can be designated as important by specifying ! important. A style that is designated as important will win out over contradictory styles of otherwise equal weight. Likewise, since both author and reader may specify important rules, the a
htmlhelp.com
이 말만 보면 pl <- px <- p 순서인건 납득가능함 더 명확한걸 뒤로 보내고있음. 그렇게 해서 last rule specified wins를 적용시켜서 우선순위를 적용하고 있는 것 같음. 근데 문제점은 어디에도 같은 속성 내에서의 specificity를 계산하는 법은 나와있지 않다는거다. tailwindcss도 cascading rule을 따른다는데 뭐가 기준인건지? 자기들 맘대로인지? inline <-> id <-> class <-> tag 사이에서 점수를 계산하는 법은 알겠는데 inline 내부에서 충돌하면요? 그건 왜안알려주세요 ㅠ https://stackoverflow.com/questions/76365575/how-does-the-css-cascade-algorithm-work-with-tailwind-classes 아니 그래서 어떻게 동작하는지는 아무도 댓글에 안적어놓음 ㅋㅋㅋ 모르나봄 자기들도!! 마지막에 위치한걸 적용하는건 알겠는데 그걸 무슨 순서로 정하냐고요~~ 아시는분?)
그러면 px-2만 주면 어떻게 되지? px-2 p-4의 결과는? p-4가 전부 적용되나? left right는 px-2가 적용되고 py는 4가 적용되나?
=> left right는 px-2가 적용되고 p-4는 적용되지 않는다.
(그러면 px-2 py-2 pl-1은 어떨까??) => pl-1이 적용된다. p-4는 우선순위가 더 낮지만 pl-1은 우선순위가 더 높다.
그래서 twMerge를 왜 쓰나?
이런 버튼 컴포넌트가 있다고 하자.
<Button size="sm"> ... <Button/>
이 버튼 컴포넌트는 재사용 가능 및 사용하기 편리하게 만들기 위해 HTMLButtonElement를 상속받았고 size: "sm" | lg" 등 variants들이 존재한다. sm은 "h-9 px-2 py-2"로 설정되어있다. 그런데 패딩만 바꾸고싶다. 그래서 이런 코드를 썼다.<Button size="sm" className="p-4"> ... </Button>twMerge가 없으면? 앞에 더 명확한 셀렉터가 있기 때문에 원하는 p-3 속성은 적용되지 않는다.
twMerge를 쓰면? px-2 py-2를 없애고 의도한 p-4만 남아있도록 해준다.
그러면 그냥 버튼 컴포넌트를 구현할 때 className props가 있으면 인자로 받은 className 순서를 맨 앞으로 하면 되는거 아닌가?
두둥. 그래도 p-4는 적용 되지 않는다. 왜냐? px-2 py-2가 우선순위가 더 높으니까. p-4 px-2 pl-8 이렇게 하면? pl-8 pr-2가 되고 py는 적용되지 않는다. 왜지? (하.. px-1 py-1을 그대로 넣어놨으니까 그렇지 다시다시)
그래서 twMerge를 쓰는걸까? 클래스가 복잡해질수록 결과를 예측하기 어렵다. 그렇다고 cascading을 다 외우기에는 너무 복잡하다. 정해진 규칙에 따라 동작한다면 일관성을 보장할 수 있다. p-4 px-2 pl-8은 refinement는 허용한다는 규칙에 따라 y축 패딩은 4, pl-8, pr-2라는 결과를 줄 것이다. 결과는? 예상과 일치한다.
또다른 이유는? twMerge는 overriding을 가능하게 해준다고 설명하고있다. 여기서의 overriding이란? ("p-3", "px-2 py-2") vs ("px-2 py-2", "p-3"). 왜 p-3을 없애고 px-2 py-2를 덮어쓰는건 override라고 하지 않는걸까?(아니 애초에 그런 동작을 하지도 않는다.) p-3 px-2 py-2는 이 상태로도 우선순위가 충돌하지 않기 때문이다. 자명하다고 할 수 있다. 그런데 px-2 py-2 p-3은? 코드순서 우선순위와 명시성 우선순위가 충돌한다. 코드 순서로는 p-3이 높고 명시성은 p-3이 낮다. px-2 py-2는 명시성은 높고 코드순서는 낮다. 그러면 원래대로라면 명시성이 더 상위에 있는 우선순위이기 때문에 px-2 py-2를 따르게 되는데 twMerge를 쓰면 p-3만이 남아있게된다. 왜 resolve non-trivial conflict의 방향이 우선순위가 낮은 것이 높은것을 덮어쓰는쪽이 되는걸까?