자바스크립트 완벽가이드 | 15장 웹 브라우저의 자바스크립트

dev_hee·2022년 7월 19일
0

본 문은 자바스크립트 완벽가이드를 읽으며 몰랐던 부분을 정리한 글입니다.


웹 프로그래밍 기본

클라이언트 사이드 자바스크립트

  • 클라이언트 사이드 (FrontEnd)
    웹 브라우저에서 실행하도록 작성된 자바스크립트

  • 서버 사이드 (BackEnd)
    웹 서버에서 실행되는 자바스크립트

  • 사이드
    웹 서버와 웹 브라우저 사이에 있는 네트워크 연결의 양 극단을 의미함.

HTML <script> 태그

self close는 제공되지 않는다. 따라서 </script> 태그가 필수적이다.
임베디드 방식 대신 src 를 사용해 자바스크립트 파일을 불러오는 방식은 장점이 있다.

  • HTML 파일에서 JS 를 제거해 '내용'과 '동작'을 분리하여 단순화 함
  • 같은 JS 코드를 공유하는 경우 파일을 재사용 하면 됨
  • 멀티 페이지 웹에서 재사용되는 JS 는 브라우저에 캐싱됨
  • 다른 서버에 있는 JS 코드를 사용할 수 있음. 광고가 이에 해당함

모듈

<script src="..." type="module"></script>

위와 같이 type=module을 사용하는 경우는 다음과 같다.

  • 자바스크립트 프로그램을 모듈로 작성한 경우
  • 코드 번들링 도구를 사용해서 모듈을 하나의 JS 파일로 조합하지 않은 경우

import, export 를 사용하여 모듈로 작성한 경우 위 처럼 최상위 모듈을 불러와야한다.
그럼 재귀적으로 가져온 모듈들을 모두 불러오게 된다.

type module 은 기본적으로 defer 속성이 있는 것처럼 문서 로딩이 끝난 후(돔 생성이 끝난 후) 실행된다.

document.write() 가 성능에 영향을 준다

과거에 document.write 를 사용했던 이유는, 이미 렌더링 된 문서에서 구조와 컨텐츠를 조작하고 문서간에 이동을 할 수 있는 API가 없었기 때문이다. (모던 JS 은 DOM API 등을 사용해 조작 가능)

따라서 document.write()를 포함한 JS를 실행하기 위해서, HTML 파서가 <script> 요소를 만날 때 마다 반드시 그 스크립트를 실행해 HTML을 출력하는지 확인했다.

즉, 반드시 HTML 파싱 중 만난 스크립트는 실행되며 그 동안 문서 분석과 렌더링을 진행할 수 없어 렌더링 속도를 심하게 저해한다.

웹 브라우저의 전역 객체

웹 브라우저에서 전역 객체는 두 가지 임무를 수행한다.

  1. 내장 타입과 함수를 정의 (표준 라이브러리, 호스트 객체)
  2. 현재 웹 브라우저 창을 나타냄
    • window.history : 그 창의 브라우징 히스토리를 나타냄
    • window.innerWidth : 창의 너비를 픽셀로 나타냄

전역 객체와 관련된 기능을 사용할 때는 window. 를 붙이자.

자바스크립트 프로그램의 두 단계

  1. 문서 콘텐츠를 불러오고 <script> 요소의 코드를 실행함
  2. 문서 로딩이 끝나고 스크립트를 전부 실행하고 난 후, 이벤트 주도적인 비동기 단계
    [두 가지 load 이벤트]
    • DOMContentLoaded : HTML 문서의 로딩과 분석이 끝났을 때 발생
    • load : 이미지 같은 문서의 외부 자원을 완전히 불러 왔을 때 발생

클라이언트 사이드 자바스크립트 스레드 모델

자바스크립트는 싱글 스레드 언어이라서 프로그래밍이 단순하다.
콘텐츠 수정 시 다른 스레드가 동시수정 할 일이 없으며, lock, deadlock, race condition 을 걱정할 필요가 없다.
싱글 스레드는 웹 브라우저가 스크립트와 이벤트 핸들러를 실행하는 동안 입력에 반응하지 않는다.

웹 워커

웹 플랫폼은 웹 어커를 통해 동시성을 구현한다.
사용자 인터페이스를 멈추지 않으면서 실행되는 백그라운드 스레드로,
웹 워커는 메인 스레드나 다른 워커와는 상태를 공유하지 않으면서 오직 비동기 메시지 이벤트를 통해서만 통신한다.

클라이언트 사이드 자바스크립트 타임 라인

(1) 스크립트 실행단계와 (2)이벤트 처리 단계, 두 단계는 다음과 같이 세분화할 수 있다.

(1) 스크립트 실행단계

  1. 웹 브라우저가 Document 객체를 생성하고 웹 페이지 분석을 시작한다. document.readyState 프로퍼티 값은 loading 이다.
  2. HTML 파서가 async, defer, type="module" 속성이 없는 <script> 태그를 만나면 스크립트 태그를 문서에 추가하고 스크립트를 실행한다. 이 스크립트는 동기적으로 실행되며 document.write를 사용할 수 있다.
  3. 파서가 async 속성이 있는 <script> 요소를 만나면 스크립트 텍스트를 내려받기 시작하며, 모듈이면 재귀적으로 내려받아 문서를 분석한다. 이런 비동기 스크립트는 document.write() 를 사용해선 안된다.
  4. 문서 분석이 완전히 끝나면 document.readyState 프로퍼티가 interactive 로 바뀐다.
  5. defer 속성이 있는 스크립트, async 속성이 없는 스크립트는 문서 순서대로 실행된다. 문서 전체에 접근이 가능하다. document.write 메서드를 사용해선 안된다.
  6. 브라우저가 Document 객체에서 DOMContentLoaded 이벤트를 일으킨다. 이 때 스크립트 단계가 두번째로 전환된다.

(2)이벤트 처리 단계

  1. 문서 분석은 끝났지만 브라우저가 여전히 이미지 같은 컨텐츠를 기다리고 있을 수 있다. 컨텐츠 로딩도 끝나고 async 스크립트 로딩과 실행도 끝나면 document.readyState 프로퍼티가 complete로 바뀐다. 웹 브라우저는 Window 객체에서 load 이벤트를 일으킨다.
  2. 이제 사용자 입력 이벤트, 네트워크 이벤트, 타이머 이벤트 핸들러가 비동기적으로 호출된다.

프로그램 입출력

사용할 수 있는 입력은 다음과 같이 다양하다.

  • DOM API 로 접근할 수 있는 문서 콘텐츠 자체
  • 이벤트 형태인 사용자 입력 (버튼 클릭 등)
  • 문서 URL (document.URL, URL())
  • HTTP 쿠키 요청 헤더 콘텐츠 (docuemnt.cookie)
  • 전역 navigator 프로퍼티
    - navigator.userAgent 웹 브라우저를 식별
    • navigator.language 사용자 선호 언어
    • navigator.hardwareConcurrency 웹 브라우저가 사용할 수 있는 논리적 cpu 개수
  • 전역 screen 프로퍼티
    - screen.width, screen.height 프로퍼티로 디스플레이 크기에 접근

프로그램 에러

예외가 발생하고 그 예외를 처리할 catch 문이 없다면 개발자 콘솔에 에러 메시지를 표시하고 등록된 이벤트 핸들러는 계속 실행되며 이벤트에 반응한다.

  • window.onerror
    잡히지 않은 예외를 최후의 수단으로 호출될 에러 핸들러를 window.onerror 에 등록한다.
    이는 세 가지 인자를 받아 호출된다.
    onerror 핸들러가 true 를 반환하면 브라우저는 에러를 처리했다고 판단하여 에러 메시지를 표시하지 않는다.

  • window.onunhandledrejection
    프로미스가 거부되고 이를 처리할 catch 함수가 없는 경우에 window.onunhandledrejection 에 등록된 이벤트 핸들러로 에러를 감지할 수 있다.
    preventDefault() 를 호출하면 처리된 것으로 간주하여 콘솔에 에러메세지를 표시하지 않는다.

동일 출처 정책 same-origin policy

동일 출처 정책은 자바스크립트 코드에서 접근할 수 있는 웹 컨텐츠를 제어하는 보안 정책이다.

문서 출처

문서를 불러온 URL 의 다음 세 가지 기준으로 구분함
1. 프로토콜 (http vs https)
2. 호스트
3. 포트

동일 출처 정책 적용 사례

  1. <iframe> 요소

스크립트 자체의 출처는 동일 출처 정책과 관련이 없다.
스크립트를 포함한 문서의 출처가 문제이다.

  1. 스크립트를 사용한 HTTP 요청

자바스크립트 코드는 자신을 포함하는 문서를 가져온 웹 서버에 HTTP 요청을 제한 없이 보낼 수 있지만 다른 웹 서버와 통신 할 수 없다. (CORS 허용된 서버는 가능)

동일 출처 정책 완화 방법

  1. document.domain 사용

서브도메인을 여러 개 사용하는 큰 웹사이트에서 동일 출처 정책이 문제가 될 수 있다. 따라서 document.domain을 사용해 도메인을 자신의 상위 도메인으로 변경할 수 있는 방법이 있다.

[예시]

  • 상위 도메인 : example.com
  • 하위 도메인 : order.example.com
    하위 -> 상위 로 출처 변경을 할 수 있다.

하지만 주의해야 할 점은, 보안상의 측면에서 더이상 사용하지 않게 되었다.

참고: https://velog.io/@youngjewoo/Chrome-브라우저에서의-document.domain-제거

2.CORS (Cross-Origin Resource Sharing)

CORS 는 교차 출처 간 자원 공유를 의미한다.
HTTP 를 Origin: 요청 헤더와 Access-Control-Allow-Origin 응답 헤더로 확장한다.

  • CORS 를 써서 헤더에 파일을 요청할 수 있는 출처를 명시적으로 나열
  • 와일드 카드를 사용해 어떤 사이트든 제한 없이 파일을 요청하게 할 수 있다.

브라우저는 CORS 헤더를 지원하며, 이 헤더가 없는 요청은 CORS 에러를 발생시킨다.

교차 사이트 스크립트 (XXS)

Cross-Site Scripting (XXS)

공격자가 대상 웹사이트에 HTML 태그나 스크립트를 주입하는 보안 문제를 통틀어 가리키는 용어.

방역(sanitize)를 통해서 신뢰할 수 없는 데이터(HTML 태그 또는 스크립트 코드)를 제거해야한다. 방역을 한 데이터를 기반으로 문서 콘텐츠를 동적으로 생성해야한다.

또는 sandbox 속성이 있는 <iframe> 에 표시해 스크립트나 기타 기능을 비활성화 해야한다.

XXS는 하나 이상의 사이트가 연관되었음을 의미한다. 사이트 B에서 사용자가 조작된 사이트 A 링크를 클릭하도록 유도하여 개인 정보를 읽고 사이트 B에 전송할 수 있다. 또는 사용자 키 입력을 추적할 수도 있다.


이벤트

클라이언트 사이드 자바스크립트 프로그램은 비동기적인 이벤트 주도 프로그래밍(event-driven)모델을 사용한다.

  • 이벤트 타입
    이벤트 종류를 지정하는 문자열
    ex) mousemove, keydown, load

  • 이벤트 대상
    이벤트가 일어난, 또는 이벤트와 연관된 객체
    - Window 객체의 load 이벤트, button요소의 click 이벤트 처럼 그 타입과 대상을 지정해야함
    - 보통 Window, Docuemnt, Element 객체
    - 일부 이벤트는 Worker 객체

  • 이벤트 핸들러/ 이벤트 리스너
    이벤트를 처리하거나 이벤트에 반응하는 함수
    이벤트 타입과 이벤트 대상(객체)을 지정해 웹 브라우저에 이벤트 핸들러 함수를 등록한다.

  • 이벤트 객체
    이벤트 객체는 특정 이벤트와 연관되어있으며 해당 이벤트에 대한 세부 정보를 포함한다.

  • 이벤트 전달/전파(propagation)
    - HTML 문서 요소에서 일어나는 이벤트는 문서 트리를 따라 전달된다.

    • Window 객체의 loadWorker객체의 message와 같은 일부 이벤트는 이벤트 전달가 필요 없다.

이벤트 범주

  1. 장치에 의존적인 입력 이벤트
    마우스/키보드 같은 특정 입력 장치에 직접적으로 묶여있다.
    mousedown, mousemove, mouseup, touchstart, touchmove, keydown, keyup ...

  2. 장치 독립적인 입력 이벤트
    특정 입력 장치에 매여 있지 않다.

  • click : 링크, 버튼, 기타 요소가 활성화 되어있음을 알림. 마우스/키보드/터치 장비를 통해서 활성화 가능
  • input : 키보드 입력, 잘라내어 붙여 넣기, 상형 문자의 입력
  • pointerdown, pointermove, pointerup : 마우스 타입 포인터, 터치스크린, 펜이나 스타일러 지원
  1. 사용자 인터페이스(UI) 이벤트
    고수준 이벤트로 사용자 인터페이스로 동작하는 HTML form 요소에서 자주 사용된다.
    focus, change, submit..

  2. 상태 전환 이벤트
    사용자의 활동이 아니라, 네트우크와 브라우저 활동에 의해 일어나며 일종의 라이프사이클이나 상태가 변경됐음을 알린다.
    load, DOMContentLoaded, online, offline, popstate ...

  3. API 전용 이벤트
    HTML과 관련 명세에 정의하는 다양한 웹 API도 자신만의 이벤트 타입을 가진다.

이벤트 핸들러 어트리뷰트 설정

<button>click!</button>

자바스크립트 코드 문자열을 위와 같이 넣어주면 아래와 같은 함수 몸체에 코드로 삽입된다.

function(event){ // 이벤트 객체 -> event
 with(document){ // with 문이 변수를 마치 스코프에 존재하듯 직접 참조할 수 있도록 함.
   with(this.form || {}){
    with(this){
    	/* 코드 */
    }
   }
 }
}

strict mode 에서는 with 문을 금지하지만 HTML 어트리뷰트의 JS코드는 strict mode가 아니므로 이벤트 핸들러에 예상치 못한 변수가 정의된 환경에서 실행된다. 이는 버그를 유발할 수 있기 때문에 어트리뷰트 방식을 사용하지 않게 되었다.

addEventListener() 세번째 인수

  1. 불리언을 받는 경우
    true 이면 캡처링 이벤트 핸들러로 등록된다. 기본값은 false이다.
  2. 옵션 객체를 받는 경우
document.addEventListener("click", handleClick, {
  capture: true,
  once: true,
  passive: true
});
  • capture: 캡처링 여부
  • once: true이면 이벤트 리스너가 한 번 호출된 뒤 자동으로 제거됨. 기본값 false
  • passive
    :true이면 preventDefault()를 호출해서 기본 동작을 취소하지 않음. 모바일 장치의 터치 이벤트에서 특히 중요한데, touchmove이벤트 핸들러가 브라우저 기본 스크롤을 방해하면 부드러운 스크롤 동작을 구현할 수 없다. 이렇게 방해될 가능성이 있는 이벤트 핸들러를 등록할 때, 웹 브라우저에서 이벤트 핸들러가 실행되는 동안 스크롤 같은 기본 동작을 수행해도 안전하다고 알려주는 역할을 함.

이벤트 핸들러 인자, 이벤트 객체

이벤트 객체의 프로퍼티는 다음과 같다.

  • type
    일어난 이벤트 타입
  • target
    이벤트가 일어난 객체
  • currentTarget
    현재 이벤트 핸들러가 등록된 객체
  • timeStamp
    이벤트가 일어난 시간을 밀리초 단위로 나타냄
    절대적인 시간은 아님.
    두 번째 이벤트와 첫 번째 이벤트의 타임스탬프를 빼서 경과한 시간을 알 수 있음
  • 기타 등등

이벤트 핸들러에서 this

이벤트 핸들러 바디 안에서 this 는 이벤트 핸들러가 등록된 객체(currentTarget)를 가리킨다.

화살표 함수를 제외한 모든 이벤트 핸들러가 그러하다.

핸들러 반환값

최신 자바스크립트에서 이벤트 핸들러는 아무것도 반환해서는 안된다.
false 를 반환하면 이벤트와 연관된 기본 동작을 수행하지 않는다. 하지만 권장하지 않는다.

브라우저 기본동작 막는 표준 방법

이벤트 객체에서 preventDefault 메서드를 호출하는 것.

이벤트 캡처링 사용

이벤트 캡처링은 Window 객체에서 부터 DOM트리를 따라 이벤트 객체가 전달되는 과정이다.

이벤트 캡처링을 사용하면 이벤트 대상에 도달하기 전에 이벤트를 먼저 살펴볼 수 있다.

  • 디버깅에 사용
  • 이벤트 취소와 함께 대상 이벤트 핸들러가 실제로 호출되지 않게 이벤트를 거르는 용도로 사용
  • 마우스 드래그 처리에서 많이 사용

이벤트 취소

  1. 이벤트 핸들러 취소
    preventDefault() 메서드를 호출해 브라우저 기본 행동 방지
    addEventListener 의 세번째 인수의 passive 옵션을 사용하면 preventDefault는 호출되지 않음.

  2. 이벤트 전파 취소
    stopPropagation()이 호출 된 뒤 이후 다른 객체의 이벤트 핸들러는 호출되지 않는다.
    stopImmediatePropagation()은 같은 객체에 후순위로 등록된 나머지 이벤트 핸들러 호출도 방지한다.

커스텀 이벤트 전달/전파

이벤트 타켓은 커스텀 이벤트를 생성하고 전달할 수 있다.

  • CustomEvent() 생성자
    • 이벤트 객체를 생성함
    • 첫번째 인자: 이벤트 타입
    • 두번째 인자: 이벤트 객체의 프로퍼티를 지정하는 객체. detail 프로퍼티에 이벤트 컨텐츠를 나타낼 수 있음.
  • dispatchEvent()
    이벤트 객체를 받아서 전파함.
document.dispatchEvent(new CustomEvent("busy", {detail:true}));

fetch(url)
.then(handleNetworkResponse)
.catch(handleNetworkError)
.finally(() => {
	document.dispatchEvent(new CustomEvent("busy", {detail:false}));
})

docuemtn.addEventListener("busy", e => {
  if(e.detail) showSpinner();
  else hideSpinner();
});

문서 스크립트

closest() 와 querySelector()은 반대로 동작한다.

두 메서드 모두 CSS에 기반한 요소 선택 메서드이다.

  • closest()
    선택자가 요소 자체와 일치하면 해당 요소를 반환한다.
    그렇지 않다면 선택자와 일치하는 가장 가까운 조상 요소를 반환하고, 없다면 null을 반환한다.
    요소에서 시작해 트리를 올라가면서 일치하는 것을 찾는다.

  • querySelector()
    선택자가 요소 자체와 일치하는 첫 번째 요소를 반환하며, 없다면 null을 반환한다.
    요소에서 시작해 트리를 내려가면서 일치하는 것을 찾는다.

관련된 메서드 matches() 는 요소를 반환하진 않고, 해당 요소가 CSS 선택자에 일치하는지만 확인하고 불리언을 반환한다.

살아 있는 NodeList 를 반환하는 선택자

querySelectorAll 을 제외한 getElementsById, getElementsByTagName, getElementsByClassName 등은 살아 있는 NodeList 를 반환하기 때문에 사용을 금지해야한다.

살아 있는 NodeList 는 문서 컨텐츠 구조가 변하면 NodeList 컨텐츠나 길이가 변화한다.

미리 선택된 요소들

Document 클래스에는 특정 노드에 접근하는 단축 프로퍼티가 있다.
이들은 HTMLCollection 객체를 참조한다.

document.images
document.links

HTMLCollection는 요소의 id나 이름으로도 인덱싱 된다.

<form id="address">

위는 다음과 같이 접근 가능하다.

document.forms.address

문서 구조 순회

  • Element 객체 프로퍼티
    Text 노드는 무시한다.
    parentNode, children, childElementCount, firstElementChild, lastElementChild, nextElementSibling, previousElementSibling

  • Node 객체 프로퍼티
    Text 노드도 포함하여 Element, Comment 노드가 포함된다.
    parentNode, childNodes, firstChild, lastChild, nextSibling, previouseSibling, nodeType, nodeValue, nodeName

append(), prepend()

Element객체에 있는 append(), prepend()는 요소에 문자열이나 다른 요소를 삽입할 때 사용하는 메서드이다.
인자를 개수 제한 없이 받는다.
append()는 인자를 요소 자식 리스트 뒤에 추가하고, prepend()는 인자를 요소 자식 리스트 앞에 추가한다.

after(), before()

Element, Text 객체에 있는 after(), before()는 요소 중간에 다른 요소를 삽입할 수 있다.

replaceWith(), remove()

노드를 제거할 때는 remove(), 다른 요소로 교체할 때는 replaceWith() 메서드를 사용한다.


CSS 스크립트

인라인 스타일

style 프로퍼티

  • 모든 Element 객체에는 style 프로퍼티가 있다.

  • style 프로퍼티는 문자열이 아닌 CSSStyleDeclaration 객체이다.

    • CSSStyleDeclaration 객체: Style 속성에 텍스트 형태로 존재하는 CSS 스타일을 파싱한 결과
    tooltip.style.display = "block"; // 문자열은 파싱되어 CSSStyleDeclaration 객체가 됨
    tooltip.style.position = "absolute";
    e.style.margin = `${top}px ${right}px ${bottom}px ${left}px`;
  • CSS 프로퍼티는 px, pt 단위를 반드시 작성해야한다.

  • style 프로퍼티는 인라인 스타일만 가져올 수 있다. 하지만 스타일은 대부분 스타일 시트로 지정된다.

위에서 console.log($box.style.width); 는 빈문자열 "" 임을 알 수 있다.

계산된 스타일 getComputedStyle()

요소의 계산된 스타일은 브라우저가 요소의 인라인 스타일과 모든 스타일시트에서 가져온 적용 가능한 스타일 규칙 전체를 합해 계산한 프로퍼티 값 집합 이다.

  • 매개변수
    • 첫번째: 계산된 스타일을 가져올 요소
    • 두번째: CSS 가상 요소 (::before, ::after)
  • 반환값
    • CSSStyleDeclaration 객체
      • 읽기 전용이다.
      • 절댓값이다. 퍼센트, 포인트 같은 상대 단위는 절댓값으로 변환된다.
      • 색갈 값 프로퍼티는 rgb()rgba() 형식으로 반환된다.
      • 단축 프로퍼티는 계산되지 않으며 베이스인 기본 프로퍼티만 계산된다.
      • cssText 프로퍼티가 없다.

계산된 스타일은 까다롭고 원하는 정보를 항상 얻을 수 있다는 보장도 없다.
따라서 요소의 위치와 크기를 가져오는 것은 권하지 않는다.

스타일시트 스크립트

스타일 시트는 <style> 또는 <link rel="stylesheet"> 로 HTML 문서에 연결된다.
이들도 HTML 태그이므로 id 속성을 사용해서 querySelector() 로 검색할 수 있다.

  • 스타일 시트 자체를 disabled 프로퍼티를 통해 비활성화할 수 있다.

      const blueStyle = document.querySelector('#blue');
      const yellowStyle = document.querySelector('#yellow');
    
      blueStyle.disabled = true;
      yellowStyle.disabled = false;
  • DOM 조작 방법으로 새로운 스타일 시트(<link>, <style>)를 삽입할 수 있다.

CSS 애니메이션과 이벤트

transition

transition 애니메이션이 적용된 CSS 클래스가 있을 때, 요소가 이 클래스를 가지도록 classList에 추가한다면 애니메이션이 시작된다. 이 애니메이션은 자바스크립트가 관여한 것이 아닌 순수 CSS 효과이고, 자바스크립트는 효과가 일어나는 트리거를 제공했을 분이다.

  • transition 의 시작과 끝에서 이벤트가 발생하는데 자바스크립트를 사용해 CSS 트랜지션 진행을 모니터링 할 수 있다.
    • transitionrun : 트랜지션 시작. transition-delay 스타일이 있으면 transitionstart 전에 이 이벤트가 먼저 발생할 것임
    • transitionstart : 시각적 변화가 일어나기 시작함
    • transitionend : 애니메이션 종료
  • TransitionEvent : 이벤트 핸들러에게 전달되는 이벤트 객체.
    • propertyName : 이밴트 객체의 프로퍼티. 애니메이션을 적용받은 CSS 프로퍼티 이름
    • elapsedTime : transitionstart 이벤트로부터 경과된 시간.

CSS 애니메이션

transition과 마찬가지로 CSS 클래스에 애니메이션 프로퍼티를 정의하고 요소에 클래스를 추가하면 애니메이션이 발생한다.

  • CSS 애니메이션도 이벤트를 발생시킨다.
    • animationstart : 애니메이션 시작
    • animationend : 애니메이션 종료
    • animationiteration : 애니메이션 2번 이상 반복시 마지막 제외하고 반복마다 발생
  • AnimationEvent : 이벤트 객체
    • animationName : CSS animation-name
    • elapsedTime : 애니메이션 시작된 후 경과 시간

문서 지오메트리와 스크롤

문서 좌표와 뷰포트 좌표

문서 좌표

문서를 종이에 출력한 상태라고 생각하면 됨.

뷰포트

문서 콘텐츠를 실제로 표시하는 부분. 메뉴와 툴바, 탭등을 제거한 부분이다.
iframe 태그에 표시되는 문서의 뷰포트는 DOM의 iframe요소이다.
화면에 직접 보여지는 부분이라고 생각하면 된다.

문서 좌표는 사실상 큰의미가 없다. (요소마다 스크롤할 수 있고, 해당 요소가 자신이 포함한 콘텐츠의 뷰포트로 동작할 수도 있기 때문)

따라서 클라이언트 사이드 자바스크립트는 뷰포트 좌표를 쓰는 경우가 많다.

position:fixed

top, left 프로퍼티는 뷰포트 좌표를 기준 으로 해석된다.

컨테이너 좌표

컨테이너 요소에 relative 포지션을 정하고 컨테이너 내부에 absolute 가 지정된 요소가 있다면, 컨테이너 내부 요소는 컨테이너 위치를 기준으로 top, left 위치를 지정할 수 있다.

문서 좌표, 뷰포트 좌표와 구분되는 새로운 좌표계이다.

요소의 위치 검색

  • getBoundingClientRect() 메서드
    요소의 크기(border, padding 포함/margin 제외)와 위치(뷰포트 좌표)를 파악할 수 있다.

      const  rect = $box.getBoundingClientRect();
      /*
       {
        "x": 8,
        "y": 8,
        "width": 100,
        "height": 100,
        "top": 8,
        "right": 108,
        "bottom": 108,
        "left": 8
       }
       */
  • getClientRects() 메서드
    인라인 요소의 개별 사각형에서 각각 getBoundingClientRect 를 호출한 것처럼 읽기 전용 배열 비슷한 객체를 반환한다.

지정된 위치에 있는 요소 파악

뷰포트 특정 좌표에 있는 요소가 무엇인지 알고 싶을 때는 Document 객체의 elementFromPoint() 메서드를 사용하면 된다.
원하는 x, y좌표(마우스 이벤트의 clientX, clientY)로 이 메서드를 호출하면 지정된 위치에 있는 Element 객체가 반환된다.

중첩되어 있는 경우는 가장 위쪽과 가장 안쪽 요소를 반환한다.

document.addEventListener('click', (e) => { 
  console.log(document.elementFromPoint(e.clientX, e.clientY)); // <div class="box"></div>
});

스크롤

scrollTo() 메서드

Window 객체의 scrollTo()문서 좌표 기준인 x, y 좌표 를 받고., 브라우저 창을 스크롤해 지정된 지점을 뷰포트의 좌측 상단 모서리 로 만든다.

scrollBy() 메서드

x, y 좌표를 받아 그 값이 현재 스크롤 위치에 더해 스크롤한다.

  • scrollTo, scrollBy 를 부드럽게 스크롤하려면 다음처럼 숫자 대신 객체 인자를 전달하면 된다.
    window.scrollTo({
      left: 0,
      top: 100,
      behavior: "smmoth"
    })

scrollIntoView()

원하는 요소가 보일 때 까지 스크롤한다.
호출된 요소가 뷰포트에 나타날 때까지 스크롤한다.

뷰포트 크기, 콘텐츠 크기, 스크롤 위치

뷰포트

  • 브라우저 창의 뷰포트 크기
window.innerWidth;
window.innerHeight;

문서

  • 문서 전체 크기
document.documentElement; // <html>요소
document.documentElement.offsetWidth; // 문서 너비
document.documentElement.offsetHeight; // 문서 높이
document.documentElement.getBoundingClientRect(); // 크기 객체
  • 문서의 스크롤 오프셋
/* 읽기 전용 */
window.scrollX; // 가로 스크롤
window.scrollY; // 세로 스크롤

/* 문서 스크롤 하고싶다면 */
window.scrollTo(x, y);

요소

Element 객체에 다음과 같은 프로퍼티들이 있다.

  • offset

모두 읽기 전용이다.

// 1. 화면에 표시된 크기를 css 픽셀로
$element.offsetWidth;
$element.offsetHeight;

// 2. 요소의 x, y 좌표. 컨테이너에 상대적인 좌표
$element.offsetLeft;
$element.offsetTop;

// 3. 좌표의 기준이 되는 요소
$element.offsetParent;
  • client
// 1. 화면에 표시된 크기를 css 픽셀로 표시
// 보더 포함 안함, 콘텐츠 영역과 패딩만 포함
$element.clientWidth;
$element.clientHeight;

// 2. 요소의 패딩 바깥쪽과 보더 바깥쪽 사이의 거리
// 왼쪽, 위쪽 보더 너비와 일치한다.
// 유용하지는 않다.
$element.clientLeft;
$element.clientTop;
  • scroll
// 1. 요소의 컨텐츠 영역과 패딩, 넘치는 컨테츠를 합한 크기
// 컨텐츠 오버플로가 없다면 clientWidth, clientHeight 와 일치
$element.scrollWidth;
$element.scrollHeight;

// 2. 요소의 뷰포트 안에 요소 컨텐츠의 스크롤 오프셋
// 쓰기도 가능해서 요소 안의 컨텐츠 스크롤 할 수 있다.
$element.scrollLeft;
$element.scrollTop;

웹 컴포넌트

웹 컴포넌트가 프론트엔드 프레임워크를 대신할까?

웹 컴포넌트는 어떤 프레임워크, 라이브러리를 사용하던 환경에 얽매이지 않고 어디서든 사용 가능하다는 장점 을 가지고있다. 리액트, 앵귤러, 뷰와 같은 서로 다른 환경에서 만든 컴포넌트들은 이들 간의 재사용이 불가능하다. 하지만 웹 컴포넌트로 만들어진 컴포넌트는 모든 환경에서 재사용할 수 있으므로 lock in 되지 않는다.

profile
🎨그림을 좋아하는 FE 개발자👩🏻‍💻

0개의 댓글