Level 3-1. HTML/CSS

soheey·2021년 5월 25일
0

HTML(HyperText Markup Language)

  • 웹페이지의 틀, 구조를 표헌하는 언어(Markup)
  • Tag(<>)
    • 트리구조
    • opening tag, closing tag, self-closing tag(ex.img)
    • div, span
    • ul, ol, li
    • input type
  • class, id로 semantic(의미) 하게 분류, semantic tag 남용 ✕
  • < header >나 < footer >, < code > 등의 태그는 < div >, < span >에 비해 더 의미론적 태그

HTML 퀴즈

다음 중 HTML Tag는? (정답 두개) 3, 4
다음 중 HTML attribute name은? class (HTML 속성(attribute)는 두 가지로 구성되는데, attribute name(속성의 이름)과 attribute value(속성의 값) 으로 구성됩니다. 위 예제에서 속성의 이름은 class입니다. attribute value(속성의 값)과 분명히 구분되어야 합니다.)

HTML의 정의와 가장 유사한 것은? "HTML은 구조를 표현하기 위한 언어다."(HTML Living Standard, MDN참고)

다음 중 자바스크립트 실행과 가장 밀접한 것은?

다음 중 빨간색 사각형 부분에 알맞은 HTML Element는? < a >
(anchor(닻; 배의 위치를 고정)의 약자로, 다른 웹페이지로 연결되는 하이퍼링크를 HTML 문서에 표시할 때 사용합니다. 주로 href 속성과 사용됩니다.)

다음 중 빨간색 사각형 부분에 알맞은 HTML Element는? < p > (paragraph(문단)의 약자로, 하나의 문단을 표현하기 위하여 사용됩니다.)

다음 중 빨간색 사각형 부분에 알맞은 HTML Element는? < section > (HTML < section > 엘리먼트는 웹 페이지의 큰 의미 단위가 될 수 있는 어떤 것이든 묶어서 하나의 구역을 구분하는데 사용됩니다. 이 엘리먼트는 HTML5 표준의 탄생과 함께 생겨난 시멘틱 엘리먼트의 일부입니다. 엘리먼트의 이름에 의미를 충분히 담고 있기 때문입니다.

< div > 엘리먼트는 HTML5 이전에는 하나의 구역(division)을 나타내기 위해 사용할 수 있었지만, 지금은 어떤 큰 구역을 구분하기 위하여 사용되는 것은 지양되고 있습니다. 다만, 작은 구역에서 불가피하게 div를 사용해야 하는 "최악(as a last resort)"로는 사용해도 괜찮습니다.)

다음 중 빨간색 사각형 부분에 알맞은 HTML Element는? < ul >
(HTML < ul > 엘리먼트는 unordered list(목록)의 약자로, 순서가 없는 데이터를 표현하는 경우에 적절합니다.)

아래 그림의 빨간색 사각형 부분에 알맞은 HTML 엘리먼트는? < h1 >

아래 그림의 빨간색 사각형 부분에 알맞은 HTML 엘리먼트는? < img >

CSS

HTML에 id와 class를 적절히 부여했다면, CSS가 적재적소에서 명확하게 웹 페이지가 표현하고자 하는 바를 보여줄 것입니다. 예를 들어, 모든 트위터 메세지에 class가 부여되어 있으면 CSS Selector를 통해 한 번에 변경할 수 있습니다. 즉, 그룹을 잘 지어둔다면 하나의 HTML tag를 고치기 위해서 똑같은 코드를 반복하여 작성할 이유가 없다는 의미가 되겠죠!

  • inline, HTML 외부, HTML 내부
  • selector
    • '#' , '.'
    • 부모 자식 관계
    • 클래스 동시에 적용하는 법, 여러 클래스 적용하는 법
  • box model
    • margin, padding, border
    • width, height, top, left, bottom, right
  • position
    • static, relative, fixed, absolute, sticky
  • z-index, float (advanced)
  • flexbox (advanced)
  • grid (advanced)
  • w3school
  • element에 class를 사용해야 할 때와 id를 사용해야 할 때
  • color, background-color, box-shadow, text-decoration, font-size, font-family, font-weight, display

CSS로 Layout 만들기

CSS는 스타일링입니다

하지만 CSS는 단순히 디자인만을 위한 것은 아닙니다.

  1. 적당한 위치에 콘텐츠 배치 (레이아웃)
  2. 텍스트 강조와 같은 최소한의 타이포그래피(조판, typography: 문자배열)
  3. 최소한의 접근성 (예를 들어 색상)

CSS에 대한 오해

CSS는 디자이너의 영역이다?

어떤 개발자든 간단한 UI를 만들 줄 아는 것은 기본적인 소양입니다. 그리고 적당한 위치에 콘텐츠 배치 (레이아웃)의 측면은 디자이너가 아니더라도 할 수 있어야만 합니다.

일반 사용자를 대상으로 하는 앱은, UI가 없으면 소용이 없습니다.

다음과 같은 UI를 한번 살펴볼까요? 다음은 자동차의 주행기록을 기록하는 앱입니다. 다소 복잡해보이는 UI를 가지고 있긴 하지만, 자동차의 주행을 기록하려는 목적을 갖고 있는 사람에게는 이만한 솔루션도 없을 겁니다. 어쨌든 중요한 것은 아무리 훌륭한 내부 기능을 갖고 있더라도 UI가 없으면 소용이 없다는 이야기입니다.

물론, 더 나은 사용자 경험을 위해서는 다음과 같이 UX적인 측면을 고려해야 합니다. 똑같은 앱을 어떻게 리디자인했는지 한번 살펴보죠.

두번째 화면을 만드려면, 디자인을 배워야 하는 것 아닌가요?

자 두번째 화면을 보고 곰곰히 생각해봅시다. 두번째 화면에 여러분이 포토샵 같은 전문 이미지 툴을 써서 만들어야 할 부분이 있나요?

  • 검색해서 무료로 사용할 수 있는 아이콘들을 쉽게 찾을 수 있습니다. (검색어: free app icon)

  • 네모 혹은 둥근 네모, 동그라미와 같은 도형들은 CSS로 쉽게 만들 수 있습니다.

프론트엔드 개발자가 되려면...

프론트엔드, 즉 사용자가 직접 사용하는 애플리케이션의 앞단을 개발할 때에는 결국 다음과 같은 소양이 필요합니다.

  • 화면 구성을 할 줄 아는 능력 (레이아웃)
  • 보기 좋은 화면을 만들 줄 아는 능력 (타이포그래피, 색상)

다음은 있으면 좋은 소양입니다.

  • 정렬이 어긋나거나 배색이 좋지 않음을 인지할 수 있는 감각
  • 사용자가 사용하기 편한 앱이 무엇인지, 왜 편하게 느끼는지에 대한 이유를 분석해본 경험

CSS는 배우기 어렵다?

CSS 고유의 복잡함을 다루기 위해서, 모든 종류의 다양한 모범 사례(best practice)가 만들어졌습니다. 문제는, 어떤 모범 사례가 실제로 제일 나은지 대한 합의된 내용이 없고, 모범 사례 중 많은 것들이 서로 완전히 상충되는 것처럼 보입니다.

이상 원문을 발췌하였습니다: https://medium.com/actualize-network/modern-css-explained-for-dinosaurs-5226febe3525

Achievement Goals

다음 화면을 최종적으로 만들어보는 게 목표입니다.

Getting Started

다음과 같은 HTML부터 시작합니다. 조금 낯선 태그가 등장하는 것을 두려워하지 마세요. 여기서 등장하는 < header > < main > < nav > < aside > < footer > 태그는 < div > 태그와 똑같이 작동합니다. 이를 시맨틱 태그라고 하며, 태그에 의미를 담아 콘텐츠 영역을 논리적으로 구분하기 위한 용도로 쓰입니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Modern CSS</title>
  <link rel="stylesheet" href="index.css" />
</head>
<body>
<header>This is the header.</header>
<div class="container">
  <nav>
    <h4>This is the navigation section.</h4>
    <ul>
      <li>Home</li>
      <li>Mac</li>
      <li>iPhone</li>
      <li>iPad</li>
    </ul>
  </nav>
  <main>
    <h1>This is the main content.</h1>
    <p>...</p>
  </main>
  <aside>
    <h4>This is an aside section.</h4>
    <p>...</p>
  </aside>
</div>
<footer>
  <ul>
    <li>개인정보 처리방침</li>
    <li>이용 약관</li>
    <li>법적 고지</li>
  </ul>
</footer>
</body>
</html>

index.css 파일에는 다음 내용을 채워넣읍시다.

body {
  margin: 0;
  padding: 0;
  background: #fff;
  color: #4a4a4a;
}
header, footer {
  font-size: large;
  text-align: center;
  padding: 0.3em 0;
  background-color: #4a4a4a;
  color: #f9f9f9;
}
nav {
  background: #eee;
}
main {
  background: #f9f9f9;
}
aside {
  background: #eee;
}

codepen에서 확인하기

CSS 내용 분해하기

CSS 문법의 구성은 다음과 같습니다.

중괄호 앞에 등장하는 태그 이름은 셀렉터(selector)라고 부르며, 중괄호에 속성과 값을 적어 스타일을 표현합니다. 각 속성과 속성 사이는 반드시 세미콜론(;)으로 구분해야 합니다.

질문

  • 위 CSS 예제에서 등장하는 속성은 어떤 것들이 있나요?
  • 텍스트의 가운데 정렬을 하기 위한 속성은 무엇인가요?
  • 글자 색을 바꾸기 위한 속성은 무엇인가요?
  • 배경 색을 바꾸기 위한 속성은 무엇인가요?
  • background 속성과 background-color 속성은 어떻게 다른가요?
  • em의 의미는 무엇인가요?

CSS 파일 추가

CSS 파일을 추가하는 부분은 HTML 문서 6번째 줄에 등장합니다. href 속성을 통해 파일을 링크합니다.

<link rel="stylesheet" href="index.css" />

똑같은 구조에 다른 스타일을 적용함으로 완전히 새로운 모양으로 탈바꿈할 수도 있습니다.

layout.css 파일을 하나 만들어서 다음과 같이 내용을 채우고, < link > 태그를 하나 더 추가해봅시다. 이번 CSS는 위에서 아래로 내려오는 구성이 아니라, 본격적으로 레이아웃을 어떻게 잡는지 보여주고 있습니다. flex와 같은 속성은 추후 레이아웃을 배울 때 좀 더 살펴봅시다.

<link rel="stylesheet" href="index.css" />
<link rel="stylesheet" href="layout.css" />
body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.container {
  display: flex;
  flex: 1;
}
main {
  flex: 1;
  padding: 0 20px;
}
nav {
  flex: 0 0 180px;
  padding: 0 10px;
}
aside {
  flex: 0 0 130px;
  padding: 0 10px;
}

codepen에서 확인하기

사실, 직접 HTML 태그에 CSS 속성을 추가하는 방법도 있습니다. 그러나, 이는 관심사 분리 측면에서 권장되지 않습니다. HTML이 설계와 디자인을 둘 다 하게 두지 말고, HTML은 설계만 신경쓰고, CSS는 디자인만 신경쓰게 하자는 의도죠. 직접 CSS 속성을 추가하는 방법은 알려만 드릴게요, 이렇게 쓰지는 말고 참고만 하세요.
CSS 스타일을 적용할 수 있는 3가지 방법 (인라인 스타일, 내부 스타일 시트, 외부 스타일 시트) 중 인라인 스타일로 작성한 방법입니다.

<nav style="background: #eee; color: blue">...</nav>

기본적인 셀렉터 (selector)

id로 이름 붙여서 스타일링 적용하기

앞서 만들어본 HTML에는 < h4 > 나 < p > 엘리먼트가 여럿 존재합니다. navigation section 아래에 있는 < h4 >만 선택해서 색을 바꿔보려면 어떻게 해야 할까요? 먼저 아래와 같이 시도해봅시다.

h4 {
  color: red;
}

codepen에서 확인하기

자세히 살펴보면 의도하지 않았던 aside section에 있는 < h4 >에도 빨간색이 적용되는 것을 확인할 수 있습니다. navigation section 아래의 < h4 >를 특정하기 위해서는 이 엘리먼트에 id를 이용해 이름을 붙여서 해결할 수 있습니다. 이름을 붙일 때에는 의미를 담아서 붙입시다. CSS에는 #기호를 이용해 id를 선택할 수 있습니다.

<h4 id="navigation-title">This is the navigation section.</h4>
#navigation-title {
  color: red;
}

codepen에서 확인하기

class로 스타일을 분류하여 적용하기

이번엔 class를 지정해서 navigation section의 < li > 엘리먼트와 footer의 < li > 엘리먼트를 구분하는 방법을 알아봅시다. 앞서 시도한 방법으로 < li >을 선택해서 스타일링을 시도해봅시다. 이번엔 밑줄을 그어봅시다.

li {
  text-decoration: underline;
}

codepen에서 확인하기

마찬가지로 의도하지 않게 footer에 있는 < li >에도 밑줄이 적용되어 있습니다. navigation section의 < li > 엘리먼트에 적용하기 위해 다음 예제와 같이 id를 여러 엘리먼트에 적용하는 것은, 잘못된 사용 방법입니다. 왜냐하면, id는 문서 내에 단 하나의 엘리먼트에만 적용할 수 있는 유일한 이름이어야 하기 때문입니다.

<!-- 잘못된 예제 -->
<ul>
  <li id="menu-item">Home</li>
  <li id="menu-item">Mac</li>
  <li id="menu-item">iPhone</li>
  <li id="menu-item">iPad</li>
</ul>

이 때에는 class를 이용해주어야 합니다. 다음과 같이 class로 동일한 스타일을 목적이 동일한 여러 엘리먼트에 적용할 수 있습니다. 이 때에는, #이 아닌 .을 이용해 선택해줄 수 있습니다.

<!-- 바른 예제 -->
<ul>
  <li class="menu-item">Home</li>
  <li class="menu-item">Mac</li>
  <li class="menu-item">iPhone</li>
  <li class="menu-item">iPad</li>
</ul>
.menu-item {
  text-decoration: underline;
}

codepen에서 확인하기

여러 개의 class를 하나의 엘리먼트에 적용하기

class는 하나의 엘리먼트에 여러 개를 적용할 수 있습니다. 공백을 이용해서 class 이름을 분리해줍시다. class 이름이 목적에 맞는지 잘 살펴보세요. 우리는 이를 보고 다음 < li >엘리먼트가 "여러 개의 메뉴 중, 선택되어 있는 메뉴"임을 짐작해볼 수 있습니다.

<li class="menu-item selected">Home</li>
.selected {
  font-weight: bold;
  color: #009999;
}

정리

class와 id의 차이점을 반드시 기억하세요.

색상

글자 색상으로는 color 속성을 사용합니다. 값으로는 HEX (16진수로 RGB가 표현된 값) 또는 주요 색상 이름을 사용할 수 있습니다.

.red {
  color: #ff0000;
}

배경 색상이나, 이후에 나올 박스 테두리 색상을 적용할 수도 있습니다.

.box {
  color: #155724; /* 글자 색상 */
  background-color: #d4edda; /* 배경 색상 */
  border-color: #c3e6cb; /* 테두리 색상 */
}

글꼴

글꼴은 font-family를 사용합니다.

.emphasize {
  font-family: "SF Pro KR", "MalgunGothic", "Verdana";
}

글꼴 이름은 따옴표를 붙여서 사용할 수 있으며, 여러 글꼴을 쉼표로 구분하여 적을 수 있는데 이는 순서대로 fallback(표현하고 싶은 글꼴이 없을 시에 사용하는 대비책)을 위한 글꼴입니다.

보다 다양한 글꼴을 사용하고 싶어요!

위에서 언급한 fallback에 대해 짐작할 수 있듯, 내가 보여주고 싶은 글꼴이라고 전부 적용할 수 있다는 것이 아닙니다. 기본적으로, 상대방의 컴퓨터에 깔려있지 않은 글꼴은 아무리 아름다운 글꼴을 내가 적용한다 해도 상대방의 웹브라우저에 보이지 않습니다. 이 문제를 해결한 것이 바로 웹 폰트 기술입니다. 표현하고 싶은 글꼴을 적용하되, 누구에게나 아름답게 표현될 수 있도록 웹에서 필요에 따라 다운로드 받게 하는 기술입니다. 링크된 문서를 읽어보면 아시겠지만, 생각보다 간단하게 구현할 수 있는 부분은 아닙니다.

Google Fonts라는 서비스는 다양한 웹 폰트를 쉽게 사용할 수 있게 도와줍니다. 한글 글꼴도 많이 준비되어 있고, 다음과 같이 embed 할 수 있는 코드도 쉽게 사용할 수 있어 많이 이용됩니다.

크기

font-size를 이용합니다

.title {
  font-size: 24px;
}

알아야 할 몇가지 단위

글꼴 크기에서 중요한 것은 다름아닌 단위입니다. 두가지 종류의 단위가 있습니다. 바로 절대 단위와 상대 단위입니다.

  • 절대 단위: px, pt(포인트) 등
  • 상대 단위: %, em, rem, ch, vw, vh 등

MDN 등에서 더 많은 단위 정보를 찾을 수 있습니다. 여기에서는 절대 단위와 상대 단위의 비교, 그리고 어떤 단위를 쓰는 것이 적합한지 안내합니다.

  1. 절대적이고 확실한 크기로 정하고 싶을 때
    px(픽셀)을 사용하면 됩니다. 다만, px은 접근성에 불리합니다. 이 말은 곧 CSS를 통해 글꼴 크기는 고정되기 때문에, 작은 글씨를 보기 힘든 사용자가 브라우저 기본 글꼴 크기를 더 크게 설정했다 하더라도 이런 설정이 무시되는 단점이 있습니다. 결과적으로 개발자가 강조하려던 제목(heading) 등이 오히려 일반 텍스트보다 작게 보이는 결과를 초래할 수 있습니다. 또한 px은 모바일 기기와 같이 작은 화면이면서 고해상도인 경우에도 적합하지 않습니다. 기본적으로 고해상도에서는 1px이 모니터의 한 점보다 크게 업스케일(upscale)되기 때문에, 뚜렷하지 못한 형태로 출력될 수 있습니다. px은 화면 크기가 절대적인 경우에 (예를 들어 출력용) 유리합니다.

  2. 보통의 경우
    rem을 추천합니다. root의 글자 크기, 즉 브라우저의 기본 글자 크기가 1rem이며, 두배로 크게 하고 싶다면 2rem, 작게 하려면 0.8rem 등으로 조절해서 사용할 수 있습니다. 이는 사용자가 설정한 기본 글꼴 크기를 따르므로, 접근성에 유리합니다. (em은 부모 엘리먼트에 따라 상대적으로 크기가 변경되므로 계산이 어렵습니다. 이에 비해 rem은 root의 글자 크기에 따라서만 상대적으로 변합니다.)

  3. 반응형 웹(responsive web)에서는 디바이스 크기 별로 CSS를 달리 적용해야 합니다. 이 때에, 디바이스 크기를 나누는 기준을 보통 px로 정합니다. 예를 들어 iPhone 12 Pro Max의 너비는 414px 입니다. 보통 450px 미만의 너비를 갖는 디바이스는 스마트폰 세로 모드로 생각해도 좋습니다. 크롬 브라우저에서는 자주 사용하는 디바이스의 너비(width)와 높이(height)별로 실제로 어떻게 보이는지 테스트해볼 수 있습니다.

  4. 화면 너비 및 높이에 따른 상대적인 크기가 중요한 경우
    이 때에는 vw, vh를 사용하세요. 웹사이트의 보여지는 영역을 Viewport라고 합니다. 간혹 화면을 가득 채우며 딱 떨어지게 스크롤되는 사이트를 본 적이 있을겁니다. 이는 100vw, 100vh를 사용해 구현한 것입니다. (참고로 < body > 태그에서의 %는 HTML이 차지하는 모든 영역, 즉 지금은 보이지 않으나 스크롤했을 때 보이는 영역까지 포함했을 때에 비율입니다.)
    codepen에서 확인하기
    예시 사이트 1
    예시 사이트 2
    예시 사이트 3

기타 스타일링

  • 굵기: font-weight
  • 밑줄, 가로줄: text-decoration
  • 자간: letter-spacing
  • 행간: line-height

정렬

가로로 정렬할 경우 text-align을 사용합니다. 유효한 값으로는 left, right, center, justify(양쪽 정렬)가 있습니다.

세로로 정렬할 경우에는 문제가 조금 복잡합니다. 보통 vertical-align을 생각하기 쉽지만, 이는 부모 엘리먼트의 종류를 특정해야 합니다. (부모 엘리먼트가 display: table-cell 일 경우에만 사용 가능) 결국 세로 정렬이란 것은 둘러싸고 있는 박스의 높이가 글자 높이보다 큰 경우에 발생하는 것인데, 이는 박스에 대한 이해가 선행됩니다. 이후 배우게 될 박스 모델 및 레이아웃에서 이 문제를 조금 더 자세히 다뤄보겠습니다.

어떤 태그를 사용해야 하나요?

텍스트를 담는 여러가지 태그가 존재합니다. 우리가 이미 알고 있는 < div > < span >을 비롯해 앞서 따라하기 시간을 통해 시맨틱 태그라는 것도 알았습니다. 어떤 것을 사용해도 상관이 없고, 고유의 스타일을 가지고 있는 태그에 대한 이해만 있으면 됩니다. 예를 들어 < li > 태그의 경우에는 항상 bullet이 등장하고, 왼쪽 여백이 존재하죠. 다만, 우리는 다음 태그의 사용은 지양해야 합니다.

< center > < font >를 사용하지 말아야 하는 이유

원래 HTML 초창기에는, 스타일을 따로 정의하겠다는 컨셉 자체가 존재하지 않았습니다. 그래서 < center >가운데 정렬< /center > 혹은 < font color="#ff0000" >빨간 글자< /font >와 같은 사용 예도 존재했었죠. 하지만 지금은 더이상 사용해서는 안되는 태그입니다. 이는 앞서 언급했던 관심사 분리 때문입니다. HTML이 설계와 디자인을 둘 다 하게 두지 말고, HTML은 설계만 신경쓰고, CSS는 디자인만 담당하게 합시다.

모든 콘텐츠는 고유한 영역이 있습니다.

모든 콘텐츠는 각자의 영역을 가지며, 보통 엘리먼트로 묶이는 콘텐츠가 하나의 박스가 됩니다.

박스는 항상 사각형이고 그 너비(width)와 높이(height)가 있습니다. 그래서 다음과 같이 CSS 속성으로 그 크기를 설정해줄 수 있습니다. 다음 예제에 width, height 속성을 넣어 테스트해보세요.

팁: 박스가 차지하는 영역을 시각적으로 확인하기 위해 배경색을 꼭 넣어주세요!

<h1>Basic document flow</h1>
<p>I am a basic block level element. My adjacent block level elements sit on new lines below me.</p>
<p>By default we span 100% of the width of our parent element, and we are as tall as our child content. Our total width and height is our content + padding + border width/height.</p>
<p>We are separated by our margins. Because of margin collapsing, we are separated by the width of one of our margins, not both.</p>
<p>inline elements <span>like this one</span> and <span>this one</span> sit on the same line as one another, and adjacent text nodes, if there is space on the same line. Overflowing inline elements will <span>wrap onto a new line if possible (like this one containing text)</span>, or just go on to a new line if not</p>
h1 {
  background: gray;
  width: 60%;
}

p {
  background: rgba(255,84,104,0.3);
  width: 80%;
  height: 200px;
}

span {
  background: yellow;
  width: 100px;
  height: 100px;
}

codepen에서 확인하기

질문

  • 위 HTML에서 줄바꿈이 되는 태그는 무엇인가요? 줄바꿈이 적용되지 않은 태그는 무엇인가요?
  • 위 CSS 선언 중 실제로 작동하지 않는 것이 존재합니다. 그게 무엇인가요?

줄바꿈이 되는 박스(block) vs. 옆으로 붙는 박스(inline, inline-block)

박스의 종류는 줄바꿈이 되는 박스와 옆으로 붙는 박스로 구분할 수 있습니다. 이를 각각 block 박스, inline 박스라고 부릅니다. 그리고 이 두가지 박스 종류의 특징이 섞인, 옆으로 붙으면서, block 박스의 특징을 갖는 inline-block 박스도 있습니다.

위 예제에서, 줄바꿈이 되는 태그와 그렇지 않은 태그는 무엇이었나요?

정답

  • 위 HTML에서 줄바꿈이 되는 태그는 무엇인가요? 줄바꿈이 적용되지 않은 태그는 무엇인가요?
    • 줄바꿈이 되는 태그: < h1 > < p >
    • 줄바꿈이 되지 않는 태그: < span >

정답을 통해, < h1 > < p > 등은 block 박스이며, < span >은 inline 박스임을 알 수 있습니다. 내가 사용하는 태그가 어떤 것이 block이며, inline임을 알 수 있을까요? MDN block 엘리먼트 목록, inline 엘리먼트 목록을 찾아보는 것도 한 방법이지만, 개발자 도구의 Element 탭에서도 확인할 수 있습니다.

다음은 block level element 입니다.

다음은 inline level element 입니다.

무엇이 block 엘리먼트인지 inline 엘리먼트인지를 외워서 공부하기 보다는, 개발하면서 자연스럽게 습득하시길 바랍니다.

두번째 질문에 대한 정답을 알아봅시다. 어떤 태그에는 CSS의 width, height 속성이 작동하지 않는 경우가 있을겁니다.

정답

  • 위 CSS 선언 중 실제로 작동하지 않는 것이 존재합니다. 그게 무엇인가요?
    • < span >

위 예제에서 span의 경우는 width, height 속성이 적용되지 않습니다. 자 이렇게 보면, block 박스와 inline 박스의 특징을 어렴풋이 짐작할 수 있을 것입니다. 이번엔 위 CSS에서 span에 대한 속성을 다음과 같이 바꿔봅시다.

span {
  background: yellow;
  display: inline-block;
  width: 100px;
  height: 100px;
}

codepen에서 확인하기

inline-block 박스는 옆으로 붙으면서, 고유의 크기를 갖게 됨을 확인할 수 있습니다. 자 그럼 이 세가지 박스의 특성을 정리해봅시다.

박스를 구성하는 요소

박스 모델은 다음 그림만 기억하면 됩니다.

border(테두리), padding(안쪽 여백), margin(바깥 여백)

border

테두리는 심미적으로도 필요하지만, 개발 과정에서도 매우 의미있게 사용됩니다. 각 영역이 해당하는 크기를 알기 위해서 보통 레이아웃을 만들 때에 다음과 같이 그 크기를 시각적으로 확인할 수 있도록 만듭니다.

p {
  border: 1px solid red;
}

각각의 값은 테두리 두께(border-width), 테두리 스타일(border-style), 테두리 색상(border-color)입니다. 괄호 안에 적힌 것들이 바로 border를 구성하는 세부 속성들입니다. 그러므로 border-style mdn과 같이 검색하면, 테두리 스타일의 다양한 값을 찾아볼 수 있습니다.

질문

  • 테두리를 점선으로 만들고 싶으면 어떻게 해야 할까요? border-style의 값 중 하나를 바꿔보세요.
  • 테두리를 둥근 모서리로 만들 수도 있습니다. 어떤 속성을 사용하면 되나요? 참고로, border 속성만으로는 둥근 모서리를 만들 수 없습니다.
  • 박스 바깥쪽에 그림자를 넣을 수도 있습니다. 어떤 속성을 사용하면 되나요? 참고로, 그림자를 명확하게 보기 위해서는 background 속성이 불투명해야 합니다.

margin

p {
  margin: 10px 20px 30px 40px;
}

각각의 값은 top, right, bottom, left로 시계방향입니다. 어떻게 적용되는지 확인하려면, 개발자 도구 -> Element 탭의 다음 그림을 확인하세요. margin은 주황색으로 표현됩니다.

p {
  margin: 10px 20px;
}

값을 두개만 넣으면 top과 bottom이 10px, left 및 right가 20px 입니다.

p {
  margin: 10px;
}

값을 하나만 넣으면 모든 방향의 바깥 여백에 적용됩니다. 물론 다음과 같이 방향을 특정한 속성도 존재합니다.

p {
  margin-top: 10px;
  margin-right: 20px;
  margin-bottom: 30px;
  margin-left: 40px;
}

위와 같은 규칙은 padding에도 동일하게 적용됩니다.

바깥 여백은 재미있게도 음수값이 지정이 가능합니다. 음수 값의 여백을 통해 다른 엘리먼트와의 간격을 떨어뜨리는 것이 아닌, 오히려 줄어들게 만들 수 있습니다. 극단적으로 적용하면, 화면(viewport)에서 아예 사라지게 하거나, 다른 엘리먼트와 겹치게 만드는 것도 가능하죠.

p {
  margin-top: -2rem;
}

codepen에서 확인하기

padding

말 그대로 안쪽 여백입니다. 값 순서에 따른 방향은 margin과 동일합니다.

p {
  padding: 10px 20px 30px 40px;
}

배경색이나 border를 적용하면 더욱 안쪽 여백을 선명하게 볼 수 있습니다.

p {
  padding: 10px 20px 30px 40px;
  border: 1px solid red;
  background-color: lightyellow;
}

개발자 도구 -> Element 탭의 다음 그림을 확인하세요. padding은 초록색으로 표현됩니다.

넘치는 컨텐츠 처리

박스의 height를 컨텐츠가 차지하는 공간보다 더 줄여보세요. 컨텐츠가 박스 바깥으로 빠져나오나요? 아니면 박스에 맞게 가려지나요?

p {
  height: 40px;
}

기본적으로 박스 크기보다 컨텐츠 크기가 더 큰 경우, 박스 바깥으로 빠져나오는 것이 기본 동작입니다. 하지만 대부분 이런 상황을 원하지 않을 것입니다. 이 때에, 한정된 박스 크기에 맞게 컨텐츠가 더이상 표시되지 않게 하거나, 혹은 박스 안쪽으로 스크롤하여 컨텐츠를 볼 수 있게 만드는 것이 가능합니다.

p {
  height: 40px;
  overflow: auto;
}

codepen에서 확인하기

auto 속성은 컨텐츠가 넘치면 자동으로 스크롤되게 만듭니다. 아예 넘치는 컨텐츠를 무시하고 가리고 싶을 경우 hidden을 사용합니다. overflow 속성은 x축과 y축을 따로 지정하는 것도 가능합니다. (overflow-x, overflow-y) 이렇게 하면 한 방향으로만 스크롤이 가능하게 만들 수도 있습니다.

박스 크기 측정 기준

박스 크기를 측정하는 기준은 매우 중요합니다. 다음과 같은 상황을 상정해봅시다.

<div id="container">
  <div id="inner">
    안쪽 box
  </div>
</div>
#container {
  width: 300px;
  padding: 10px;
  background-color: yellow;
  border: 2px solid red;
}

#inner {
  width: 100%;
  height: 200px;
  border: 2px solid green;
  background-color: lightgreen;
  padding: 30px;
}

codepen에서 확인하기

자 문제가 무엇인지 인지하셨나요? 하나하나 살펴보죠.

  • #container의 너비는 300px이 아닙니다. 정확히 324px이죠. 이는 다음 계산의 결과입니다.

    300 (콘텐츠 영역)

  • 10 (padding-left)
  • 10 (padding-right)
  • 2 (border-left)
  • 2 (border-right)
  • #inner의 100%는 300px이 아닙니다. 364px을 차지하고 있습니다. 어떻게 된 일일까요?

    300 (300px의 100%)

  • 30 (padding-left)
  • 30 (padding-right)
  • 2 (border-left)
  • 2 (border-right)

우리가 생각하는 박스의 크기는 여백을 포함한 것이 아닙니다. 박스의 사이즈는, 오롯이 콘텐츠 영역에만 적용되어 있습니다. 이러한 계산 방식은 레이아웃을 어렵게 만듭니다.

다행히 여기에 여백과 테두리 두께를 포함한 박스 계산 방법이 존재합니다. 아래 스타일을 추가합시다.

* {
  box-sizing: border-box;
}

codepen에서 확인하기

자 이렇게 해주면, 300px은 이후에 모든 여백과 테두리를 포함한 크기로 계산됩니다. * 셀렉터는 HTML의 모든 태그, 모든 영역에 적용하겠다는 의미입니다. box-sizing은 페이지 일부분에 적용할 필요가 없습니다. 오히려 이는 혼란을 가중시키며, 모든 페이지에 적용하는 것이 합리적입니다. 앞으로 레이아웃과 관련된 이야기를 할 때에는 border-box 계산법을 기준으로 이야기할 것입니다. 그러므로, 박스 크기 측정 기준 두가지를 항상 염두해둘 필요가 있습니다.

정리하면 다음 그림과 같습니다. (박스 측정 기준의 기본값은 content-box입니다. 우리는 border-box를 권장합니다.)

CSS Selector

  • 셀렉터
h1 { }
div { }
  • 전체 셀렉터
* { }
  • Tag 셀렉터
section, h1 { }
  • ID 셀렉터
#only { }
  • class 셀렉터
.widget { }
.center { }
  • attribute 셀렉터 (외울 필요는 없습니다)
a[href] { }
p[id="only"] { }
p[class~="out"] { }
p[class|="out"] { }
section[id^="sect"] { }
div[class$="2"] { }
div[class*="w"] { }
  • 후손 셀렉터
header h1 {}
  • 자식 셀렉터 (후손 셀렉터와의 차이를 반드시 알고 있어야 합니다)
header > p { }
  • 인접 형제 셀렉터
section + p { }
  • 형제 셀렉터
section ~ p { }
  • 가상 클래스
a:link { }
a:visited { }
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 { }

레이아웃: 화면을 나누는 방법

HTML 구성하기

기본적으로 콘텐츠의 흐름은 좌에서 우로, 위에서 아래로 흐릅니다. 먼저 수직으로 분할하고, 수직으로 분할된 div에서 height 속성을 이용해 수평 분할을 하면 큰 도움이 됩니다.

여러분들이 예를 들어 VS Code와 비슷한 레이아웃의 앱을 만든다고 가정해봅시다.

위와 같은 앱은 큰 틀에서 추상화하면, 다음과 같이 영역을 나눌 수 있습니다.

앞서 언급한, 수직 분할 그리고 그 후 수평 분할을 생각해보면 다음과 같이 레이아웃 구성이 가능할 것입니다.

<div id="container">
  <div class="col w10">
    <div class="icon">아이콘 1</div>
    <div class="icon">아이콘 2</div>
    <div class="icon">아이콘 3</div>
  </div>
  <div class="col w20">
    <div class="row h40">영역1</div>
    <div class="row h40">영역2</div>
    <div class="row h20">영역3</div>
  </div>
  <div class="col w70">
    <div class="row h80">영역4</div>
    <div class="row h20">영역5</div>
  </div>
</div>

참고: w70이나, h40과 같은 클래스 이름의 구현은 실제로 다음과 같을 것입니다. (이와 같이 클래스 이름과 구현을 1:1로 일치시키는 CSS 작성 기법을 Atomic CSS 방법론이라고 합니다. 클래스 이름 짓는 법에 대한 더 자세한 이야기는 이 링크를 참고하세요. 지금 당장은 몰라도 됩니다!)

.w70 { width: 70%; }
.h40 { height: 40%; }

레이아웃 리셋

때로는 HTML 문서가 갖는 기본 스타일이 레이아웃을 잡는 데 방해가 될 수 있습니다. 어떤 사례가 있는지 찾아볼까요?

  • 박스의 시작을 정확히 (0,0)의 위치에서 시작하고 싶은데, 태그가 기본적으로 약간의 여백을 갖고 있습니다.

  • width, height 계산이 여백을 포함하지 않아서 계산하기 힘듭니다. (지난 시간 박스 크기 측정 기준 - box-sizing에 대해 다뤘던 것을 기억하시죠?)

  • 브라우저마다 여백이나 글꼴이 조금씩 다릅니다.

    이러한 수요에 따라 초기화(리셋)을 위한 다양한 라이브러리가 등장했지만, 사실 굳이 라이브러리를 사용할 필요는 없으며, 위에 언급한 문제를 해결할 몇 줄의 코드를 적용시키기만 한다면, 레이아웃을 잡는데 도움이 될 것입니다.

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

Flexbox로 레이아웃 잡기

flexbox 레이아웃은, 말 그대로 박스를 유연하게 늘리고 줄이는 방법을 토대로 레이아웃을 잡는 방법입니다. 앞서 CSS 따라하기를 통해 flex라는 CSS 속성을 본 적이 있을겁니다. 이제 그 내용이 무엇인지 구체적으로 알아봅시다.

Flex 코드 분석하기

flex는 부모 박스에 display: flex를 적용해줌으로, 자식 박스의 방향과 크기를 결정하는 레이아웃입니다.
기본적으로, flex가 적용된 부모 박스의 자식 박스는 왼쪽으로 차례대로 붙게 됩니다.

<div id="outer">
  <div class="box">box1</div>
  <div class="box">box2</div>
  <div class="box">box3</div>
</div>
#outer {
  display: flex;
  border: 1px dotted red;
  padding: 10px;
}

.box {
  border: 1px solid green;
  padding: 10px;
}

codepen에서 보기

방향 (flex-direction)

기본적으로 flexbox는 박스가 수직으로 분할되지만, 수평으로도 분할할 수 있습니다. flex-direction 속성은 부모 박스에 적용합니다. 자식 박스에 특별한 속성을 주지 않아도 영향을 미칩니다.

주요 속성은 다음과 같습니다. 한번씩 적용해보세요.

  • row (기본값)

  • column

    Must know concepts: grow(팽창 지수), shrink(수축 지수), basis(기본 크기)

    자식 박스에 어떠한 속성도 주지 않으면, 그저 오른쪽으로 컨텐츠 크기만큼 배치됩니다. 이 때의 자식 박스의 flex 속성 기본값은 다음과 같습니다.
    (flex 속성은 부모에 적용하는 것이 아닌, 자식 박스에 적용합니다.)

flex: 0 1 auto;

직관적이지 않은 이 숫자와 속성들은 처음에는 조금 당황스럽게 느껴질 수도 있습니다. 하지만, flexbox가 기본 크기를 바탕으로 필요에 따라 늘릴 수 있다 라는 컨셉을 이해하고 나면, 어떤 식으로도 박스를 나눌 수 있습니다. flex 속성은 자식 박스를 어떤 식으로 늘릴지를 결정합니다. 각각의 값이 의미하는 것은 다음과 같습니다.

flex: <grow> <shrink> <basis>

이 순서는 반드시 외웁시다. 속으로 따라해보세요 "grow shrink basis" 기본값도 외웁시다 "0 1 auto"...

각각을 따로 지정할 수도 있습니다.

flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;

grow, shrink는 단위가 없으며, 비례하는 값입니다. 박스를 여러개로 나누었을 때, 각 자식 박스가 갖는 grow값의 총 합이 n이라고 칩시다. 이 때의 1은 1/n의 크기를 의미합니다, 2는 2/n의 크기를 의미합니다.

HTML을 다음과 같이 바꾸고, target 클래스를 추가해서 이런저런 테스트를 해보면서 이해해봅시다.

<div id="outer">
  <div class="box target">.box.target</div>
  <div class="box">.box</div>
  <div class="box">.box</div>
</div>

grow: 이 박스는 얼마나 늘어날 수 있나요?

grow를 1로 바꿔봅시다. 해당 박스는 가로의 남은 영역 전부만큼 늘어납니다. (총 grow값의 합은 1+0+0이므로, .target은 1/1 = 100%이여야 하지만, .box 안에 이미 콘텐츠가 존재하므로 콘텐츠가 담긴 크기는 보장합니다)

.target {
  flex: 1 1 auto;
}

codepen에서 보기

box 클래스의 flex 속성에 grow를 1로 주면, 모든 박스가 늘어나려고(grow) 하므로, 결과적으로 동일한 비율로 박스가 늘어나게 됩니다. (총 grow 값 1+1+1, 각 박스는 1/3씩 크기를 가짐)

.box {
  flex: 1 1 auto;
}

codepen에서 보기

grow 값은 비율을 의미한다는 것을 잊지 마세요. 모든 자식 박스가 동일한 grow 값을 가질 경우, 각 박스가 동일 비율만큼 차지하므로, 다음 코드는 전부 같은 모양으로 렌더링됩니다.

.box {
  flex: 1 1 auto;
  /*
  flex: 2 1 auto;
  flex: 3 1 auto;
  flex: 4 1 auto;
  */
}

.target {
  /* flex 값을 지정하지 않음 */
}

.box는 그대로 두고, .target만 바꿀 경우, 차지하는 전체 비율만큼 .target의 크기는 커지게 됩니다.

.box {
  flex: 1 1 auto;
}

.target {
  flex: 2 1 auto; /* 자식 박스가 총 세개인데, target만 2의 비율을 가지므로, 결과적으로 가로의 50%를 차지하게 됨 */
}
  • .target의 grow 속성이 1, .box의 grow 속성이 1일 경우, 1+1+1로 박스가 만들어지므로, 속성 1은 1/3의 크기를 가짐

  • .target의 grow 속성이 2, .box의 grow 속성이 1일 경우, 2+1+1로 박스가 만들어지므로, 속성 1은 1/4의 크기를 가짐

codepen에서 보기

shrink: 이 박스는 얼마나 줄어들 수 있나요?

shrink는 grow와 반대로, 차지하는 비율만큼 박스 크기가 작아지게 만듭니다. 사실 비율로 레이아웃을 지정할 경우 grow를 주로 사용합니다. 왜냐하면 shrink는 width나 이후 설명할 basis에 따른 비율이므로 실제 크기를 예측하기 어렵습니다. 보통 shrink는 기본값인 1로 두어도 무방합니다.

basis: 이 박스의 기본 크기는 몇인가요?

박스가 grow나 shrink에 의해 늘어나거나 줄어들기 전 갖게 되는 기본 크기를 의미합니다. grow가 0일 때, basis 크기를 지정하면 그 크기는 보장됩니다.

<div id="outer">
  <div class="left">메뉴</div>
  <div class="right">본문</div>
</div>
.left {
  flex: 0 1 100px; /* grow를 0으로 설정해줘야 100px 이상으로 늘어나지 않습니다. */
}

.right {
  flex: 1 1 auto; /* 우측 박스는 grow를 1로 설정해 나머지 공간을 채워줍시다 */
}

codepen에서 보기

질문: 잠깐, 앞서 언급한 1:1:1 비율의 박스가 정말 1:1:1이 맞나요? 크롬 Element 탭으로 실제 크기를 재보셨나요?

각 박스의 basis를 0%로 한번 만들어보세요. auto와 어떤 차이가 있나요?

한편, grow가 0일때만 크기가 보장된다는 이야기를 다른 말로 표현하면, 경우에 따라 flex 컨테이너 안에 박스가 들어갔을 때, basis로 설정된 크기가 항상 보장되지 않는다는 의미이기도 합니다. grow이 1 이상일 경우, 100px보다 커질 수도 있습니다. 다음은 실제로 레이아웃을 구현할 때, "왜 내 마음대로 안되지?" 라는 생각이 드실 때, 참고하면 좋은 원리입니다.

참고 (이런건 무작정 외우는 게 아니라, 해보면서 원리를 파악하는 겁니다)

  • width와 flex-basis를 동시에 적용하면, flex-basis가 우선됩니다.
  • 안쪽 박스의 콘텐츠가 넘칠 경우, width가 정확한 크기를 보장하지 않을 것입니다.
  • 안쪽 박스의 콘텐츠가 넘치는 경우를 대비해, width 대신 max-width를 쓸 수 있습니다. (flex-basis를 사용하지 않을 경우)

컨텐츠 수평 정렬 (justify-content)

바깥 박스에 justify-content 속성을 이용하면, 안쪽 박스의 수평 정렬을 지정할 수 있습니다. 주요 옵션을 소개합니다. 한번씩 적용해보세요.

  • flex-start
  • flex-end
  • center
  • space-between

컨텐츠 수직 정렬 (align-items)

바깥 박스에 align-items 속성을 이용하면, 안쪽 박스의 수직 정렬을 지정할 수 있습니다. 주요 옵션을 소개합니다. 한번씩 적용해보세요.

  • flex-start
  • flex-end
  • center
  • stretch

프로토타이핑: 개발 초기의 모형을 만들어 기능의 요구사항을 파악 후 반영하는 개선 방식

HTML로 웹 앱의 구조 잡기

  1. 큰 틀에서 영역 나누기
  2. 각 영역을 태그로 표현하기
    (여러 태그를 하나의 div(section, form:화면 전환)로 감싸줘야 함)

0개의 댓글