오늘은 마크업의 꽃, HTML 문서에 스타일을 부여할 수 있는 CSS에 대해 알아보자!
CSS
- 웹페이지 스타일 및 레이아웃을 정의하는 스타일시트 언어
- HTML구조의 UX를 제공하기 위해 UI 및 레이아웃을 적절히 구성하여 멋진 웹페이지 완성이 가능하다.
- 웹 사이트 사용자가 HTML 문서에 작성된 콘텐츠를 잘 이해할 수 있도록 돕는 역할을 한다.
주의!: CSS는 UI(사용자 인터페이스)를 고려해야한다!
...
그렇다면 UI는 무엇일까?
인터페이스는 컴퓨터와 교류하기 위한 연결고리!
메세지를 키보드 인터페이스로 입력하고, 마우스 모양 인터페이스를 사용할 수 있는 것처럼 사용자가 쉽게 사용할 수 있는 인터페이스는 앞에 ‘사용자’를 붙여 사용자인터페이스, 즉 UI라고 부름
FE는 웹 개발 기술을 기반으로 사용자와 소통할 수 있는 웹 페이지 제작을 담당한다. 그렇기 때문에 애플리케이션과 소통이 필요한 UI 제작은 FE 개발자의 기본 소양이다.
CSS를 잘 이용해 본텐츠가 더욱 잘 보이게 레이아웃을 적절히 디자인하는 것이 필요
- 아무리 훌륭한 내부 기능을 갖고 있더라도, UI가 없으면 소용 X
- 사용자가 애플리케이션을 사용하게 하려면 UI가 꼭 필요!
이처럼 중요한 UI를 만드는 것이 프론트엔드 개발자의 역할이다!
그럼 이제 UI의 중요성을 알았으니, CSS 내용에 대해 알아보자!
CSS에는 id와 class가 있는데, 그 둘의 차이점을 표로 보자.
id와 class의 차이점
| id | class |
|---|---|
| #으로 선택 | .으로 선택 |
| 한 문서에 단 하나의 요소에만 적용 | 동일한 값을 갖는 요소 많음 |
| 특정 요소에 이름을 붙이는 데 사용 | 스타일의 분류(classification)에 사용 |
흠... id랑 class로 구분하는건 알겠어! 그럼 다른 요소를 바꿀 때는 어떻게 할까?
만약...글자 색이나 글꼴을 바꾸고 싶을때 어떻게 하지? 정렬은...?
.red {
color: #ff0000;
}
.box {
color: #155724; /* 글자 색상 */
background-color: #d4edda; /* 배경 색상 */
border-color: #c3e6cb; /* 테두리 색상 */
}
.emphasize {
font-family: "SF Pro KR", "MalgunGothic", "Verdana";
}
h1{
font: 12px/1em "SF Pro KR" #ff0;
}
.title {
font-size: 24px;
}
font-weighttext-decorationletter-spacingline-heighttext-align, 유효한 값으로는 left, right, center, justify(양쪽 정렬)vertical-align 속성을 쉽게 떠올릴 수 있지만, 이 속성은 부모 요소의 display 속성이 반드시 table-cell이어야 하기 때문이다. 어라...? 그럼 글꼴 사이즈는 px 하나만 쓰나? 그거 말고 다른 단위가 있나?
...있다! 바로 글꼴에 따르냐 화면에 따르냐 정할때 말이다!
px사용한다.rem을 추천(root의 글자 크기)em은 부모 엘리먼트에 따라 상대적으로 크기가 변경되므로 계산이 어려운데 rem은 root의 글자 크기에 따라서만 상대적으로 변한다)반응형 웹(responsive web)에서 기준점을 만들 때
px로 정함화면 너비나 높이에 따른 상대적인 크기가 중요한 경우
vw, vh를 사용(웹사이트의 보이는 영역을 Viewport라고 함)vw , vh는 각각 viewport width와 viewport height를 뜻하며, 1vw는 보이는 영역 너비의 1/100, 1vh는 보이는 영역 높이의 1/100100vw, 100vh를 사용해 구현한다.우와 생각보다 고려해야 할게 많네...? CSS는 생각보다 복잡하네...
맞다. CSS는 깊게 파고들면 파고들수록 어렵다.
그 이유로 모든 콘텐츠는 고유한 영역이 있는데, 그것을 하나하나 지정하고 특성을 고려해서 스타일을 하려니 어려운 것이다...!
예를 들어 박스모델을 한 번 알아보자.
박스 모델은 두가지로 나눌 수 있다
- 줄 바꿈이 되는 박스는 block 박스
- 줄 바꿈이 일어나지 않고, 크기 지정을 할 수 없는 박스는 inline 박스
- 줄 바꿈이 일어나지 않는 동시에 block 박스의 특징을 가지는 inline-block 박스
- 줄 바꿈이 되는 요소:
<h1>,<p>- 줄 바꿈이 되지 않는 요소:
<span>
더 많은 block 요소의 목록은 MDN block 엘리먼트 목록, inline 요소의 목록은 inline 엘리먼트 목록을 찾아보자!
- block 요소의 대표적인 예는
<div>,<p>- inline 요소의 대표적인 예는
<span>- inline-block 박스는 inline 박스처럼 다른 요소의 옆으로 붙으면서, 자체적으로 고유의 크기를 가진다.
span {
background: yellow;
display: inline-block;
width: 100px;
height: 100px;
}
표로 간단히 세가지를 비교해보자!

아! 박스요소는 3가지로 나뉠 수 있구나... 그렇다면...박스를 구성하는 요소로 무엇이 있을까?
- border 속성에 적용된 각각의 값은 테두리 두께(
border-width), 테두리 스타일(border-style), 테두리 색상(border-color)
p {
border: 1px solid red;
}
- 각각의 값은 top, right, bottom, left로 시계방향(상우하좌)
p {
margin: 10px 20px 30px 40px;
padding: 10px 20px 30px 40px;
}
/* 값을 두 개만 넣으면 top과 bottom이 10px, left 및 right가 20px */
p {
margin: 10px 20px;
}
/* 값을 하나만 넣으면 모든 방향의 바깥 여백에 적용 */
p {
margin: 10px;
}
/* 음수도 사용 가능-> 화면 밖에서 사라지거나 겹치게 만들 수 있음 */
p {
margin-top: -2rem;
}
- 박스의
height속성에 콘텐츠가 차지하는 공간보다 작은 값을 지정할 때, 콘텐츠가 박스를 뚫고 나가는 경우에는 박스 크기에 맞게 콘텐츠를 더 이상 표시하지 않거나, 혹은 박스 안에 스크롤을 추가하여 콘텐츠를 확인할 수 있게 만든다.
p {
height: 40px;
overflow: auto;
}
overflow: hidden; overflow-x, overflow-y 도 사용 가능하다
여백과 테두리 두께를 포함해서 박스 크기를 계산
- 모든 요소에
box-sizing: border-box를 적용하면, 모든 박스에서 여백과 테두리를 포함한 크기로 계산한다.- 일반적으로
box-sizing은 HTML 문서 전체에 적용한다.box-sizing을 일부 요소에만 적용하는 경우, 혼란을 가중시킬 수 있다.content-box는 박스의 크기를 측정하는 기본값. 그러나 대부분의 레이아웃 디자인에서 여백과 테두리를 포함하는 박스 크기 계산법인border-box를 권장한다.
* {
box-sizing: border-box;
}
우와! 이렇게나 다양하다니... 신기하다! 아! 그럼 마지막으로 셀렉터를 한 번 알아볼까?
/* 전체 셀렉터 */
* { }
/* 태그 셀렉터 -> 복수 선택 가능*/
h1 { }
div { }
section, h1 { }
/* ID 셀렉터 */
#only { }
/* class 셀렉터 */
.widget { }
.center { }
/* attribute 셀렉터 */
a[href] { } /*태그[속성명] 속성명이 있는 항목*/
p[id="only"] { } /*태그 [속성명="속성값"] 속성명에 속성값과 일치하는 항목*/
p[class~="out"] { } /*태그[속성명~="속성값"] 속성값에 공백이 있는 경우 그 중 하나라도 일치하는 항목 or 공백이 없으면 정확히 일치하는 속성값이 있는 항목*/
p[class|="out"] { } /* 태그[속성명|="속성값"] 속성값에 하이픈(-)이 있는 경우 속성값으로 시작하는 항목 or 하이픈(-)이 없으면 정확히 일치하는 값이 있는 항목 */
section[id^="sect"] { } /* 태그[속성명^="속성값"] 속성값으로 시작하는 항목 */
div[class$="2"] { } /*태그[속성명$="속성값"] 속성값으로 끝나는 항목*/
div[class*="w"] { } /* 태그[속성명*="속성값"] 속성값을 포함하는 항목*/
/* 전체 셀렉터 */
* { }
/* 태그 셀렉터 -> 복수 선택 가능*/
h1 { }
div { }
section, h1 { }
/* ID 셀렉터 */
#only { }
/* class 셀렉터 */
.widget { }
.center { }
/* attribute 셀렉터 */
a[href] { } /*태그[속성명] 속성명이 있는 항목*/
p[id="only"] { } /*태그 [속성명="속성값"] 속성명에 속성값과 일치하는 항목*/
p[class~="out"] { } /*태그[속성명~="속성값"] 속성값에 공백이 있는 경우 그 중 하나라도 일치하는 항목 or 공백이 없으면 정확히 일치하는 속성값이 있는 항목*/
p[class|="out"] { } /* 태그[속성명|="속성값"] 속성값에 하이픈(-)이 있는 경우 속성값으로 시작하는 항목 or 하이픈(-)이 없으면 정확히 일치하는 값이 있는 항목 */
section[id^="sect"] { } /* 태그[속성명^="속성값"] 속성값으로 시작하는 항목 */
div[class$="2"] { } /*태그[속성명$="속성값"] 속성값으로 끝나는 항목*/
div[class*="w"] { } /* 태그[속성명*="속성값"] 속성값을 포함하는 항목*/
- 첫 번째로 입력한 요소의 바로 아래 자식인 요소를 선택한다.
- 아래 예시의 경우
<header>요소 바로 아래에 있는 두 개의<p>요소는 선택되지만,<span>``header p {}``header p {}요소의 자식인<p>요소는 선택되지 않는다.
header > p { }
<header>
<p> <!-- 선택 -->
<span>
<p></p>
</span>
</p>
<p> <!-- 선택 -->
<span>
<p></p>
</span>
</p>
</header>
- 첫 번째로 입력한 요소의 후손을 선택한다.
- 아래 예시의 경우
<header>요소의 자식인<p>요소 뿐 아니라,<header>요소의 자식인<p>요소까지 모두 선택한다.
header p {}
<header>
<p><!-- 선택 -->
<span>
<p><!-- !!선택!! -->
</p>
</span>
</p>
<p><!-- 선택 -->
<span>
<p><!-- !!선택!! -->
</p>
</span>
</p>
</header>
- 같은 부모 요소를 공유하면서, 첫 번째 입력한 요소 뒤에 오는 두 번째 입력한 요소를 모두 선택한다.
- 아래 예시의 경우
<section>요소 뒤에 있는 세 개의<p>``section ~ p { }요소를 모두 선택한다.
section ~ p { }
<header>
<section></section>
<p></p> <!-- 선택 -->
<p></p> <!-- 선택 -->
<p></p> <!-- 선택 -->
</header>
- 같은 부모 요소를 공유하면서, 첫 번째 입력한 요소 바로 뒤에 오는 두 번째 입력한 요소를 선택한다
- 예시의 경우
<section>요소 뒤에 있는 세 개의<p>요소 중 첫 번째<p>요소를 선택한다.
section + p { }
<header>
<section></section>
<p></p> <!-- 선택 -->
<p></p>
<p></p>
</header>
가상 클래스는 요소의 상태 정보에 기반해 요소를 선택한다
a:link { } /*사용자가 방문하지 않은 <a>요소를 선택합니다.*/
a:visited { } /*사용자가 방문한 <a>요소를 선택합니다. */
a:hover { } /* 마우스를 요소 위에 올렸을 때 선택합니다. */
a:active { } /* 활성화 된(클릭된) 상태일 때 선택합니다. */
a:focus { } /* 포커스가 들어와 있을 때 선택합니다. */
input:checked + span { } /*체크 상태일 때 선택합니다. */
input:enabled + span { } /*사용 가능한 상태일 때 선택합니다. */
input:disabled + span { } /*사용 불가능한 상태일 때 선택합니다. */
p:first-child { }
ul > li:last-child { }
ul > li:nth-child(2n) { }
section > p:nth-child(2n+1) { }
ul > li:first-child { }
li:last-child { }
div > div:nth-child(4) { }
div:nth-last-child(2) { }
section > p:nth-last-child(2n + 1) { }
p:first-of-type { }
div:last-of-type { }
ul:nth-of-type(2) { }
p:nth-last-of-type(1) { }
input:not([type="password"]) { }
div:not(:nth-of-type(2)) { }
input[type="text"]:valid { }
input[type="text"]:invalid { }