CSS 값은 각각의 CSS 속성에 어떤 유형의 값이 들어가는 게 '유효한지(valid)'를 정의해 줍니다. 예를 들어, color나 border-color 속성에는 색상 값을 지정할 수 있지만, 길이나 퍼센트(%) 값은 넣을 수 없죠.
CSS 공식 스펙 문서나 MDN의 속성 페이지를 보다 보면, 값 유형들이 꺾쇠괄호(<, >)로 둘러싸여 있는 것을 보실 수 있을 거예요. <color>나 <length> 처럼요. 만약 특정 속성에서 <color>가 유효한 값 유형이라고 적혀있다면, 이는 <color> 레퍼런스 페이지에 나열된 올바른 형태의 색상 값이라면 무엇이든 사용할 수 있다는 뜻입니다.
가끔은 값 유형과 속성 이름이 똑같거나 비슷할 때가 있어요. 예를 들면, color라는 속성도 있고 <color>라는 데이터 타입(값 유형)도 있죠. 이럴 때는 꺾쇠괄호(< >)가 있는지 없는지를 보고 내가 지금 보고 있는 게 속성인지, 값 유형인지 구분하시면 됩니다. (HTML 태그도 꺾쇠괄호를 쓰지만, 문맥상 무엇을 가리키는지 충분히 구분이 되실 거예요. 정 헷갈리신다면 MDN에 직접 검색해 보는 것도 좋은 방법입니다!)
참고:
CSS 값 유형(value types)을 데이터 타입(data types)이라고 부르는 것도 자주 보실 텐데요. 사실상 같은 말이라고 생각하셔도 무방해요. CSS에서 데이터 타입이라고 하면 그냥 값 유형을 조금 더 멋지게 부르는 말일 뿐이랍니다. 그리고 값(value)이라는 단어는 여러분이 선택해서 작성하는, 그 값 유형이 지원하는 특정 표현식 하나하나를 가리킵니다.
아래 예제를 한번 볼게요. 제목(<h1>)의 글자 색상은 색상 키워드(단어)를 사용해서 지정했고, 배경색은 rgb() 함수라는 조금 다른 형태의 색상 값을 사용해서 설정했어요.
h1 {
color: black;
background-color: rgb(197 93 161);
}
CSS의 값 유형은 '허용되는 값들의 모음'을 정의합니다. 즉, 유효한 값으로 <color>가 적혀있다면, 색상 키워드를 써야 할지, 헥스(hex) 값을 써야 할지, 아니면 rgb() 함수를 써야 할지 고민할 필요가 없다는 뜻이에요. 사용자의 브라우저가 지원하기만 한다면 사용 가능한 어떤 <color> 값이든 다 쓸 수 있거든요! MDN의 각 값 페이지를 들어가 보시면 브라우저 지원 현황에 대한 정보도 자세히 나와 있습니다. 예를 들어, <color> 페이지를 보면 여러 가지 색상 값 형태와 브라우저 호환성 목록이 정리되어 있죠.
자, 그럼 이제 여러분이 자주 마주치게 될 다양한 값의 유형과 단위들을 예제와 함께 살펴볼까요? 직접 다양한 값으로 바꿔보면서 테스트해 보셔도 좋습니다!
CSS를 작성하다 보면 정말 다양한 숫자 형태의 값 유형을 사용하게 됩니다. 아래에 나오는 것들은 모두 '숫자형(numeric)'으로 분류된답니다.
| 데이터 타입 (Data type) | 설명 (Description) |
|---|---|
<integer> | <integer>는 1024나 -55 같은 정수(whole number)를 말합니다. 소수점이 없는 깔끔한 숫자죠. |
<number> | <number>는 십진수(decimal number)를 나타냅니다. 소수점이 있을 수도 있고 없을 수도 있어요. 예를 들면 0.255, 128, -1.2 같은 것들이에요. |
<dimension> | <dimension>은 <number> 뒤에 단위(unit)가 찰싹 붙어있는 형태입니다. 예를 들어 45deg, 5s, 10px 같은 값들이죠. 사실 <dimension>은 넓은 의미의 카테고리라서, 이 안에 <length>(길이), <angle>(각도), <time>(시간), <resolution>(해상도) 유형들이 모두 포함된답니다. |
<percentage> | <percentage>는 다른 어떤 기준 값에 대한 비율(fraction)을 나타냅니다. 예를 들면 50% 처럼요. 퍼센트 값은 항상 다른 양(quantity)에 상대적으로 작용합니다. 가령 어떤 요소의 길이를 %로 주면, 그건 부모 요소의 길이에 비례해서 계산되죠. |
숫자 유형 중에서도 여러분이 가장 자주 만나게 될 녀석은 바로 <length>입니다. 10px(픽셀)이나 30em 같은 것들이죠. CSS에서 사용되는 길이 단위는 크게 상대 단위(relative)와 절대 단위(absolute) 두 가지로 나뉩니다. 내가 만든 요소가 도대체 화면에서 얼마나 크게 보일지 정확히 이해하려면 이 둘의 차이점을 꼭 알고 있어야 해요.
아래에 있는 것들은 모두 절대 길이 단위입니다. 이 녀석들은 다른 어떤 것에도 영향을 받지 않고(상대적이지 않고), 일반적으로 화면이나 종이에서 항상 동일한 크기를 유지한다고 간주됩니다.
| 단위 (Unit) | 이름 (Name) | 변환 (Equivalent to) |
|---|---|---|
cm | 센티미터 (Centimeters) | 1cm = 37.8px = 25.2/64in |
mm | 밀리미터 (Millimeters) | 1mm = 1/10th of 1cm |
Q | 쿼터 밀리미터 (Quarter-millimeters) | 1Q = 1/40th of 1cm |
in | 인치 (Inches) | 1in = 2.54cm = 96px |
pc | 파이카 (Picas) | 1pc = 1/6th of 1in |
pt | 포인트 (Points) | 1pt = 1/72nd of 1in |
px | 픽셀 (Pixels) | 1px = 1/96th of 1in |
대부분의 이 단위들은 화면 출력보다는 문서 인쇄(print) 작업에 훨씬 더 유용하게 쓰입니다. 예를 들어, 우리가 화면에서 웹사이트를 볼 때 cm(센티미터) 단위로 크기를 지정하는 일은 거의 없죠. 우리가 화면상에서 일상적으로 숨 쉬듯이 쓰게 될 단위는 오직 px (픽셀) 뿐입니다.
💡 강사님의 보충 설명 & 실무 팁!
주의할 점이 있어요. CSS에서의1px이 기계의 실제 물리적인 1픽셀(디바이스 픽셀)과 완벽히 똑같은 것은 아니랍니다. 요즘 많이 쓰는 망막(Retina) 디스플레이 같은 고해상도 화면에서는 CSS의1px이 실제로는 여러 개의 물리적 픽셀을 차지하게 돼요.
마찬가지로 CSS에서1cm를 지정했다고 해서 진짜 자로 잰 1cm가 나오는 것도 아니에요. 큰 TV 화면에서는 더 길게 보일 수도 있죠. 즉, 이 길이들은 '시각적인 인식(perceptual)'에 기반을 둡니다.16px이라는 글자 크기는 폰으로 보든 랩탑으로 보든 TV로 보든 일반적인 시청 거리에서 "대략 비슷하게" 보이도록 브라우저가 알아서 조정해 준다는 의미예요!
상대 길이 단위는 말 그대로 '다른 무언가에 상대적으로' 크기가 결정되는 단위입니다. 대표적으로 이런 것들이 있어요:
em은 현재 요소에 지정된 폰트 크기에 상대적입니다. (단, font-size 속성 자체에 em을 쓸 때는 부모 요소의 폰트 크기에 상대적으로 계산됩니다.) rem은 부모가 아니라 문서의 가장 뿌리가 되는 루트(root) 요소(보통 <html> 태그)의 폰트 크기에 상대적입니다.vh와 vw는 브라우저 창(뷰포트, viewport)의 높이(height)와 너비(width)에 상대적입니다.상대 단위를 사용하는 가장 큰 장점은 무엇일까요? 바로 설계를 조금만 꼼꼼히 해두면, 화면 크기나 전체 설정이 바뀔 때 텍스트나 다른 요소들의 크기가 그에 맞춰 비율대로 자연스럽게 변하게(스케일링) 만들 수 있다는 점이에요! 사용 가능한 모든 상대 단위 목록이 궁금하시다면 <length> 타입 레퍼런스 페이지를 참고해 보세요.
이번 섹션에서는 가장 흔하게 쓰이는 상대 단위 몇 가지를 집중적으로 탐구해 보겠습니다.
아래 예제를 통해 상대 길이와 절대 길이 단위가 어떻게 다르게 행동하는지 눈으로 직접 확인해 보세요.
width)가 픽셀(px)로 설정되어 있어요. 절대 단위이기 때문에, 브라우저 크기를 어떻게 바꾸든 저 너비는 꿋꿋하게 변하지 않습니다.vw (viewport width)로 설정되어 있어요. 이 값은 뷰포트(브라우저 창) 너비에 비례합니다. 10vw는 브라우저 창 너비의 딱 10퍼센트를 의미해요. 브라우저 창 크기를 늘렸다 줄였다 해보시면 박스 크기도 따라서 쫀쫀하게 변하는 걸 볼 수 있을 거예요. (참고로 여기서는 iframe 안에 예제가 들어있어서 바로 확인이 안 될 수 있으니, 새 탭에서 예제 열기를 눌러서 창 크기를 직접 조절해 보세요!)em 단위를 썼습니다. em은 요소의 폰트 크기에 비례한다고 했죠? 이 박스를 감싸고 있는 껍데기(부모) <div> (클래스 이름이 .wrapper입니다)에 폰트 크기를 1em으로 줘 볼게요. 만약 이 값을 1.5em으로 바꾸면, 안에 있는 글자 크기들이 전체적으로 커지는 걸 볼 수 있을 겁니다. 하지만 재밌는 건, 박스의 '너비'가 길어지는 건 마지막 세 번째 박스뿐이에요. 세 번째 박스의 너비만 폰트 크기에 비례하도록 em으로 설정해 뒀기 때문이죠.위 설명을 토대로 아래 코드의 값들을 이것저것 바꿔보면서 어떤 결과가 나오는지 맘껏 실험해 보세요!
<div class="wrapper">
<div class="box px">I am 200px wide</div>
<div class="box vw">I am 10vw wide</div>
<div class="box em">I am 10em wide</div>
</div>
.box {
background-color: lightblue;
border: 5px solid darkblue;
padding: 10px;
margin: 1em 0;
}
.wrapper {
font-size: 1em;
}
.px {
width: 200px;
}
.vw {
width: 10vw;
}
.em {
width: 10em;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
박스 사이즈를 정하든, 폰트 크기를 정하든, 여러분이 CSS를 다루면서 가장 지겹도록(?) 보게 될 두 가지 상대 길이가 바로 em과 rem입니다. 이 둘이 어떻게 작동하는지, 그리고 어떤 차이가 있는지 확실히 이해하고 넘어가는 건 정말 중요해요. 나중에 텍스트 스타일링이나 CSS 레이아웃 같은 복잡한 주제로 넘어갔을 때 헤매지 않으려면 말이죠.
아래에 중첩된(nested) 목록 예제가 있습니다. HTML 구조는 두 목록이 완전히 똑같아요. 유일한 차이점은 첫 번째 목록에는 ems라는 클래스가, 두 번째 목록에는 rems라는 클래스가 붙어 있다는 것뿐입니다.
먼저, 기준을 잡기 위해 가장 뿌리가 되는 <html> 요소의 폰트 크기를 16px로 설정했습니다.
다시 한번 복습해 볼까요?
em 단위는 font-size 속성에 쓰일 때는 "내 부모 요소의 폰트 크기"를 기준으로 삼고, 그 외의 다른 속성(margin, padding 등)에 쓰일 때는 "나 자신의 폰트 크기"를 기준으로 삼습니다.
ems 클래스를 가진 <ul> 안의 <li> 요소들은 자신의 크기를 '부모'로부터 가져옵니다. 그런데 각 단계마다 폰트 크기를 1.3em(부모 크기의 1.3배)으로 지정해 두었기 때문에, 목록 안으로 깊이 파고들어 갈수록(중첩될수록) 글자 크기가 1.3배씩 계속 커지게 됩니다. 눈덩이처럼 불어나는 거죠!
반면에 rem 단위는 "루트(root) 요소의 폰트 크기"를 기준으로 삼습니다. (rem의 'r'이 root를 뜻해요!)
rems 클래스를 가진 <ul> 안의 <li> 요소들은 바로 부모가 아니라 문서의 최상단인 루트 요소(<html>)의 폰트 크기(여기선 16px)만 바라봅니다. 그래서 목록이 아무리 깊이 중첩되어도 글자 크기가 계속 커지지 않고 일정한 1.3rem (16px * 1.3 = 20.8px) 크기를 유지하는 것을 볼 수 있습니다.
물론 여기서 CSS의 <html> 요소 font-size를 바꾸면 어떻게 될까요? 루트 크기가 변했으니 루트를 참조하는 rem이나, 간접적으로 루트의 영향을 받는 em이나 모두 크기가 따라서 변하게 됩니다. 이 부분도 MDN Playground에서 직접 수치를 바꿔보며 확인해 보세요!
💡 강사님의 실무 팁!
방금 보셨듯이em을 폰트 크기에 사용하면 중첩될 때마다 크기가 걷잡을 수 없이 커지거나 작아지는 현상이 발생해요. 이걸 유지보수하기란 정말 끔찍한 일이죠. 😭
그래서 실무에서는 폰트 크기나 마진/패딩을 잡을 때 기본적으로rem을 사용하는 것이 표준(Best Practice)으로 자리 잡았습니다.rem을 쓰면 부모 요소 신경 쓰지 않고 깔끔하게 크기를 예측할 수 있거든요. (참고로 브라우저의 기본 폰트 크기가 보통 16px 이기 때문에, 1rem = 16px 로 계산하시면 편합니다!)
<ul class="ems">
<li>One</li>
<li>Two</li>
<li>
Three
<ul>
<li>Three A</li>
<li>
Three B
<ul>
<li>Three B 2</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul class="rems">
<li>One</li>
<li>Two</li>
<li>
Three
<ul>
<li>Three A</li>
<li>
Three B
<ul>
<li>Three B 2</li>
</ul>
</li>
</ul>
</li>
</ul>
html {
font-size: 16px;
}
.ems li {
font-size: 1.3em;
}
.rems li {
font-size: 1.3rem;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
많은 경우 백분율(퍼센트, %)은 길이(length)와 비슷한 방식으로 취급됩니다. 퍼센트를 쓸 때 가장 중요한 핵심은 항상 다른 어떤 값을 기준으로 계산된다는 점입니다.
예를 들어 어떤 요소의 font-size를 퍼센트로 설정하면, 그건 '부모 요소의 font-size'의 몇 퍼센트인지로 계산됩니다. 만약 width(너비) 값에 퍼센트를 주면, 그건 '부모 요소의 width'의 몇 퍼센트인지로 계산되고요.
다음 예제에서는 퍼센트 너비 박스와 픽셀 너비 박스 두 쌍이 준비되어 있습니다. 두 쌍 모두 클래스 이름은 똑같이 사용했고, 각각 40%와 200px의 너비를 주었습니다.
차이점은 바로 '부모 요소'에 있습니다. 두 번째 묶음의 박스들은 너비가 400px로 고정된 부모 래퍼(.wrapper) 안에 들어있습니다.
보시면 200px로 설정된 픽셀 박스는 부모가 누구든 상관없이 똑같은 너비를 유지합니다. 하지만 40%로 설정된 퍼센트 박스는 부모의 너비인 400px의 40% (즉, 160px)로 좁아져서 첫 번째 묶음의 퍼센트 박스보다 훨씬 짧아진 것을 볼 수 있습니다!
래퍼(.wrapper)의 너비 값이나 박스의 퍼센트 값을 직접 수정해 보시면서 이 원리를 완벽히 이해해 보세요.
💡 강사님의 실무 팁!
처음 레이아웃을 짤 때%를 썼는데 왜 내 마음대로 화면이 안 채워질까 고민하는 경우가 많아요. 특히height(높이)에%를 줄 때는 부모 요소의 높이가 명확하게 픽셀 등으로 정해져 있지 않으면 아무리 100%를 줘도 높이가 변하지 않는답니다.%는 항상 기준이 되는 부모가 있어야 동작한다는 사실, 꼭 머릿속에 메모해 두세요!
<div class="box px">I am 200px wide</div>
<div class="box percent">I am 40% wide</div>
<div class="wrapper">
<div class="box px">I am 200px wide</div>
<div class="box percent">I am 40% wide</div>
</div>
.box {
background-color: lightblue;
border: 5px solid darkblue;
padding: 10px;
margin: 1em 0;
}
.wrapper {
width: 400px;
border: 5px solid rebeccapurple;
}
.px {
width: 200px;
}
.percent {
width: 40%;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
다음은 폰트 크기를 퍼센트로 설정한 예제입니다. 아까 본 em 단위와 아주 똑같이 행동하죠? 각 <li>의 폰트 크기를 80%로 주었더니, 자식 요소로 파고들수록 부모 폰트 크기의 80%씩 작아져서 글씨가 점점 깨알 같아지는 걸 볼 수 있습니다.
<ul>
<li>One</li>
<li>Two</li>
<li>
Three
<ul>
<li>Three A</li>
<li>
Three B
<ul>
<li>Three B 2</li>
</ul>
</li>
</ul>
</li>
</ul>
li {
font-size: 80%;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
한 가지 주의할 점! 많은 속성들이 길이(length)나 퍼센트(percentage)를 모두 값으로 받을 수 있지만, 어떤 속성들은 오직 '길이'만을 요구하기도 합니다. 대표적으로 테두리 두께를 정하는 border-width 속성이 그래요. 테두리 두께를 부모 요소의 %로 정하는 건 말이 안 되니까요.
MDN의 속성 레퍼런스 페이지를 보면 허용되는 값 유형이 적혀있는데, 만약 <length-percentage>라고 적혀있으면 길이나 퍼센트 둘 다 써도 되고, 오직 <length>만 적혀있다면 퍼센트는 쓸 수 없다는 점 기억하세요!
어떤 값 유형들은 뒤에 단위를 붙이지 않고 순수한 '숫자' 그 자체만 받기도 합니다. 가장 대표적인 예가 요소의 불투명도(얼마나 투명한가)를 조절하는 opacity 속성이에요. 이 속성은 요소가 완전히 투명할 때 0, 완전히 불투명하게 다 보일 때 1을 사용하며, 그 사이의 소수점 숫자를 값으로 받습니다.
아래 예제에서 opacity 값을 0에서 1 사이의 다양한 소수점(예: 0.2, 0.8 등)으로 바꿔보세요. 박스와 그 안의 글씨들이 어떻게 투명해졌다 진해졌다 하는지 관찰할 수 있습니다.
<div class="wrapper">
<div class="box">I am a box with opacity</div>
</div>
.wrapper {
background-image: url("[https://mdn.github.io/shared-assets/images/examples/balloons.jpg](https://mdn.github.io/shared-assets/images/examples/balloons.jpg)");
background-repeat: no-repeat;
background-position: bottom left;
padding: 20px;
}
.box {
margin: 40px auto;
width: 200px;
background-color: lightblue;
border: 5px solid darkblue;
padding: 30px;
opacity: 0.6;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
참고:
CSS에서 값을 지정할 때 '숫자'를 쓴다고 해서 문자열처럼 따옴표(" ")로 감싸시면 안 됩니다! 그냥 숫자만 깔끔하게 적어주세요.
CSS에서 색상 값은 글자 색, 배경 색, 테두리 색 등등 정말 무궁무진하게 쓰입니다. CSS에서 색상을 지정하는 방법도 여러 가지가 있어서 아주 다채로운 표현이 가능하죠.
현대 컴퓨터에서 사용하는 표준 색상 시스템은 24비트 색상을 지원하는데요, 이는 빨강(Red), 초록(Green), 파랑(Blue) 세 가지 채널에 각각 256단계의 값을 섞어서 약 1,670만 가지의 색(256 x 256 x 256 = 16,777,216)을 화면에 띄울 수 있게 해 줍니다.
이번 섹션에서는 가장 흔하게 접하게 될 3총사 — 색상 키워드, 16진수(Hexadecimal) 코드, 그리고 rgb() 값 — 에 대해 먼저 알아볼 거예요. 그리고 다른 최신 색상 함수들도 살짝 맛보기로 살펴볼 건데, 나중에 실무에서 코드를 마주쳤을 때 당황하지 않고 아는 체를 하거나 다양한 색상 적용법을 테스트해 볼 수 있도록 말이죠!
일반적으로 프로젝트를 시작할 때는 브랜드에 맞는 '컬러 팔레트'를 미리 정해놓고 사용합니다. 물론 이 방법 저 방법 섞어 쓸 수도 있지만, 코드가 깔끔해 보이려면(그리고 동료 개발자와 싸우지 않으려면) 전체 프로젝트에서 색상을 선언하는 방식은 한 가지로 통일하는 것이 좋습니다!
MDN의 수많은 코드 예제들을 보다 보면 색상의 이름을 나타내는 키워드(또는 "네임드 컬러(named colors)")를 많이 보실 수 있을 거예요. 사실 <named-color> 데이터 타입에 있는 색상의 종류는 한정되어 있어서, 아주 세밀하고 세련된 디자인 가이드가 있는 실제 서비스(Production) 환경에서는 키워드 방식을 잘 쓰지 않습니다. 대신 MDN 같은 곳에서 예제로 많이 쓰는 이유는, 학습하시는 분들이 코드를 딱 봤을 때 "아 이건 빨간색이구나" 하고 직관적으로 이해하기 쉽게 만들기 위함이랍니다.
아래 예제에서 다양한 색상 키워드들을 넣어서 테스트해 보세요. 사용 가능한 키워드는 <named-color> 레퍼런스 페이지에서 찾아보실 수 있어요. (ex: tomato, hotpink, dodgerblue 등 재미있는 이름들이 많답니다!)
💡 강사님의 실무 팁!
"실무에서 이름 있는 색상은 전혀 안 쓰나요?" 라고 물으신다면, 그렇진 않습니다!
개발 과정에서 영역 박스를 잠깐 칠해놓고 레이아웃을 확인하고 싶을 때background-color: red;나blue;처럼 타이핑하기 가장 빠르기 때문에 디버깅 용도로 아주 요긴하게 쓰입니다.
<div class="wrapper">
<div class="box one">antiquewhite</div>
<div class="box two">blueviolet</div>
<div class="box three">greenyellow</div>
</div>
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: antiquewhite;
}
.two {
background-color: blueviolet;
}
.three {
background-color: greenyellow;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
다음으로 만나볼 녀석은 바로 실무 점유율 1위에 빛나는 16진수(hex, 헥스) 코드입니다!
16진수 숫자는 0부터 9까지의 숫자와 a부터 f까지의 알파벳, 총 16개의 문자를 사용합니다. 즉 0123456789abcdef 범위를 갖게 되죠.
각각의 헥스 색상 값은 맨 앞에 우물 정자 혹은 파운드 기호라고 부르는 샵(#)을 붙이고, 그 뒤에 6자리의 16진수 문자가 따라오는 형태입니다 (예: #ffc0cb).
이 6자리는 두 글자씩 3쌍으로 나뉘어서 각각 RGB (Red, Green, Blue) 채널을 담당해요. 각 채널마다 16 x 16 = 256 가지의 값을 지정할 수 있는 거죠.
직관적인 영어 단어(키워드)보다는 색을 상상하기 조금 어렵게 느껴질 수도 있지만, 이 6자리 코드로 RGB로 만들 수 있는 모든 색상을 표현할 수 있기 때문에 활용도 면에서는 단연 최고입니다. 디자이너분들이 건네주는 색상 코드도 대부분 이 형태고요!
아래 값들을 바꿔가며 색이 어떻게 변하는지 확인해 보세요. (ex: 빨간색을 강조하고 싶으면 첫 두 자리를 ff로 주고 나머지를 00으로 줘보세요! #ff0000)
<div class="wrapper">
<div class="box one">#02798b</div>
<div class="box two">#c55da1</div>
<div class="box three">#128a7d</div>
</div>
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: #02798b;
}
.two {
background-color: #c55da1;
}
.three {
background-color: #128a7d;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
참고:
헥스 코드가 6자리가 아니라 3자리로 쓰여 있는 것도 보실 수 있을 거예요. 이건 각 채널의 두 글자가 똑같을 때 쓸 수 있는 축약형(shorthand) 문법입니다. 예를 들어#ff00ff와#f0f는 완전히 같은 색이에요.
또한 요즘은 8자리(또는 4자리)로 적힌 헥스 코드도 쓰이는데, 마지막 2자리(또는 1자리)는 색상의 투명도(alpha-transparency)를 의미합니다.#ff00ff66처럼요!
RGB 값을 직접 함수 형태로 작성하고 싶다면 rgb() 함수를 쓰면 됩니다. 이 함수는 순서대로 빨강(red), 초록(green), 파랑(blue) 채널의 값을 넘겨받아요. 앞서 배운 헥스 값처럼, 슬래시(/)로 구분해서 네 번째 값으로 투명도(opacity)를 줄 수도 있습니다.
헥스 방식과의 차이점이라면, 두 자리의 16진수 문자를 쓰는 대신 우리가 익숙한 십진수 숫자 0부터 255 사이의 값을 쓰거나, 혹은 0%부터 100% 사이의 퍼센트 값을 쓴다는 점이에요. (하지만 숫자와 퍼센트를 섞어 쓰시면 안 됩니다!)
방금 위에서 본 예제를 똑같이 rgb() 문법으로 바꿔서 써볼게요.
<div class="wrapper">
<div class="box one">rgb(2 121 139)</div>
<div class="box two">rgb(197 93 161)</div>
<div class="box three">rgb(18 138 125)</div>
</div>
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: rgb(2 121 139);
}
.two {
background-color: rgb(197 93 161);
}
.three {
background-color: rgb(18 138 125);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
이번 예제에서는 색상 박스들을 감싸는 배경(.wrapper)에 그림 이미지를 하나 깔아보았어요. 그리고 박스들의 배경색에는 각기 다른 투명도(알파 채널) 값을 주었죠.
알파 채널 값이 작아질수록 투명해져서 뒤에 깔린 풍선 그림이 더 잘 비치는 것을 눈으로 확인해 보세요. 이 값을 0으로 주면 색이 100% 투명해져서 아예 안 보이고, 1을 주면 완전히 불투명해져서 뒷배경이 다 가려집니다. 그 사이의 값들을 통해 반투명 효과를 자유자재로 낼 수 있죠.
알파 채널 값을 직접 변경해 가면서 색상이 어떻게 나타나는지 확인해 보세요!
<div class="wrapper">
<div class="box one">rgb(2 121 139 / .3)</div>
<div class="box two">rgb(197 93 161 / .7)</div>
<div class="box three">rgb(18 138 125 / .9)</div>
</div>
.wrapper {
background-image: url("[https://mdn.github.io/shared-assets/images/examples/balloons.jpg](https://mdn.github.io/shared-assets/images/examples/balloons.jpg)");
padding: 40px 20px;
}
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: rgb(2 121 139 / 0.3);
}
.two {
background-color: rgb(197 93 161 / 0.7);
}
.three {
background-color: rgb(18 138 125 / 0.9);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
참고:
색상 값 안에 알파 채널을 설정하는 것과, 앞서 숫자 섹션에서 배운opacity속성을 쓰는 것에는 아주 큰 차이가 하나 있습니다.
opacity속성을 사용하면 해당 요소 전체와 그 안에 들어있는 모든 내용물(글자 포함)까지 몽땅 투명해집니다. 반면에 RGB의 알파 파라미터를 사용하면, 오직 내가 지정하고 있는 그 '배경색' 하나만 투명해지고 안에 있는 글씨는 진하게 그대로 유지돼요. 실무에서 이 차이를 몰라 글씨까지 투명해져서 당황하는 경우가 많으니 꼭 알아두세요!
단순한 키워드나 헥스, rgb()를 넘어 조금 더 감각적으로 색상을 다루고 싶다면, <hue>(색조)를 사용하는 방식에 도전해 볼 만합니다.
색조는 빨강, 주황, 노랑, 초록, 파랑 등 색상 본연의 빛깔 자체를 구별하게 해주는 값이에요. 가장 중요한 개념은 대부분의 색상 모델이 색조를 색상환(Color wheel)을 이용해 나타내기 때문에, 색조 값을 각도(<angle>) 단위로 지정할 수 있다는 것입니다. (예: 0deg는 빨강, 120deg는 초록 등)
이 <hue> 요소를 포함하고 있는 색상 함수로는 hsl(), hwb(), lch() 등이 있습니다. 이 외에도 인간이 눈으로 보는 방식을 기반으로 색상을 정의하는 lab() 같은 색상 함수도 존재해요.
이런 함수들이나 색 공간(color spaces)에 대해 더 깊이 파고들고 싶다면 CSS를 이용해 HTML 요소에 색상 입히기 가이드나, CSS의 모든 색상 사용법을 망라한 <color> 레퍼런스, 그리고 CSS 색상 모듈을 읽어보시는 걸 추천해 드립니다.
색조를 사용하는 좋은 출발점으로 hwb() 함수를 소개할게요. 이 함수는 srgb() 색상 체계 안에서 세 가지 파트의 값을 받습니다:
0에서 360 사이의 <hue> 값을 받습니다.0%(흰색 없음)부터 100%(완전한 흰색) 사이의 값을 가집니다.0%(검은색 없음)부터 100%(완전한 검은색) 사이의 값을 가집니다.hwb() 함수와 비슷하게 hsl() 함수도 자주 쓰입니다. HSL은 Hue(색조)와 함께 Saturation(채도), Lightness(명도)를 사용합니다:
0~100%의 값을 가지며, 0이면 색상이 전혀 없는 회색톤이 되고, 100%면 완전 쨍한 원색이 됩니다.0~100%의 값을 가지며, 0은 빛이 아예 없는 완전한 검은색, 100%는 빛으로 꽉 찬 완전한 흰색이 됩니다. (보통 우리가 생각하는 본연의 색상은 50% 명도일 때 가장 잘 보입니다.)hsl() 함수 역시 rgb()처럼 슬래시(/)로 구분해서 네 번째 자리에 알파 투명도 값을 줄 수 있어요.
이전에 봤던 RGB 예제를 HSL 색상으로 똑같이 구현해 볼게요:
<div class="wrapper">
<div class="box one">hsl(188 97% 28%)</div>
<div class="box two">hsl(321 47% 57%)</div>
<div class="box three">hsl(174 77% 31%)</div>
</div>
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: hsl(188 97% 28%);
}
.two {
background-color: hsl(321 47% 57%);
}
.three {
background-color: hsl(174 77% 31%);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
rgb() 와 마찬가지로 hsl() 에도 알파 파라미터를 추가해 투명도를 줄 수 있답니다:
<div class="wrapper">
<div class="box one">hsl(188 97% 28% / .3)</div>
<div class="box two">hsl(321 47% 57% / .7)</div>
<div class="box three">hsl(174 77% 31% / .9)</div>
</div>
.wrapper {
background-image: url("[https://mdn.github.io/shared-assets/images/examples/balloons.jpg](https://mdn.github.io/shared-assets/images/examples/balloons.jpg)");
padding: 40px 20px;
}
.box {
padding: 10px;
margin: 0.5em 0;
border-radius: 0.5em;
}
.one {
background-color: hsl(188 97% 28% / 0.3);
}
.two {
background-color: hsl(321 47% 57% / 0.7);
}
.three {
background-color: hsl(174 77% 31% / 0.9);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
💡 강사님의 실무 팁!
"복잡하게 HSL 같은 걸 왜 쓰나요? 그냥 Hex 쓰면 안 되나요?"
디자인 시스템을 구축하다 보면 특정 브랜드 컬러(예: 파란색)를 기준으로 마우스를 올렸을 때 약간만 더 어둡게(Hover) 만들고 싶은 경우가 생기죠. 이럴 때 HSL을 쓰면 색조(Hue)는 그대로 둔 채 명도(Lightness) 퍼센트 수치만 살짝 조절해주면 아주 쉽게 파생 색상들을 뚝딱 만들어낼 수 있어요. 그래서 UI 컴포넌트 라이브러리 개발에 엄청나게 유리한 방식이랍니다.
다음 챕터로 넘어가기 전에, 위 두 예제의 HSL 값들을 직접 수정해 보며 색조 기반의 색상을 체득해 보세요. 색조 수치를 바꾸면 베이스 색상이 어떻게 달라지는지, 그리고 채도나 명도를 바꾸면 어떤 느낌으로 변하는지 감을 잡아보시면 좋습니다.
<image> 값 유형은 이미지가 유효한 값으로 들어갈 수 있는 곳이라면 어디든 쓰입니다. 보통은 url() 함수를 사용해서 실제 이미지 파일 경로를 연결하는 방식으로 쓰이지만, 여기서 한 가지 흥미로운 점은 그라데이션(gradient) 또한 CSS에서는 이미지로 취급된다는 사실입니다!
아래 예제에서 우리는 CSS background-image 속성의 값으로 하나는 진짜 이미지 파일을, 또 다른 하나는 선형 그라데이션(linear-gradient)을 사용해 보았습니다.
<div class="box image"></div>
<div class="box gradient"></div>
.box {
height: 150px;
width: 300px;
margin: 20px auto;
border-radius: 0.5em;
}
.image {
background-image: url("[https://mdn.github.io/shared-assets/images/examples/big-star.png](https://mdn.github.io/shared-assets/images/examples/big-star.png)");
}
.gradient {
background-image: linear-gradient(
90deg,
rgb(119 0 255 / 39%),
rgb(0 212 255 / 25%)
);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
참고:
<image>로 쓸 수 있는 값 중에는 최신 문법들도 몇 가지 더 있지만, 아직 브라우저 호환성이 떨어지는 편이에요. 궁금하시다면 MDN의<image>데이터 타입 문서를 직접 읽어보시길 권해드립니다.
이미지 값에 대한 더 깊은 내용은 이어지는 배경과 테두리 (Backgrounds and borders) 강의에서 자세히 다룰 예정이니 기대해 주세요!
<position> 값 유형은 요소의 위치를 정해주는 2D(2차원) 좌표값을 말합니다. 보통 배경 이미지의 위치를 옮길 때 사용하는 background-position 속성 같은 곳에 쓰이죠.
여기에는 top, left, bottom, right, center 같은 텍스트 키워드를 사용해서 2D 박스의 특정 테두리에 딱 붙일 수도 있고, 길이 단위(px, % 등)를 사용해서 요소의 위쪽 끝과 왼쪽 끝으로부터 얼마만큼 떨어져 있을지 직접 세밀하게 오프셋(offset) 값을 지정할 수도 있습니다.
위치 값은 보통 가로 위치와 세로 위치, 이렇게 두 개의 값으로 이루어집니다. 첫 번째 값이 가로(수평) 위치를, 두 번째 값이 세로(수직) 위치를 결정해요. 만약 축 하나(가령 가로)의 값만 지정하고 세로 값을 생략하면, 생략된 축은 자동으로 center(가운데)로 잡히게 됩니다.
아래 예제는 배경 이미지를 컨테이너의 맨 위에서 60px 떨어진 곳, 그리고 수평으로는 맨 오른쪽(right)에 위치시키는 모습입니다. 코드의 값을 이리저리 바꿔가면서 이미지를 박스 안에서 자유롭게 이동시켜 보세요. (음수 값도 가능하답니다!)
<div class="box"></div>
.box {
height: 200px;
width: 400px;
background-image: url("[https://mdn.github.io/shared-assets/images/examples/big-star.png](https://mdn.github.io/shared-assets/images/examples/big-star.png)");
background-repeat: no-repeat;
background-position: right 60px;
margin: 20px auto;
border-radius: 0.5em;
border: 5px solid rebeccapurple;
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
지금까지 예제들을 살펴보면서 red, black, rebeccapurple, goldenrod 같이 값 자리에 영어 단어(키워드)가 쏙쏙 들어가는 걸 많이 보셨을 거예요. 이런 키워드들은 CSS가 찰떡같이 알아듣는 특별한 값으로, 더 정확한 용어로는 식별자(identifiers)라고 부릅니다. 이 식별자들은 일반 문장과는 다르게 취급되기 때문에 주변에 따옴표(" ")를 붙이지 않습니다. 즉, 단순한 문자열(string)로 취급되지 않아요.
하지만 반대로 CSS에서 진짜 '문자열'을 써야 하는 곳도 존재합니다. 대표적으로 ::before나 ::after로 생성된 콘텐츠(generated content)를 만들 때가 그렇죠. 이때는 값 양 끝에 따옴표를 반드시 붙여서 "이건 단순한 글자들로 이뤄진 문자열이야!"라는 걸 브라우저에게 알려줘야 합니다.
아래 예제에서 볼 수 있듯, 색상 키워드는 따옴표 없이 사용하지만, 생성된 콘텐츠(content 속성)에는 텍스트 앞뒤로 따옴표를 붙여서 쓰고 있습니다.
<div class="box"></div>
.box {
width: 400px;
padding: 1em;
border-radius: 0.5em;
border: 5px solid rebeccapurple;
background-color: lightblue;
}
.box::after {
content: "This is a string. I know because it is quoted in the CSS.";
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
일반적인 프로그래밍에서 함수(Function)란 특정한 작업 하나를 수행하기 위해 묶어놓은 코드 덩어리를 말해요. 함수는 한 번 만들어 두면 똑같은 로직을 매번 처음부터 다시 쓸 필요 없이 여러 번 재사용할 수 있어서 아주 편리하죠. 대부분의 프로그래밍 언어들은 함수 문법을 지원할 뿐만 아니라, 개발자들이 자주 쓸 법한 기능들은 아예 내장 함수(built-in functions)로 만들어서 제공해주기도 합니다.
그런데 재밌게도, 스타일링 언어인 CSS에도 이와 아주 유사하게 동작하는 함수(functions) 문법이 있습니다. 사실 우리는 위에서 색상을 다룰 때 이미 rgb()나 hsl() 같은 CSS 함수들을 써봤어요. (이름 뒤에 괄호 () 가 붙어있으면 십중팔구 함수라고 보시면 됩니다!)
CSS에서 함수는 색상을 입히는 일 말고도 정말 다양한 일을 해낼 수 있습니다.
예를 들어 화면의 요소를 움직이고, 회전시키고, 크기를 줄이거나 키울 때 흔히 쓰는 변형 함수(Transform functions)들이 있어요. 수평이나 수직으로 요소를 밀어내는 translate(), 뱅글뱅글 돌려버리는 rotate(), 크기를 배수로 키웠다 줄였다 하는 scale() 같은 함수들을 곧 마주치게 되실 겁니다.
프로젝트를 진행하다 보면 처음에는 크기를 300px, 애니메이션 지속시간을 200ms 같이 고정된 숫자로 딱딱 맞춰서 코딩을 시작하게 될 거예요. 하지만 반응형 웹을 만들다 보면, 어떤 값의 일정 퍼센트(%)를 구하거나 서로 다른 성격의 단위(예: %와 px)를 더해서 새로운 크기를 동적으로 만들어내야 할 때가 옵니다. 결국 수학 연산이 필요해지는 거죠!
CSS는 바로 이런 상황을 위해 수학 함수(Math functions)를 지원합니다. 이 함수들을 사용하면 자바스크립트(JavaScript)의 도움 없이도 CSS 파일 내부에서 직접 연산을 처리할 수 있어요.
이 중에서도 단연 압도적으로 가장 많이 쓰이는 함수는 바로 덧셈, 뺄셈, 곱셈, 나눗셈 사칙연산을 모두 수행할 수 있게 해주는 calc() 함수입니다.
예를 들어, 어떤 요소의 너비를 '부모 컨테이너 너비의 20%에다가 추가로 100px을 더한 값'으로 설정하고 싶다고 상상해 보세요.
이 너비는 고정된 값(static value)으로 절대 적어낼 수 없습니다. 왜냐하면 부모 컨테이너의 너비가 사용자의 기기나 브라우저 창 크기에 따라 실시간으로 계속 변할 수 있기 때문이죠.
하지만 calc() 함수를 쓰면 이게 가능해집니다!
calc(20% + 100px)이라고 적어두면, 앞의 20%는 부모(.wrapper)의 너비에 비례해 계산되고, 만약 창 크기가 변해서 부모 너비가 달라지면 이 계산식도 알아서 다시 똑똑하게 척척 계산된답니다.
💡 강사님의 실무 팁!
calc()함수를 쓸 때 정말 자주 겪는 초보자분들의 흔한 실수 중 하나가 바로 띄어쓰기예요!+나-같은 연산자 양옆에는 반드시 공백(띄어쓰기)을 한 칸씩 넣어주셔야 합니다.calc(100%-20px)처럼 붙여서 쓰면 CSS가 이걸 뺄셈 기호가 아니라 음수를 나타내는 문법으로 오해해서 에러를 내고 속성이 아예 적용되지 않아요. 조심, 또 조심하세요!
<div class="wrapper">
<div class="box">My width is calculated.</div>
</div>
.wrapper {
width: 400px;
}
.box {
padding: 1em;
border-radius: 0.5em;
border: 5px solid rebeccapurple;
background-color: lightblue;
width: calc(20% + 100px);
}
MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)
calc() 외에도 실무에서 유용하게 쓸 수 있는 수학 함수들이 꽤 있습니다. 여러 개의 값 중 가장 작은 값을 골라주는 min(), 가장 큰 값을 골라주는 max(), 그리고 최소치와 최대치 사이에서 딱 적당한 중간 값을 유연하게 유지해 주는 clamp() 함수 등이 있죠. 사용 가능한 모든 함수가 궁금하시다면 CSS 값 함수(CSS value functions) 문서를 꼭 즐겨찾기 해두고 살펴보세요!
이런 CSS 함수들의 존재를 미리 알아두면 코드를 읽을 때 훨씬 수월하고, 나아가 내 프로젝트에 직접 적용해 보면 반복적이고 비효율적인 코드를 엄청나게 줄일 수 있습니다. CSS만으로 해낼 수 있는 멋진 결과물들을 굳이 자바스크립트로 길게 작성할 필요가 없어지니까요.
수고 많으셨습니다! 지금까지 CSS에서 가장 흔하게 쓰이는 값의 유형과 단위들을 쭈욱 훑어보았습니다. 더 세세한 전체 타입 종류가 궁금하시다면 CSS 값과 단위(CSS Values and units) 모듈 페이지를 쓱 둘러보시는 것도 좋습니다. 사실 앞으로 이어질 강의 예제들을 따라가다 보면 이 값들을 자연스럽게 수도 없이 마주치게 되실 거예요.
오늘 꼭 가져가셔야 할 핵심은 딱 두 가지입니다.
첫째, 모든 CSS 속성에는 그 자리에 들어갈 수 있는 '정해진 값의 유형' 목록이 존재한다.
둘째, 이 값 유형들이 도대체 뭔지 뜻을 알고 있어야 한다.
조금 막힌다 싶으면 언제든 MDN 레퍼런스 문서를 열어보는 습관을 들이세요. 예를 들어 <image> 값 유형에 단순히 사진 파일만 들어가는 줄 알았는데 색상 그라데이션까지 만들 수 있다는 걸 문서에서 발견했을 때의 그 짜릿함! 아는 만큼 코드가 더 우아해진답니다.