[데브코스] 11일차 TIL (HTML/CSS, 브라우저, 쿠키, WebStorage)
공부
자바스크립트
javascript
데브코스
TIL
HTML
CSS
브라우저
2022-04-04

HTML / CSS

HTML

HTML은 Hypertext Markup Language의 약자로 웹 문서를 표시하기 위한 마크업을 의미한다. 마크업이란 과거에 원고에 대한 수정 지침을 나타내는 언어였다고 한다. 시간이 지나면서 용도가 점차 확장되어 문서의 구조를 표현하는 역할을 하게 되었다. 이러한 태그 방법의 체계를 사용하는 언어를 마크업 언어라고 한다.

HTML은 프로그래밍 언어가 아니다!

과거에 웹이 등장한지 얼마 되지 않았을 때에는 디자인을 담당하는 HTML 태그가 있었지만 CSS가 등장한 이후 HTML은 문서의 의미와 전체 구조만을 담당한다.

주의할 점! HTML 태그는 각 태그마다 기본 스타일을 가진다. 기본 스타일을 모르고 페이지를 구성하면 의도와 다르게 요소가 배치될 수 있다. 그렇기 때문에 태그들이 어떻게 구성되어 있는지 확인 할 필요가 있다. 또, 브라우저마다 태그들의 디자인이 조금씩 다르기 때문에 다양한 브라우저에서 공통된 디자인을 제공하기 위해 차이를 알아둘 필요가 있다.

CSS

CSS는 Cascading Style Sheets의 약자이다. Cascading은 '위에서 아래로 흐르는', '상속 또는 종속하는' 이라는 뜻을 가지고 있다. 스타일을 적용할 때 상위 요소의 스타일이 하위 요소에게 적용되는 모습이 DOM 트리에서 폭포수처럼 내려가는 모습을 닮았다고 해서 이런 이름이 붙여졌다고 한다.

CSS는 선택자(Selector)를 사용해 어떤 태그에 스타일을 적용할 지 정하고, 속성(Property)과 속성값(Value)을 이용해 어떤 스타일을 적용할 지 선언한다.

css 구조

CSS에는 다양한 선택자가 있다.

  • 기본 선택자

    1. 전체 선택자 (*) 모든 요소를 선택한다. 아래의 경우 모든 요소에 margin과 padding을 0으로 설정한다.

      1 * {
      2 margin: 0;
      3 padding: 0;
      4 }
    2. 유형 선택자 (elementname) 주어진 노드 이름을 가진 모든 요소를 선택한다.

      1 /*모든 input 태그의 너비를 300px로*/
      2 input {
      3 width: 300px;
      4 }
    3. 클래스 선택자 (.classname) 주어진 클래스 특성을 가진 모든 요소를 선택한다.

      1 /*
      2 index 클래스를 가진 모든 요소의
      3 배경색을 red로
      4 */
      5 .index {
      6 background-color: red;
      7 }
    4. ID 선택자 (#idname) 주어진 ID 특성에 따라 요소를 선택한다. 문서 내에는 주어진 ID를 가진 요소가 하나만 존재해야 한다.

      1 /*
      2 index ID를 가진 요소의
      3 배경색을 blue로
      4 */
      5 #index {
      6 background-color: blue;
      7 }

      class와 id의 차이 class는 여러 요소에 중복으로 사용 가능하고, id는 하나의 요소에만 사용 가능하다.

    5. 특성 선택자 주어진 특성을 가진 모든 요소를 선택한다.

      • [attr]: attr이라는 이름의 특성을 가진 요소를 선택한다
      • [attr=value]: attr이라는 이름의 특성값이 정확히 value인 요소를 선택한다.
      • [attr~=value]: attr이라는 이름의 특성값이 정확히 value인 요소를 선택한다. [attr=value]와 다르게 attr 특성은 공백으로 구분한 여러 개의 값을 가지고 있을 수 있다.
      • [attr|=value]: attr이라는 특성값을 가지고 있고, 그 특성값이 정확히 value이거나 value로 시작하면서 - 문자가 곧바로 뒤에 따라 붙는 요소를 선택한다.
      • [attr^=value]: attr이라는 특성값을 가지고 있으며, 접두사로 value가 값에 포함되어 있으면 이 요소를 선택한다.
      • [attr$=value]: attr이라는 특성값을 가지고 있으며, 접미사로 value가 값에 포함되어 있으면 이 요소를 선택한다.
      • [attr*=value]: attr이라는 특성값을 가지고 있으며, 값 안에 value라는 문자열이 적어도 하나 이상 존재하면 이 요소를 선택한다.
      • [attr operator value i]: 괄호를 닫기 전에 i 또는 I를 붙여주면 값의 대소문자를 구분하지 않는다.
      • [attr operator value s]: 괄호를 닫기 전에 s 또는 S를 붙여주면 값의 대소문자를 구분한다.
  • 그룹 선택자 쉼표를 사용해 여러 개의 선택자를 그룹으로 묶는다.

    1 /*
    2 div와 span 요소의 마진과 패딩을 0으로
    3 */
    4 div,
    5 span {
    6 margin: 0;
    7 padding: 0;
    8 }
  • 결합자

    1. 자손 결합자 (공백) 첫 번째 요소의 자손인 노트를 선택한다.

      1 /*
      2 div 안에 위치하는 모든 span 요소의 배경색을 black으로
      3 */
      4 div span {
      5 background-color: black;
      6 }
    2. 자식 결합자 (>) 첫 번째 요소의 바로 아래 자식 노드를 선택한다.

      1 /*
      2 ul 요소 바로 아래의 모든 li 요소의 마진을 10px으로
      3 */
      4 ul > li {
      5 margin: 10px;
      6 }
    3. 일반 형제 결합자 (~) 첫 번째 요소를 뒤따르면서 같은 부모를 공유하는 두 번째 요소를 선택한다.

      1 /*
      2 p 요소를 뒤따르는 모든 span 요소의 배경색을 red로
      3 */
      4 p ~ span {
      5 background-color: red;
      6 }
    4. 인접 형제 결합자 (+) 첫 번째 요소의 바로 뒤에 위치하면서 같은 부모를 공유하는 두 번째 요소를 선택한다.

      1 /*
      2 h2 바로 뒤에 위치하는 p 요소의 배경색을 red로
      3 */
      4 h2 + p {
      5 background-color: red;
      6 }
  • 의사 클래스/요소

    1. 의사 클래스 (:) 문서 트리가 포함하지 않는 상태 정보에 기반해 요소를 선택한다. a:visited 는 사용자가 방문한 모든 a 요소와 일치함. MDN 의사 클래스
    2. 의사 요소 (::) HTML이 포함하지 않는 개체를 선택한다.
      p::first-line 은 모든 p 요소의 첫 번째 줄과 일치함.
      MDN 의사 요소

브라우저 로딩 과정

브라우저 렌더링 과정 브라우저는 파싱 -> 스타일 -> 레이아웃 -> 페인트 -> 합성 -> 렌더 등의 과정을 거친다.

  1. 파싱 브라우저가 HTML을 파싱하고 읽어들이는 과정이다. HTML을 통해 DOM 트리를 구성한다.
    외부/내부의 스타일시트의 CSS를 해석해 CSSOM 트리를 구성한다. 선택자가 노드로 생성되고 각 노드는 적용될 스타일을 참조한다.

  2. 스타일 DOM 트리, CSSOM 트리가 생성되면 DOM 요소에 스타일을 입혀 렌더 트리를 구성한다. (이 과정을 Attachment 라고 함) 렌더 트리에는 페이지를 렌더링하는 데 필요한 노드만 포함된다.

  3. 레이아웃 기기의 뷰포트 내에서 노드의 정확한 위치와 크기를 계산한다. 리플로우라고도 한다. %로 지정된 값은 픽셀 단위로 측정 및 계산된다.

  4. 페인트 렌더 트리의 각 노드를 화면의 실제 픽셀로 변환하는 마지막 단계이다. 래스터화라고도 하며 위치와 관계없는 CSS 속성(background-color, opacity, transform, box-shadow 등)을 적용한다.

  5. 합성 화면에 표시하기 위해 페이지에서 페인트 된 부분을 합치는 과정이다.

위의 과정을 렌더링이라고 한다. 렌더링 과정은 상황에 따라 반복해서 발생할 수 있는데, DOM을 추가하거나 삭제하고, CSS의 기하학적인 변화가 있을 때 레이아웃 과정이 다시 발생한다. 이를 리플로우(reflow)라고 한다. CSS의 기하학적 변화가 아닌 다른 속성의 변경이 일어날 경우 리페인트(repaint)가 발생한다.
브라우저는 렌더링 과정에서 많은 성능을 필요로 하는데, 특히 reflow가 순간적으로 많이 발생할 경우 브라우저에 치명적이라고 한다. 이를 해결하기 위해 가상돔(VirtualDOM)이라는 개념이 등장하게 되었다.

가상돔(VirtualDOM)이란

앞에서 설명한 것처럼 DOM을 추가하거나 삭제할 때, CSS의 위치나 높이 등 기하학적 속성의 변화가 있을 때 reflow가 발생한다. reflow를 줄이면 성능이 향상하는데 이때 사용하는 것이 가상돔이다. 뷰에 변화가 있을 때 가상돔을 사용해 최종적으로 변경된 내용만 DOM에 적용하는 방법으로 브라우저 내에서 발생하는 연산의 양을 줄이면서 성능을 개선할 수 있다.

컴포넌트란

웹 개발 관련해서 검색을 하면서 컴포넌트라는 단어를 정말 많이 본 것 같다. 컴포넌트란 뭘까? UI를 선언적으로 표현하기 위해, 표현하는 부분을 추상화 할 수 있는데, 이때 추상화 한 단위를 컴포넌트라고 한다. 항상 개념을 설명하는 문장은 이해하기 어려운 것 같다. 만약 간단한 투두리스트를 만든다고 하면, 맨 위에 투두리스트의 이름과 할 일을 입력할 수 있는 입력창, 입력을 전송할 수 있는 버튼, 마지막으로 입력 받은 할 일 목록을 보여주는 리스트가 있을 것이다. 이를 구현할 때 투두리스트의 이름 영역, 입력받는 영역, 보여주는 영역으로 구분해 생각할 수 있는데 이때 각각의 영역을 컴포넌트라고 부른다.
컴포넌트로 구성하게 되면, 작은 단위로 나누었기 때문에 재사용이 쉽다는 장점이 있다. 이때, 각 컴포넌트는 서로 독립적이어야 한다.

Client-Side 에서 데이터 저장하기

  1. 쿠키 쿠키는 브라우저에 저장되는 작은 크기의 문자열로, RFC 6265 명세에서 정의한 HTTP 프로토콜의 일부이다. 쿠키를 사용하는 예로 팝업창이 있다. 팝업창을 보면 오늘 하루동안 이 창을 열지 않음과 같은 선택 박스가 있는 걸 볼 수 있다. 이를 선택하면 브라우저에 쿠키를 설정하고 해당 쿠키가 있다면 팝업창을 띄우지 않는 등의 방법으로 구현한다.
    document.cookie 를 사용해 브라우저에 쿠키를 저장할 수 있다.

    1 document.cookie = "key=value";

    와 같이 문자열로 된 key, value 형태의 값을 저장하면 쿠키가 저장된다. document.cookie 를 그대로 호출하면 브라우저에 저장된 모든 쿠키가 문자열 형태로 나타난다. 이때 각 쿠키들은 ; 으로 구분되어 있기 때문에 ; 을 구분자로 사용하면 각 쿠키들을 불러올 수 있다.

    1 document.cookie.split(";");

    쿠키의 유효기간을 설정하는 방법이 2가지가 있다.

    1. expires: 쿠키를 언제까지 사용할 지 설정한다. GMT 시간을 기준으로 쿠키의 만료날짜를 설정한다.
    2. max-age: 쿠키가 얼마나 유효한지 설정한다. 초 단위를 사용한다.
    1 const date = new Date();
    2 date.setDate(date.getDate() + 1); // 유효기간 하루
    3 document.cookie = `key=value;expires=${date.toGMTString()}`;
    4
    5 document.cookie = `key=value;max-age=${1 * 24 * 60 * 60}`; // 유효기간 하루

    HTTP 요청 시 헤더에 쿠키가 같이 나가기 때문에 쿠키 사이즈가 커지면 HTTP 요청 크기가 커진다. 따라서 사이즈에 제한이 있고, 여러가지 보안 취약점을 조심해야 한다.

  2. Local Storage key-value 기반으로 로컬에 데이터를 저장한다. 도메인을 기반으로 저장소가 생기기 때문에, 같은 도메인이라면 다른 탭이라도 같은 저장소를 공유한다. 삭제하거나 저장소를 삭제하지 않는 한 삭제되지 않는다. getItem, setItem, removeItem 을 사용해 데이터를 저장하거나 불러오고 삭제할 수 있다.

    1 localStorage.setItem("test", "test1");
    2 localStorage.getItem("test"); // 'test1'
    3 localStorage.removeItem("test");

    local storage에 데이터를 저장할 때 주의할 점이 하나 있는데, 자바스크립트의 객체를 저장하기 위해선 JSON.stringify를 사용해 객체를 문자열로 변환 후 저장해야 한다. 그렇지 않으면 객체에 toString() 메서드를 적용한 문자열인 [object Object]로 저장된다. 저장된 데이터를 사용할 때는 JSON.parse를 사용해 저장된 문자열을 파싱해서 사용해야 한다.

  3. Session Storage 전체적으로 localStorage와 같지만 브라우저를 닫으면 저장된 내용이 초기화된다.

localStorage와 sessionStorage는 브라우저에서 임의로 값을 변경할 수 있다. 개발자가 의도한 대로 값을 저장했는데, 사용자가 저장된 값을 바꾸게 되면 의도한 대로 동작하지 않을 수 있고, 오류가 발생할 수도 있다. 그렇기 때문에 localStorage나 sessionStorage를 사용할 때는 try catch 등을 사용해 방어코드를 작성하는 것이 중요하다.

정리

브라우저에서 렌더링 하는 과정과 브라우저에 정보를 저장하는 방법에 대해 공부했다. CSS의 선택자는 항상 사용할 때마다 헷갈렸는데 이번 기회에 조금 정리가 된 것 같아 다행이다. HTML을 파싱에 DOM 트리 구성하는 과정을 직접 코드로 구현할 수도 있다고 하는데 재미있을 것 같다.

배운 내용을 정리하는데에도 시간이 오래 걸린다. 그래서 어느 순간 공부를 위한 정리가 아니라 정리를 위한 정리가 되는 것 같다. 너무 많은 내용을 정리하려고 해서 그런 것 같기도 해서 정말 몰랐던 내용만 정리하거나 정리하는 방법을 조금 바꿔야겠다는 생각을 하고 있다.

사람들이 올리는 TIL을 읽고 슬랙에 이모지를 남기는데 저번주 중반부터 바빠서 글을 다 못 읽었다. 글을 안 읽고 이모지 남기는 건 뭔가 양심에 가책이 느껴져서 빨리 글 읽고 이모지 달아야겠다.

참고자료

나무위키 - CSS https://namu.wiki/w/CSS
MDN CSS 선택자 https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Selectors
CSS: 선택자(Selector) 이해 https://www.nextree.co.kr/p8468/
Vanilla Javascript로 가상돔(VirtualDOM) 만들기 https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/#_1-%E1%84%80%E1%85%A1%E1%84%89%E1%85%A1%E1%86%BC%E1%84%83%E1%85%A9%E1%86%B7-virtualdom-%E1%84%86%E1%85%A1%E1%86%AB%E1%84%83%E1%85%B3%E1%86%AF%E1%84%80%E1%85%B5