CSS 사용자 정의 속성에 대한 전략 가이드
게시 됨: 2022-03-10CSS 사용자 정의 속성('CSS 변수'라고도 함)은 이제 모든 최신 브라우저에서 지원되며 사람들은 프로덕션 환경에서 이를 사용하기 시작했습니다. 이것은 훌륭하지만 전처리기의 변수와 다르며 어떤 이점을 제공하는지 고려하지 않고 사용하는 사람들의 많은 예를 이미 보았습니다.
사용자 정의 속성은 CSS를 작성하고 구조화하는 방법과 JavaScript를 사용하여 UI 구성 요소와 상호 작용하는 방법을 변경할 수 있는 엄청난 잠재력을 가지고 있습니다. 나는 구문과 작동 방식에 초점을 맞추지 않을 것입니다(이를 위해 "사용자 정의 속성 사용을 시작할 때입니다"를 읽는 것이 좋습니다). 대신 CSS 사용자 정의 속성을 최대한 활용하기 위한 전략을 더 자세히 살펴보고 싶습니다.
전처리기의 변수와 어떻게 유사합니까?
사용자 정의 속성은 전처리기의 변수와 약간 비슷하지만 몇 가지 중요한 차이점이 있습니다. 첫 번째이자 가장 분명한 차이점은 구문입니다.
SCSS
에서는 달러 기호를 사용하여 변수를 나타냅니다.
$smashing-red: #d33a2c;
Less에서는 @
기호를 사용합니다.
@smashing-red: #d33a2c;
사용자 정의 속성은 유사한 규칙을 따르고 --
접두사를 사용합니다.
:root { --smashing-red: #d33a2c; } .smashing-text { color: var(--smashing-red); }
전처리기에서 사용자 정의 속성과 변수 간의 중요한 차이점 중 하나는 사용자 정의 속성이 값을 할당하고 해당 값을 검색하는 구문이 다르다는 것입니다. 사용자 정의 속성의 값을 검색할 때 var()
함수를 사용합니다.
다음으로 가장 분명한 차이점은 이름에 있습니다. 그것들은 실제로 CSS 속성이기 때문에 '사용자 정의 속성'이라고 합니다. 전처리기에서는 외부 선언 블록, 미디어 규칙 또는 선택기의 일부를 포함하여 거의 모든 곳에서 변수를 선언하고 사용할 수 있습니다.
$breakpoint: 800px; $smashing-red: #d33a2c; $smashing-things: ".smashing-text, .cats"; @media screen and (min-width: $breakpoint) { #{$smashing-things} { color: $smashing-red; } }
위의 대부분의 예는 사용자 정의 속성을 사용하면 유효하지 않습니다.
사용자 정의 속성에는 일반 CSS 속성으로 사용할 수 있는 위치에 대한 동일한 규칙이 있습니다. 변수보다 동적 속성으로 생각하는 것이 훨씬 낫습니다. 즉, 선언 블록 내에서만 사용할 수 있습니다. 즉, 사용자 지정 속성이 선택기에 연결됩니다. 이것은 :root
선택기 또는 다른 유효한 선택기일 수 있습니다.
:root { --smashing-red: #d33a2c; } @media screen and (min-width: 800px) { .smashing-text, .cats { --margin-left: 1em; } }
속성 선언에서 값을 사용하는 모든 위치에서 사용자 정의 속성 값을 검색할 수 있습니다. 즉, 속기 명령문의 일부로 또는 calc()
방정식 내부에서도 단일 값으로 사용할 수 있습니다.
.smashing-text, .cats { color: var(--smashing-red); margin: 0 var(--margin-horizontal); padding: calc(var(--margin-horizontal) / 2) }
그러나 미디어 쿼리나 :nth-child()
를 포함한 선택기에서는 사용할 수 없습니다.
대체 값을 사용하는 방법과 다른 변수에 변수를 할당할 수 있는 방법(예)과 같이 구문과 사용자 정의 속성이 작동하는 방식에 대해 알고 싶은 것이 더 많을 수 있지만 이 기본 소개는 나머지를 이해하기에 충분할 것입니다. 이 기사의 개념. 사용자 지정 속성의 작동 방식에 대한 자세한 내용은 Serg Hospodarets가 작성한 "사용자 지정 속성 사용을 시작할 때입니다"를 참조하십시오.
동적 대 정적
외관상의 차이점을 제외하고 전처리기의 변수와 사용자 정의 속성 사이의 가장 중요한 차이점은 범위가 어떻게 되는지입니다. 변수를 정적으로 또는 동적으로 범위를 지정할 수 있습니다. 전처리기의 변수는 정적이지만 사용자 정의 속성은 동적입니다.
CSS와 관련하여 static은 컴파일 프로세스의 다른 지점에서 변수 값을 업데이트할 수 있지만 이전에 제공된 코드 값은 변경할 수 없음을 의미합니다.
$background: blue; .blue { background: $background; } $background: red; .red { background: $background; }
결과:
.blue { background: blue; } .red { background: red; }
이것이 CSS로 렌더링되면 변수가 사라집니다. 이는 HTML, 브라우저 또는 기타 입력에 대한 정보 없이 .scss
파일을 읽고 출력을 결정할 수 있음을 의미합니다. 이것은 사용자 정의 속성의 경우가 아닙니다.
전처리기에는 선택기, 함수 또는 믹스인 내부에서 변수가 일시적으로 변경될 수 있는 일종의 "블록 범위"가 있습니다. 이렇게 하면 블록 내부의 변수 값이 변경되지만 여전히 정적입니다. 이것은 선택기가 아니라 블록에 연결됩니다. 아래 예에서 변수 $background
는 .example
블록 내에서 변경됩니다. 동일한 선택기를 사용하더라도 블록 외부의 초기 값으로 다시 변경됩니다.
$background: red; .example { $background: blue; background: $background; } .example { background: $background; }
결과:
.example { background: blue; } .example { background: red; }
사용자 정의 속성은 다르게 작동합니다. 사용자 지정 속성과 관련하여 동적으로 범위가 지정된다는 것은 해당 속성이 상속 및 캐스케이드의 대상임을 의미합니다. 속성은 선택기에 연결되며 값이 변경되면 다른 CSS 속성과 마찬가지로 일치하는 모든 DOM 요소에 영향을 줍니다.
호버와 같은 의사 선택기를 사용하거나 JavaScript를 사용하여 미디어 쿼리 내에서 사용자 정의 속성의 값을 변경할 수 있기 때문에 이것은 훌륭합니다.
a { --link-color: black; } a:hover, a:focus { --link-color: tomato; } @media screen and (min-width: 600px) { a { --link-color: blue; } } a { color: var(--link-color); }
사용자 정의 속성이 사용되는 위치를 변경할 필요가 없습니다. CSS를 사용하여 사용자 정의 속성의 값을 변경합니다. 이것은 동일한 사용자 정의 속성을 사용하여 동일한 페이지의 다른 위치 또는 컨텍스트에서 다른 값을 가질 수 있음을 의미합니다.
글로벌 대 로컬
변수는 정적이거나 동적일 뿐만 아니라 전역 또는 지역일 수도 있습니다. 자바스크립트를 작성해보시면 이 부분에 익숙하실 것입니다. 변수는 응용 프로그램 내부의 모든 것에 적용하거나 범위를 특정 기능이나 코드 블록으로 제한할 수 있습니다.
CSS도 비슷합니다. 우리는 전 세계적으로 적용되는 것과 더 지역적으로 적용되는 것이 있습니다. 브랜드 색상, 세로 간격 및 타이포그래피는 모두 웹사이트 또는 애플리케이션 전반에 걸쳐 일관되게 전역적으로 적용되기를 원하는 항목의 예입니다. 현지 물건도 있습니다. 예를 들어 버튼 구성 요소에는 크고 작은 변형이 있을 수 있습니다. 이러한 버튼의 크기가 모든 입력 요소 또는 페이지의 모든 요소에 적용되는 것을 원하지 않을 것입니다.
이것은 CSS에서 우리에게 익숙한 것입니다. 우리는 디자인 시스템, 명명 규칙 및 JavaScript 라이브러리를 개발했으며 모두 로컬 구성 요소와 글로벌 디자인 요소를 분리하는 데 도움이 됩니다. 사용자 정의 속성은 이 오래된 문제를 처리하기 위한 새로운 옵션을 제공합니다.
CSS 사용자 정의 속성은 기본적으로 우리가 적용하는 특정 선택기로 로컬 범위입니다. 그래서 그것들은 지역 변수와 비슷합니다. 그러나 사용자 정의 속성도 상속되므로 많은 상황에서 전역 변수처럼 작동합니다. 특히 :root
선택기에 적용될 때 그렇습니다. 이것은 우리가 그것들을 사용하는 방법에 대해 생각할 필요가 있음을 의미합니다.
많은 예제가 :root
요소에 적용되는 사용자 정의 속성을 보여줍니다. 데모에서는 괜찮지만 전체 범위가 지저분하고 상속과 관련된 의도하지 않은 문제가 발생할 수 있습니다. 운 좋게도 우리는 이미 이러한 교훈을 배웠습니다.
전역 변수는 정적인 경향이 있습니다.
몇 가지 작은 예외가 있지만 일반적으로 CSS의 대부분의 전역 항목도 정적입니다.
브랜드 색상, 타이포그래피 및 간격과 같은 전역 변수는 한 구성 요소에서 다음 구성 요소로 크게 변경되지 않는 경향이 있습니다. 그들이 변경되면 이는 글로벌 리브랜딩 또는 성숙한 제품에서 거의 발생하지 않는 기타 중요한 변경이 되는 경향이 있습니다. 이러한 것들이 변수라는 것은 여전히 의미가 있고 많은 곳에서 사용되며 변수는 일관성을 유지하는 데 도움이 됩니다. 그러나 그것들이 역동적이라는 것은 말이 되지 않습니다. 이러한 변수의 값은 동적으로 변경되지 않습니다.
이러한 이유로 전역(정적) 변수에 전처리기를 사용하는 것이 좋습니다. 이것은 항상 정적임을 보장할 뿐만 아니라 코드 내에서 시각적으로 표시합니다. 이것은 CSS를 훨씬 더 읽기 쉽고 유지 관리하기 쉽게 만들 수 있습니다.
로컬 정적 변수는 정상입니다(가끔)
전역 변수가 정적이라는 강력한 입장을 고려할 때 반사에 의해 모든 지역 변수가 동적이어야 한다고 생각할 수도 있습니다. 지역 변수가 동적인 경향이 있는 것은 사실이지만, 이것은 전역 변수가 정적인 경향만큼 강하지 않습니다.
지역적으로 정적 변수는 많은 상황에서 완벽하게 괜찮습니다. 나는 주로 개발자의 편의를 위해 구성 요소 파일에서 전처리기 변수를 사용합니다.
다양한 크기 변형이 있는 버튼 구성 요소의 고전적인 예를 고려하십시오.
내 scss
는 다음과 같이 보일 수 있습니다.
$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { // Visual styles } .btn-sml { font-size: $button-sml; } .btn-med { font-size: $button-med; } .btn-lrg { font-size: $button-lrg; }
분명히 이 예제는 변수를 여러 번 사용하거나 크기 변수에서 여백 및 패딩 값을 파생하는 경우 더 의미가 있습니다. 그러나 다양한 크기의 프로토타입을 신속하게 제작할 수 있는 능력이 충분한 이유가 될 수 있습니다.
대부분의 정적 변수는 전역적이므로 구성 요소 내부에서만 사용되는 정적 변수를 구별하는 것을 좋아합니다. 이렇게 하려면 이러한 변수에 구성 요소 이름을 접두사로 붙이거나 구성 요소의 경우 c-variable-name
또는 로컬의 경우 l-variable-name
과 같은 다른 접두사를 사용할 수 있습니다. 원하는 접두사를 사용하거나 전역 변수에 접두사를 붙일 수 있습니다. 무엇을 선택하든 사용자 지정 속성을 사용하도록 기존 코드베이스를 변환하는 경우 특히 차별화하는 것이 좋습니다.
사용자 정의 속성을 사용하는 경우
구성 요소 내에서 정적 변수를 사용하는 것이 괜찮다면 언제 사용자 정의 속성을 사용해야 합니까? 기존 전처리기 변수를 사용자 정의 속성으로 변환하는 것은 일반적으로 거의 의미가 없습니다. 결국 사용자 정의 속성의 이유는 완전히 다릅니다. 사용자 정의 속성은 DOM의 조건, 특히 :focus
, :hover
, 미디어 쿼리 또는 JavaScript와 같은 동적 조건과 관련하여 변경되는 CSS 속성이 있을 때 의미가 있습니다.
사용자 정의 속성이 논리와 코드를 구성하는 새로운 방법을 제공하기 때문에 앞으로 더 적게 필요할 수도 있지만 항상 정적 변수 형식을 사용할 것이라고 생각합니다. 그때까지는 대부분의 상황에서 전처리기 변수와 사용자 정의 속성의 조합으로 작업할 것이라고 생각합니다.
사용자 정의 속성에 정적 변수를 할당할 수 있다는 것을 아는 것이 도움이 됩니다. 전역적이든 지역적이든 정적 변수를 로컬 동적 사용자 정의 속성으로 변환하는 것은 많은 상황에서 의미가 있습니다.
참고 : $var
가 사용자 정의 속성에 유효한 값이라는 것을 알고 계셨습니까? 최신 버전의 Sass는 이를 인식하므로 #{$var}
와 같이 사용자 정의 속성에 할당된 변수를 보간해야 합니다. 이것은 Sass에게 스타일시트에 $var
가 아닌 변수의 값을 출력하기를 원한다는 것을 알려줍니다. 이것은 변수 이름이 유효한 CSS가 될 수 있는 사용자 정의 속성과 같은 상황에서만 필요합니다.
위의 버튼 예제를 사용하여 HTML에 적용된 클래스에 관계없이 모든 버튼이 모바일 장치에서 약간의 변형을 사용해야 한다고 결정하면 이것은 이제 더 동적인 상황입니다. 이를 위해 사용자 정의 속성을 사용해야 합니다.
$button-sml: 1em; $button-med: 1.5em; $button-lrg: 2em; .btn { --button-size: #{$button-sml}; } @media screen and (min-width: 600px) { .btn-med { --button-size: #{$button-med}; } .btn-lrg { --button-size: #{$button-lrg}; } } .btn { font-size: var(--button-size); }
여기에서 단일 사용자 정의 속성인 --button-size
만듭니다. 이 사용자 정의 속성은 처음에 btn
클래스를 사용하는 모든 버튼 요소로 범위가 지정됩니다. 그런 다음 btn-med
및 btn-lrg
클래스에 대해 --button-size
값을 600px 이상으로 변경합니다. 마지막으로 이 사용자 정의 속성을 한 곳에서 모든 버튼 요소에 적용합니다.
너무 영리하지 마십시오
사용자 정의 속성의 동적 특성으로 인해 영리하고 복잡한 구성 요소를 만들 수 있습니다.
전처리기의 도입으로 우리 중 많은 사람들이 믹스인과 사용자 정의 함수를 사용하여 영리한 추상화로 라이브러리를 만들었습니다. 제한된 경우에는 이와 같은 예가 오늘날에도 여전히 유용하지만 대부분의 경우 전처리기를 오래 사용할수록 사용하는 기능이 줄어듭니다. 오늘날 저는 정적 변수에 대해 거의 독점적으로 전처리기를 사용합니다.
사용자 지정 속성은 이러한 유형의 실험에서 면역이 되지 않으며(그렇지 않아야 하며) 많은 영리한 예를 보기를 기대합니다. 그러나 장기적으로 읽기 쉽고 유지 관리 가능한 코드는 항상 영리한 추상화(적어도 프로덕션 단계에서는)를 이깁니다.
나는 최근에 Free Code Camp Medium에서 이 주제에 대한 훌륭한 기사를 읽었습니다. Bill Sourour가 작성했으며 "Don't Do It At Runtime"이라고 합니다. 디자인 타임에 하세요.” 그의 주장을 의역하기 보다는 당신이 그것을 읽게 할 것입니다.
전처리기 변수와 사용자 지정 속성 간의 주요 차이점 중 하나는 사용자 지정 속성이 런타임에 작동한다는 것입니다. 이는 복잡성 측면에서 전처리기를 사용하여 허용 가능한 경계선이었던 것들이 사용자 정의 속성에서는 좋은 생각이 아닐 수 있음을 의미합니다.
최근에 이를 설명하는 한 가지 예는 다음과 같습니다.
:root { --font-scale: 1.2; --font-size-1: calc(var(--font-scale) * var(--font-size-2)); --font-size-2: calc(var(--font-scale) * var(--font-size-3)); --font-size-3: calc(var(--font-scale) * var(--font-size-4)); --font-size-4: 1rem; }
이것은 모듈식 스케일을 생성합니다. 모듈식 척도는 비율을 사용하여 서로 관련된 일련의 숫자입니다. 웹 디자인 및 개발에서 글꼴 크기 또는 간격을 설정하는 데 자주 사용됩니다.
이 예에서 각 사용자 정의 속성은 calc()
를 사용하여 이전 사용자 정의 속성의 값을 취하고 여기에 비율을 곱하여 결정됩니다. 이렇게 하면 눈금에서 다음 숫자를 얻을 수 있습니다.
즉, 비율은 런타임에 계산되며 --font-scale
속성 값만 업데이트하여 변경할 수 있습니다. 예를 들어:
@media screen and (min-width: 800px) { :root { --font-scale: 1.33; } }
이것은 영리하고 간결하며 스케일을 변경하려는 경우 모든 값을 다시 계산하는 것보다 훨씬 빠릅니다. 또한 프로덕션 코드에서는 하지 않을 것입니다.
위의 예는 프로토타이핑에 유용하지만 프로덕션에서는 다음과 같은 것을 보고 싶습니다.
:root { --font-size-1: 1.728rem; --font-size-2: 1.44rem; --font-size-3: 1.2em; --font-size-4: 1em; } @media screen and (min-width: 800px) { :root { --font-size-1: 2.369rem; --font-size-2: 1.777rem; --font-size-3: 1.333rem; --font-size-4: 1rem; } }
Bill의 기사에 있는 예와 유사하게 실제 값이 무엇인지 확인하는 것이 도움이 됩니다. 우리는 코드를 작성하는 것보다 훨씬 더 많이 읽고 글꼴 크기와 같은 전역 값은 프로덕션에서 드물게 변경됩니다.
위의 예는 아직 완벽하지 않습니다. 전역 값은 정적이어야 한다는 이전의 규칙을 위반합니다. 전처리기 변수를 사용하고 앞에서 설명한 기술을 사용하여 로컬 동적 사용자 정의 속성으로 변환하는 것을 훨씬 선호합니다.
하나의 사용자 지정 속성을 다른 사용자 지정 속성으로 사용하는 상황을 피하는 것도 중요합니다. 이것은 우리가 이와 같은 속성의 이름을 지정할 때 발생할 수 있습니다.
변수가 아닌 값 변경
변수가 아닌 값을 변경하는 것은 사용자 정의 속성을 효과적으로 사용하기 위한 가장 중요한 전략 중 하나입니다.
일반적으로 단일 목적으로 사용되는 사용자 지정 속성을 변경해서는 안 됩니다. 이것이 바로 우리가 전처리기로 작업하는 방식이기 때문에 하기 쉽지만 사용자 정의 속성에서는 의미가 거의 없습니다.
이 예제에는 예제 구성 요소에 사용되는 두 개의 사용자 지정 속성이 있습니다. 화면 크기에 따라 --font-size-large
--font-size-small
값으로 전환합니다.
:root { --font-size-small: 1.2em; --font-size-large: 2em; } .example { font-size: var(--font-size-small); } @media screen and (min-width: 800px) { .example { font-size: var(--font-size-large); } }
이를 수행하는 더 좋은 방법은 구성 요소로 범위가 지정된 단일 사용자 정의 속성을 정의하는 것입니다. 그런 다음 미디어 쿼리나 다른 선택기를 사용하여 값을 변경합니다.
.example { --example-font-size: 1.2em; } @media screen and (min-width: 800px) { .example { --example-font-size: 2em; } }
마지막으로 한 곳에서 이 사용자 지정 속성의 값을 사용합니다.
.example { font-size: var(--example-font-size); }
이 예와 그 이전의 다른 예에서 미디어 쿼리는 사용자 정의 속성 값을 변경하는 데만 사용되었습니다. var()
문이 사용되고 일반 CSS 속성이 업데이트되는 위치가 한 곳뿐임을 알 수 있습니다.
변수 선언과 속성 선언 사이의 이러한 분리는 의도적입니다. 여기에는 여러 가지 이유가 있지만 반응형 디자인을 생각할 때 이점이 가장 분명합니다.
사용자 정의 속성이 있는 반응형 디자인
미디어 쿼리에 크게 의존할 때 반응형 디자인의 어려움 중 하나는 CSS를 구성하는 방법에 관계없이 특정 구성 요소와 관련된 스타일이 스타일시트 전체에서 조각화된다는 것입니다.
어떤 CSS 속성이 변경될지 아는 것은 매우 어려울 수 있습니다. 그래도 CSS 사용자 정의 속성은 반응형 디자인과 관련된 일부 논리를 구성하고 미디어 쿼리 작업을 훨씬 쉽게 만드는 데 도움이 됩니다.
변경되면 변수입니다
미디어 쿼리를 사용하여 변경되는 속성은 본질적으로 동적이며 사용자 정의 속성은 CSS에서 동적 값을 표현하는 수단을 제공합니다. 즉, 미디어 쿼리를 사용하여 CSS 속성을 변경하는 경우 이 값을 사용자 정의 속성에 배치해야 합니다.
그런 다음 모든 미디어 규칙, 호버 상태 또는 값 변경 방식을 정의하는 동적 선택기와 함께 이를 문서의 맨 위로 이동할 수 있습니다.
디자인에서 논리 분리
올바르게 완료되면 논리와 디자인의 분리는 미디어 쿼리가 사용자 정의 속성 값을 변경하는 데만 사용 된다는 것을 의미합니다. 반응형 디자인과 관련된 모든 논리가 문서의 맨 위에 있어야 하며 CSS에서 var()
문을 볼 때마다 이 속성이 변경된다는 것을 즉시 알 수 있습니다. CSS를 작성하는 전통적인 방법으로는 이를 한 눈에 알아볼 수 있는 방법이 없었습니다.
우리 중 많은 사람들이 다양한 상황에서 속성이 변경된 것을 머리로 추적하면서 한 눈에 CSS를 읽고 해석하는 데 매우 능숙했습니다. 나는 이것에 지쳤고, 더 이상 이 일을 하고 싶지 않다! 사용자 정의 속성은 이제 논리와 구현 간의 링크를 제공하므로 이를 추적할 필요가 없으며 이는 매우 유용합니다!
논리 접기
문서나 함수의 맨 위에 변수를 선언한다는 아이디어는 새로운 아이디어가 아닙니다. 이것은 우리가 대부분의 언어에서 하는 일이며 이제는 CSS에서도 할 수 있는 일입니다. 이러한 방식으로 CSS를 작성하면 문서의 상단과 하단의 CSS를 시각적으로 명확하게 구분할 수 있습니다. 나는 그들에 대해 이야기할 때 이러한 섹션을 구별할 방법이 필요하고 "논리적 접힘"이라는 아이디어는 내가 사용하기 시작한 은유입니다.
폴드 위에는 모든 전처리기 변수와 사용자 정의 속성이 포함됩니다. 여기에는 사용자 정의 속성이 가질 수 있는 모든 다른 값이 포함됩니다. 사용자 정의 속성이 어떻게 변경되는지 추적하기 쉬워야 합니다.
스크롤 없이 볼 수 있는 CSS는 간단하고 매우 선언적이며 읽기 쉽습니다. 현대 CSS의 미디어 쿼리 및 기타 필요한 복잡성 이전의 CSS처럼 느껴집니다.
6열 플렉스박스 그리드 시스템의 정말 간단한 예를 살펴보세요.
.row { --row-display: block; } @media screen and (min-width: 600px) { .row { --row-display: flex; } }
--row-display
사용자 정의 속성은 처음에 block
으로 설정됩니다. 600px 이상에서는 디스플레이 모드가 플렉스로 설정됩니다.
스크롤 없이 볼 수 있는 부분은 다음과 같습니다.
.row { display: var(--row-display); flex-direction: row; flex-wrap: nowrap; } .col-1, .col-2, .col-3, .col-4, .col-5, .col-6 { flex-grow: 0; flex-shrink: 0; } .col-1 { flex-basis: 16.66%; } .col-2 { flex-basis: 33.33%; } .col-3 { flex-basis: 50%; } .col-4 { flex-basis: 66.66%; } .col-5 { flex-basis: 83.33%; } .col-6 { flex-basis: 100%; }
--row-display
가 변경되는 값이라는 것을 즉시 알 수 있습니다. 처음에는 block
이므로 flex 값은 무시됩니다.
이 예제는 매우 간단하지만 나머지 공간을 채우는 유연한 너비 열을 포함하도록 확장하면 flex-grow
, flex-shrink
및 flex-basis
값을 사용자 지정 속성으로 변환해야 할 가능성이 높습니다. 이것을 시도하거나 여기에서 더 자세한 예를 볼 수 있습니다.
테마를 위한 사용자 정의 속성
저는 대부분 전역 동적 변수에 대한 사용자 정의 속성을 사용하는 것에 반대했으며, 희망적으로 사용자 정의 속성을 :root
선택기에 연결하는 것이 많은 경우에 해로운 것으로 간주된다는 것을 암시했습니다. 그러나 모든 규칙에는 예외가 있으며 사용자 지정 속성의 경우 테마입니다.
전역 사용자 지정 속성을 제한적으로 사용하면 테마를 훨씬 쉽게 지정할 수 있습니다.
테마는 일반적으로 사용자가 어떤 방식으로 UI를 사용자 정의할 수 있도록 하는 것입니다. 이것은 프로필 페이지의 색상 변경과 같은 것일 수 있습니다. 또는 더 현지화 된 것일 수 있습니다. 예를 들어 Google Keep 애플리케이션에서 메모 색상을 선택할 수 있습니다.
테마 지정에는 일반적으로 별도의 스타일시트를 컴파일하여 사용자 기본 설정으로 기본값을 재정의하거나 각 사용자에 대해 다른 스타일시트를 컴파일하는 작업이 포함됩니다. 이 두 가지 모두 어려울 수 있으며 성능에 영향을 미칩니다.
사용자 정의 속성을 사용하면 다른 스타일시트를 컴파일할 필요가 없습니다. 사용자의 기본 설정에 따라 속성 값만 업데이트하면 됩니다. 그것들은 상속된 값이기 때문에 루트 요소에서 이 작업을 수행하면 애플리케이션의 어느 곳에서나 사용할 수 있습니다.
글로벌 동적 속성 활용
사용자 지정 속성은 대소문자를 구분하며 대부분의 사용자 지정 속성은 로컬이므로 전역 동적 속성을 사용하는 경우 대문자로 표시하는 것이 좋습니다.
:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); }
변수의 대문자는 종종 전역 상수를 의미합니다. 우리에게 이것은 속성이 응용 프로그램의 다른 곳에 설정되어 있으며 로컬에서 변경해서는 안 된다는 의미입니다.
전역 동적 속성을 직접 설정하지 않기
사용자 정의 속성은 대체 값을 허용합니다. 전역 사용자 지정 속성 값을 직접 덮어쓰는 것을 피하고 사용자 값을 별도로 유지하는 것이 유용할 수 있습니다. 이를 위해 fallback 값을 사용할 수 있습니다.
위의 예는 --THEME-COLOR
값이 존재하는 경우 --user-theme-color
값으로 설정합니다. --user-theme-color
가 설정되지 않은 경우 #d33a2c
값이 사용됩니다. 이렇게 하면 --THEME-COLOR
를 사용할 때마다 대체를 제공할 필요가 없습니다.
아래 예에서 배경이 green
으로 설정될 것으로 예상할 수 있습니다. 그러나 루트 요소에 --user-theme-color
값이 설정되지 않았으므로 --THEME-COLOR
값이 변경되지 않았습니다.
:root { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); }
이와 같이 전역 동적 속성을 간접적으로 설정하면 로컬에서 덮어쓰지 않도록 보호하고 사용자 설정이 항상 루트 요소에서 상속되도록 합니다. 이것은 테마 값을 보호하고 의도하지 않은 상속을 방지하는 데 유용한 규칙입니다.
특정 속성을 상속에 노출하려는 경우 :root
선택기를 *
선택기로 바꿀 수 있습니다.
* { --THEME-COLOR: var(--user-theme-color, #d33a2c); } body { --user-theme-color: green; background: var(--THEME-COLOR); }
이제 --THEME-COLOR
값이 모든 요소에 대해 다시 계산되므로 --user-theme-color
의 로컬 값을 사용할 수 있습니다. 즉, 이 예제의 배경색은 green
입니다.
사용자 정의 속성으로 색상 조작 섹션에서 이 패턴의 더 자세한 예를 볼 수 있습니다.
JavaScript로 사용자 정의 속성 업데이트
JavaScript를 사용하여 사용자 정의 속성을 설정하려는 경우 상당히 간단한 API가 있으며 다음과 같습니다.
const elm = document.documentElement; elm.style.setProperty('--USER-THEME-COLOR', 'tomato');
여기에서 document 요소, 즉 모든 요소가 상속할 :root
요소에 --USER-THEME-COLOR
값을 설정합니다.
이것은 새로운 API가 아닙니다. 요소의 스타일을 업데이트하는 것과 동일한 JavaScript 방법입니다. 이들은 인라인 스타일이므로 일반 CSS보다 더 높은 특수성을 갖습니다.
즉, 로컬 사용자 지정을 쉽게 적용할 수 있습니다.
.note { --note-color: #eaeaea; } .note { background: var(--note-color); }
여기에서 --note-color
의 기본값을 설정하고 이 범위를 .note
구성 요소로 지정합니다. 이 간단한 예에서도 변수 선언을 속성 선언과 별도로 유지합니다.
const elm = document.querySelector('#note-uid'); elm.style.setProperty('--note-color', 'yellow');
그런 다음 .note
요소의 특정 인스턴스를 대상으로 지정하고 해당 요소에 대해서만 --note-color
사용자 정의 속성 값을 변경합니다. 이제 기본값보다 더 높은 특이성을 갖게 됩니다.
React를 사용하여 이 예제에서 이것이 어떻게 작동하는지 확인할 수 있습니다. 이러한 사용자 기본 설정은 로컬 저장소에 저장하거나 더 큰 응용 프로그램의 경우 데이터베이스에 저장할 수 있습니다.
사용자 정의 속성으로 색상 조작하기
16진수 값 및 명명된 색상 외에도 CSS에는 rgb()
및 hsl()
) 과 같은 색상 기능이 있습니다. 이를 통해 색조 또는 밝기와 같은 색상의 개별 구성 요소를 지정할 수 있습니다. 사용자 정의 속성은 색상 기능과 함께 사용할 수 있습니다.
:root { --hue: 25; } body { background: hsl(var(--hue), 80%, 50%); }
이것은 유용하지만 전처리기에서 가장 널리 사용되는 기능 중 일부는 밝게, 어둡게 또는 채도 감소와 같은 기능을 사용하여 색상을 조작할 수 있는 고급 색상 기능입니다.
darken($base-color, 10%); lighten($base-color, 10%); desaturate($base-color, 20%);
브라우저에 이러한 기능 중 일부가 있으면 유용할 것입니다. 그것들은 오고 있지만 CSS에 기본 색상 수정 기능이 있을 때까지 사용자 정의 속성은 그 간극의 일부를 채울 수 있습니다.
rgb()
및 hsl()
) 과 같은 기존 색상 함수 내에서 사용자 정의 속성을 사용할 수 있지만 calc()
에서도 사용할 수 있음을 보았습니다. 이는 실수를 곱하여 백분율로 변환할 수 있음을 의미합니다(예: calc(50 * 1%)
= 50%
).
:root { --lightness: 50; } body { background: hsl(25, 80%, calc(var(--lightness) * 1%)); }
밝기 값을 실수로 저장하려는 이유는 백분율로 변환하기 전에 calc
로 조작할 수 있기 때문입니다. 예를 들어 색상을 20%
어둡게 하려면 밝기에 0.8
을 곱하면 됩니다. 밝기 계산을 로컬 범위의 사용자 정의 속성으로 분리하여 이것을 조금 더 읽기 쉽게 만들 수 있습니다.
:root { --lightness: 50; } body { --lightness: calc(var(--lightness * 0.8)); background: hsl(25, 80%, calc(var(--lightness) * 1%)); }
더 많은 계산을 추상화하고 사용자 정의 속성을 사용하여 CSS에서 색상 수정 기능과 같은 것을 만들 수도 있습니다. 이 예제는 테마를 지정하는 대부분의 경우에 너무 복잡할 수 있지만 동적 사용자 지정 속성의 모든 기능을 보여줍니다.
테마 단순화
사용자 지정 속성을 사용할 때의 장점 중 하나는 테마를 단순화할 수 있다는 것입니다. 응용 프로그램은 사용자 지정 속성이 사용되는 방식을 알 필요가 없습니다. 대신 JavaScript 또는 서버 측 코드를 사용하여 사용자 정의 속성 값을 설정합니다. 이러한 값이 사용되는 방식은 스타일시트에 의해 결정됩니다.
이것은 다시 한번 우리가 디자인과 논리를 분리할 수 있다는 것을 의미합니다. 기술 디자인 팀이 있는 경우 작성자는 JavaScript 또는 백엔드 코드를 한 줄도 변경하지 않고 스타일시트를 업데이트하고 사용자 정의 속성을 적용하는 방법을 결정할 수 있습니다.
사용자 정의 속성을 사용하면 테마의 복잡성 중 일부를 CSS로 이동할 수 있으며 이러한 복잡성은 CSS의 유지 관리 가능성에 부정적인 영향을 미칠 수 있으므로 가능한 한 단순하게 유지해야 합니다.
오늘 사용자 정의 속성 사용하기
IE10 및 11을 지원하는 경우에도 오늘부터 사용자 지정 속성을 사용할 수 있습니다. 이 기사의 대부분의 예제는 CSS를 작성하고 구성하는 방법과 관련이 있습니다. 이점은 유지 관리 측면에서 중요하지만 대부분의 예제는 더 복잡한 코드로 수행할 수 있는 작업을 줄입니다.
나는 postcss-css-variables라는 도구를 사용하여 사용자 정의 속성의 대부분의 기능을 동일한 코드의 정적 표현으로 변환합니다. 다른 유사한 도구는 미디어 쿼리 또는 복잡한 선택기 내부의 사용자 정의 속성을 무시하고 사용자 정의 속성을 전처리기 변수와 매우 유사하게 취급합니다.
이러한 도구가 할 수 없는 것은 사용자 정의 속성의 런타임 기능을 에뮬레이트하는 것입니다. 즉, JavaScript로 속성을 변경하거나 테마를 지정하는 것과 같은 동적 기능이 없습니다. 이것은 많은 상황에서 괜찮을 수 있습니다. 상황에 따라 UI 사용자 정의는 점진적 개선으로 간주될 수 있으며 기본 테마는 이전 브라우저에서 완벽하게 수용될 수 있습니다.
올바른 스타일시트 로드
postCSS를 사용하는 방법에는 여러 가지가 있습니다. 저는 gulp
며 최신 및 구형 브라우저에 대해 별도의 스타일시트를 컴파일합니다. 내 gulp
작업의 단순화 된 버전은 다음과 같습니다.
import gulp from "gulp"; import sass from "gulp-sass"; import postcss from "gulp-postcss"; import rename from "gulp-rename"; import cssvariables from "postcss-css-variables"; import autoprefixer from "autoprefixer"; import cssnano from "cssnano"; gulp.task("css-no-vars", () => gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssvariables(), cssnano()])) .pipe(rename({ extname: ".no-vars.css" })) .pipe(gulp.dest("./dist/css")) ); gulp.task("css", () => gulp .src("./src/css/*.scss") .pipe(sass().on("error", sass.logError)) .pipe(postcss([cssnano()])) .pipe(rename({ extname: ".css" })) .pipe(gulp.dest("./dist/css")) );
그 결과 두 개의 CSS 파일이 생성됩니다. 하나는 사용자 정의 속성이 있는 일반 파일( styles.css
)이고 다른 하나는 이전 브라우저용( styles.no-vars.css
)입니다. IE10 및 11에서 styles.no-vars.css
를 제공하고 다른 브라우저에서 일반 CSS 파일을 가져오길 원합니다.
일반적으로 기능 쿼리 사용을 지지하지만 IE11은 기능 쿼리를 지원하지 않으며 사용자 지정 속성을 너무 광범위하게 사용하여 이 경우 다른 스타일시트를 제공하는 것이 합리적입니다.
지능적으로 다른 스타일시트를 제공하고 스타일이 지정되지 않은 콘텐츠의 플래시를 피하는 것은 간단한 작업이 아닙니다. 사용자 지정 속성의 동적 기능이 필요하지 않은 경우 모든 브라우저 styles.no-vars.css
를 제공하고 사용자 지정 속성을 개발 도구로 사용하는 것을 고려할 수 있습니다.
사용자 정의 속성의 모든 동적 기능을 최대한 활용하려면 중요한 CSS 기술을 사용하는 것이 좋습니다. 이러한 기술을 따르면 주요 CSS가 인라인으로 렌더링되는 동안 기본 스타일시트가 비동기식으로 로드됩니다. 페이지 헤더는 다음과 같을 수 있습니다.
<head> <style> /* inlined critical CSS */ </style> <script> loadCSS('non-critical.css'); </script> </head>
브라우저가 사용자 정의 속성을 지원하는지 여부에 따라 이를 확장하여 styles.css
또는 styles.no-vars.css
를 로드할 수 있습니다. 다음과 같은 지원을 감지할 수 있습니다.
if ( window.CSS && CSS.supports('color', 'var(--test)') ) { loadCSS('styles.css'); } else { loadCSS('styles.no-vars.css'); }
결론
CSS를 효율적으로 구성하는 데 어려움을 겪고 있거나 반응형 구성 요소에 어려움이 있거나 클라이언트 측 테마를 구현하고 싶거나 사용자 정의 속성으로 제대로 시작하려는 경우 이 가이드에서 알아야 할 모든 것을 알려줄 것입니다.
CSS의 동적 변수와 정적 변수의 차이점과 몇 가지 간단한 규칙을 이해하는 것입니다.
- 디자인과 논리를 분리합니다.
- CSS 속성이 변경되면 사용자 정의 속성을 사용하는 것이 좋습니다.
- 사용되는 사용자 정의 속성이 아니라 사용자 정의 속성의 값을 변경하십시오.
- 전역 변수는 일반적으로 정적입니다.
이러한 규칙을 따르면 사용자 정의 속성으로 작업하는 것이 생각보다 훨씬 쉽다는 것을 알게 될 것입니다. This might even change how you approach CSS in general.
추가 읽기
- “It's Time To Start Using Custom Properties,” Serg Hospodarets
A general introduction to the syntax and the features of custom properties. - “Pragmatic, Practical, And Progressive Theming With Custom Properties,” Harry Roberts
More useful information on theming. - Custom Properties Collection, Mike Riethmuller on CodePen
A number of different examples you can experiment with.