@supports 거짓말: CSS가 “예”라고 할 때 브라우저는 “LOL No”라고 말한다
Source: Dev.to
소개
CSS 사양에 따르면 @supports at‑rule은 최상위 레벨에 두거나 다른 conditional‑group at‑rule 안에 중첩해야 합니다. 하지만 브라우저는 다음과 같은 코드를 허용합니다(이론적으로는 유효하지 않음):
.my-class {
@supports (property: value) {
/* … */
}
}
이 동작은 혼란을 줍니다. 브라우저는 중첩된 @supports를 완전히 무시하거나(또는 HTML·CSS에 관대하게 동작하기 때문에 항상 실행할 수도 있음) 중첩된 규칙에 상대적으로 적용할 수 있습니다. 선택자 안에 시각적으로 중첩된 상태로 루트 레벨에 있는 것처럼 적용되는 것은 오해를 일으킬 수 있습니다.
예시
li::marker {
@supports (content: " - ") {
content: " - ";
color: red;
}
}
- Chrome, Safari, Firefox 모두
::marker를 지원하고,content: " - "도 지원합니다. - Safari는
::marker안에서content를 지원하지 않습니다.
위 코드를 사용하면:
- Chrome과 Firefox는 빨간색 “ - ”를 렌더링합니다.
- Safari는 빨간색 원을 대신 렌더링합니다.
혼란스러운 점은 @supports 조건이 해당 선언이 특정 컨텍스트에서 실제로 지원되지 않음에도 불구하고 성공한다는 것입니다.
왜 이런 일이 발생하는가
문제는 브라우저가 중첩된 @supports 규칙을 최상위 컨텍스트로 “이동”(혹은 더 정확히는 “파싱”)하는 것이 아니라, @supports 자체가 어떻게 정의되어 있는가에 있습니다. 기능 검사는 선언이 일반적으로 유효한지를 판단할 뿐, 특정 선택자나 의사 요소 컨텍스트에서 유효한지를 판단하지 않습니다.
가능한 해결책
컨텍스트 인식 검사를 지원하도록 @supports 확장
새 연산자나 함수를 도입해 @supports가 독립적인 기능이 아니라 조합을 검증하도록 합니다. 예시:
@supports selector(::marker) and (content: " - ")
또는
@supports selector(::marker) xand (content: " - ")
또는 규칙 기반 검사:
@supports rule(::marker { content: " - " })
이렇게 하면 선언이 실제로 주어진 렌더링 컨텍스트에서 동작하는지를 확인할 수 있어, 단순히 구문이 인식되는지만 검사하는 현재 방식보다 정확합니다.
브라우저의 관용성을 낮추기
덜 바람직한 접근법으로는 브라우저가 중첩된 @supports 규칙을 절대 실행하지 않게 하는 것이 있습니다. 하지만 이는 현재 관용적인 동작에 의존하고 있는 기존 코드를 깨뜨릴 수 있습니다.
우회 방법
컨테이너 쿼리와 스타일 쿼리를 우회적으로 사용할 수 있지만, 현재는 부분적인 지원만 제공되며 사용자 정의 속성만 검사할 수 있고 임의 선언은 검사하지 못합니다. 일부 경우에 도움이 되긴 하지만, 중첩된 @supports가 갖는 오해의 소지나 제한성을 완전히 없애지는 못합니다.