[SCSS] 02. Style Rules
이번 포스트에서는 Scss에서 style을 작성하는 규칙인 Style Rule에 대해서 살펴보자.
기본 작성법
그냥 쓰려면 scss나 css나 동일
scss의 특별한 기능을 사용하지 않을꺼라면 scss나 css의 사용법은 동일하다.
// scss
.button {
padding: 3px 10acpx;
font-size: 12px;
}
// css
.button {
padding: 3px 10acpx;
font-size: 12px;
}
앞으로 코드를 비교할 때 왼쪽 블록은 scss, 오른쪽 블록은 css임을 밝혀둔다.
삶을 윤택하게 해주는 nesting
scss의 진가는 선택자의 중첩 기능에서부터 발휘된다. 일반적인 css의 선택자는 재사용이나 계층적인 구조화가 어렵다. 예를 들어 nav ul, nav>li, nav~a 등을 나타낼 때 선택자들의 시작이 nav로 모두 같음에도 불구하고 매번 따로 작성해야 했다.
하지만 scss에서는 산택자를 계층적으로 사용해서 조상-자손의 관계를 표현할 수 있다.
nav {
padding: 10px;
// 기본은 자손 선택자로 연결
ul {
list-style: none;
}
>li {
display: inline-block;
}
~a {
display: block;
}
}
nav {
padding: 10px;
}
nav ul {
list-style: none;
}
nav > li {
display: inline-block;
}
nav ~ a {
display: block;
}
한눈에 봐도 코드가 깔끔하고 관계의 추적이 용이해보인다. 나만 그러는건 아니겠지..
기본적으로 nav를 선택자로한 스타일이 잘 적용된 것을 볼 수 있고 nav ul, nav>li, nav~a 가 잘 생성된 것을 확인할 수 있다.
combinator( , >, ~, + 등) 의 위치는 외부, 내부 모두 가능
선택자를 중첩할 때 combinator의 위치는 외부와 내부 모두 가능하기 때문에 구성할 선택자에 따라 편하게 작성할 수 있다.
div> {
ul {
list-style-type: none;
}
a {
font-size: 2em;
}
}
div {
>p {
border-top: 1px solid gray;
}
div {
border-top: 1px solid red;
}
}
div > ul {
list-style-type: none;
}
div > a {
font-size: 2em;
}
div > p {
border-top: 1px solid gray;
}
div div {
border-top: 1px solid red;
}
위 예에서 첫번째 블록은 "div>" 를 상위 선택자로 해서 중첩하고 있도 두 번째 블록은 "div"를 상위 선택자로 사용하는 형태이다.
selector 목록의 중첩
comma(,)를 이용해서 선택자의 목록을 사용하는 경우에도 nesting을 잘 동작한다. 하지만 헷갈리니까 확인하고 넘어가자.
.alert,.warning {
ul, p {
margin-right: 0;
}
}
.alert ul, .alert p, .warning ul,.warning p {
margin-right: 0;
}
좌측의 선택자가 사용된 형태를 보면 외부 선택자로 .alert과 .warning의 목록이 사용되고 있고 내부에 다시 ul과 p의 목록이 중첩되어있다. 이 경우는 마치 2중 반복문이 적용되는 것 처럼 우측과 같이 4개의 선택자 목록에 적용된다.
속성의 선언
변수의 선언과 사용
css에서는 변수의 개념이 없기 때문에 중복되는 내용이 있을 때 계속해서 값을 써주는 수밖에 없었다. 일괄적으로 변경하려면? 당연히 모든 선언을 쫒아다니며 수정해줘야 한다. 하지만 scss에서는 변수를 사용할 수 있게 되었다! 변수를 선언할 때에는 $를 사용한다.
.circle {
$size: 100px; // 변수의 선언
width: $size; // 변수의 사용
border-radius: $size * 0.5;
}
.circle {
width: 100px;
border-radius: 50px;
}
$size로 설정된 100px이 width와 border-radius에서 사용되고 있어 나중에 변경이 필요할 때 한 번만 변경하면 처리가 가능하다. 선언된 변수는 컴파일된 css에는 당연히 보이지 않는다.
보간법(interpolation)
이 변수를 이용해서는 속성을 구성할 수 있는 보간법 즉 interpolation을 적용할 수 있다. 이때는 #을 사용한다.
.rect {
$size: 100px; // 변수의 선언
$위: top;
margin-#{$위}: $size; // 보간법
padding-#{$위}: $size;
border-radius: $size * 0.5;
}
.rect {
margin-top: 100px;
padding-top: 100px;
border-radius: 50px;
}
컴파일된 css에서는 margin-top과 margin-top 처럼 #{$위}의 내용이 top으로 치환 된 것을 볼 수 있다. 역시 변경이 필요하다면 $위의 값을 변경하면 된다.
속성의 중첩
앞서 선택자의 중첩에 대해서 살펴봤었는데 선택자와 마찬가지로 속성도 중첩될 수 있다. 많은 속성에는 prefix가 있는데 scss에서는 이 prefix를 마치 namespace 처럼 사용해서 중첩할 수 있다. 예를 들어 font-size, font-family 처럼 동일한 prefix로 시작하는 속성들을 여러개 설정해야 한다면 매우 유용하다.
.enlarge {
font: {
size: 2em;
weight: bolder;
}
margin: auto {
bottom: 10px;
top: 2px;
}
}
.enlarge {
font-size: 2em;
font-weight: bolder;
margin: auto;
margin-bottom: 10px;
margin-top: 2px;
}
상황에 따른 속성 적용
어떤 경우에는 상황(변수 값)에 따라서 속성의 값을 달리 하거나 또는 설정하지 말아야 할 경우도 있다. 이때는 if 같은 함수를 이용할 수 있다.
// 전역 변수 선언
$rounded: false;
.button {
border: 1px solid black;
border-radius: if($rounded, 5px, 1px);
}
.button {
border: 1px solid black;
border-radius: 1px;
}
여기서는 $rounded를 전역 레벨로 선언하고 있다. 현재는 할당된 값이 false이기 때문에 border-radius는 1px가 설정된다. 만약 $rounded가 true가 되면 당연히 border-radius는 5px이 설정된다. 또는 null을 할당하면 선언 자체를 없애버리기도 한다.
외부 선택자 참조 &
외부 선택자 참조 &
선택자를 중첩해서 사용하는데 중첩의 대상이 가상 선택자라면 한가지 고민이 필요하다. 단순히 하위 선택자를 사용하면 자손의 관계가 자동으로 추가되어버리기 때문이다. 따라서 이때는 외부 선택자에 대한 참조가 필요한데 &를 사용할 수 있다.
div {
// 자손 선택자 적용: div의 자손 중 :hover
:hover {
color: blue;
}
// 조상 선택자 활용: div 중 hover
&:hover {
color: red;
}
// 파라미터로 전달 가능
:not(&) {
color: green;
}
}
div :hover {
color: blue;
}
div:hover {
color: red;
}
:not(div) {
color: green;
}
전체적으로 div를 외부 선택자로 하고 내부에 여러가지 선택자들이 중첩되어있다. 첫번째 경우는 div :hover처럼 자손 선택자로 분리되어버린 것을 확인할 수 있다. 하지만 두번째의 경우는 div:hover로 div에서 hover가 발생했을 때로 처리된다. 이처럼 외부 선택자 참조시 &를 사용할 수 있다.
마지막 형태처럼 파라미터로 외부 선택자를 전달할 수도 있는데 이때는 외부 선택자와의 결합은 발생하지 않는다.
placeholder selector %
placeholder selector %
sass에서는 새로운 종류의 선택자가 추가되었는데 %를 기호로 하는 placeholder 선택자이다. 이 녀석은 재밋는 점이 자체적으로 보이지 않으며 심지어는 css에 포함되지도 않는다.
.li:hover, %strong {
color: red;
}
%strong:hover {
color: red;
}
.li:hover {
color: red;
}
위의 예는 %strong 처럼 뭔가 선택자가 선언되었고 심지어는 %strong:hover처럼 가상선택자를 이용해서 확장도 하고 있다. 하지만 sass를 컴파일한 결과에는 strong에 대한 내용이 존재하지 않는다. 그럼 %는 왜 사용하는가? % 선택자는 @extend에 의해 재사용하기 위해 사용된다. (마치 자바의 abstract class와 유사하다. 자체적으로는 사용되지 않는 상속 전용의 클래스.)
%base-box {
box-sizing: border-box;
display: flex;
&:hover {
color: white;
}
}
.action-box {
@extend %base-box;
color:green;
}
.reset-box {
@extend %base-box;
color:gray;
}
.reset-box, .action-box {
box-sizing: border-box;
display: flex;
}
.reset-box:hover, .action-box:hover {
color: white;
}
.action-box {
color: green;
}
.reset-box {
color: gray;
}
여기서는 base-box라는 placeholder 선택자를 선언하고 .action-box와 .reset-box에서 @extend를 통해서 사용하고 있는 것을 볼 수 있다.
컴파일된 결과를 살펴보면 상당히 놀라운점이 있는데 동일한 속성을 가지는 스타일 끼리 헤처모여하고 있다는 점이다. 단순히 컴파일만 하지 않고 코드 정리까지 깔끔하게 되니 인정! (모든 스타일을 저렇게 정리해주지는 않는다 ㅎ)