[번역] Popups and window methods

정은경·2021년 5월 3일
0

👸 Front-End Queen

목록 보기
151/271
post-thumbnail

아래의 글을 번역한 글입니다.

Popups and window methods
https://ko.javascript.info/popup-windows

팝업창과 윈도우 메소드

팝업창(popup window)은 사용자에게 추가적인 문서를 보여주는 아주 오래된 방법 중 하나다.
기본적으로 아래의 코드를 실행하기만 하면 된다.

window.open('https://javascript.info/')

위의 코드는 위의 주어진 url에 해당하는 새로운 창(window)을 연다.
대부분의 현대 브라우저들은 별도의 새로운 창을 열기보다는,
새로운 탭을 열도록 설정되어 있다.

팝업창(popup)은 아주 고대? 시절부터 존재한다.
초기의 아이디어는 메인창을 닫지 않으면서, 또다른 콘텐츠를 보여주는 것이었다.
현재에는 "또다른 콘텐츠를 보여주기"위한 다른 방법이 있다.
fetch를 이용해서 동적으로 콘텐츠를 로드하고, 로드된 콘텐츠를 동적으로 생성된 div 태그에서 보여줄 수 있다.
그래서, 팝업을 사용하는 일은 요즘은 잘 없다.

또한, 팝업창은 모바일 장치에서는 좀 까다롭다.
모바일 장치는 여러 창을 동시적으로 보여주지 않기 때문에 까다롭다.

여전히 팝업창이 사용되는 작업들이 있다.
예를 들면, OAuth 인증 (구글,페이스북 등을 이용한 소셜 로그인).
왜 팝업이 사용되는가하면..

    1. 팝업창은 자신만의 자바스크립트 환경을 갖는 별개의 창이다. 그래서 써드파티 또는 신뢰할 수 없는 사이트를 열어보는 것에서 안전한다.
    1. 팝업창은 url을 변경하거나 opener window에 메세지를 전송할 수 있다.

팝업 블로킹

과거에 악성 사이트를 팝업창을 많이 남용했다.
나쁜 페이지는 수십개의 광고 팝업창을 열 수 있었다.
그래서, 지금은 대부분의 브라우저들은 팝업창을 차단해서 사용자를 보호하려고 노력한다.

대부분의 브라우저들은
만약 팝업창들이 "onClick"과 같은 유저의 실행으로 인해 실행되는 이벤트를 제외한
다른 원인으로 실행되는 팝업을 차단한다.

// popup blocked
window.open('https://javascript.info');

// popup allowed
button.onclick = () => {
	window.open('https://javascript.info');
}

이렇게 하면,
원치않는 팝업들로 부터 사용자들이 보호될 수 있다.
하지만, 팝업기능 자체가 완전히 disable되는 것은 아니다.

만약 팝업이 "onClick"에 의해서 열리는데,
"setTimeout"이후라면 어떨까?
좀 어려운 문제다.

// open after 3 seconds
setTimeout(() => window.open('http://google.com'), 3000);

위의 코드는
구글 크롬 브라우저에서는 팝업이 열리지만,
파이어 폭스 브라우저에서는 차단된다.

setTimeout(() => window.open('http://google.com'), 1000);

delay 시간을 줄인 위의 코드는
구글 크롬 브라우저, 파이어 폭스 브라우저 둘 다에서 팝업이 실행된다.

이렇게 차이가 나는 이유는,
파이어폭스는 2000ms 또는 그 이하의 timeout을 허용하기 때문이다.
하지만, "trust"를 삭제하고, "사용자의 행동의 밖"이라고 가정하면.
첫번째는 차단된고, 두번째는 아니다.?!

window.open

팝업을 여는 문법은 "window.open(url, name, params)

url

새로운 창(window)에 로드할 url

name

새로운 창(window)의 이름.
각 창에는 "window.name"이 있다.
그리고, 팝업으로 어느 창을 사용할 지 명시할 수 있다.
같은 이름의 창이 이미 존재하면, 그 창에 주어진 url이 열리고,
같은 이름의 창이 존재하지 않으면, 새로운 창을 열러 주어진 url을 연다.

params

새로운 창을 위한 "설정 문자열"
이 문자열에는 콤마(,)로 구분된 설정정보가 들어가 있다.
파라미터 사이에는 공백이 있으면 안된다.
파라미터의 예시:

width=200,height=100

params을 통해 설정할 수 있는 것들:

  • 위치(position):
    • left/top(숫자): 스크린의 상위-왼쪽 코너의 위치 설정. 단, 새로운 창은 스크린의 위치를 벗어날 수 없음
    • width/height(숫자): 새로운 창의 넓이/높이, 단, 넓이/높이의 최소값이 있음. 크기를 0으로 줄여서 안보이도록 할 수 없음
  • 창 기능(Window features)
    • menubar (yes/no): 새로운 창의 브라우저 메뉴 보이기/안보이기
    • toolbar (yes/no): 브라우저 네이게이션 바(뒤로가기, 앞으로가기, 새로고침 등)를 새로운 창에 보이기/안보이기
    • location (yes/no): 새로운 창에 url 주소 창 보이기/안보이기, 파이어폭스랑 인터넷 익스플러러는 디폴트로 hide 못하게 함
    • status (yes/no): 상태 바 보이기/안보이기, 대부분의 브라우저들은 보이도록 강제 설정함
    • resizable (yes/no): 새로운 창을 resize하는 것을 disable하도록 허용, 추천하지 않음
    • scrollbar (yes/no): 새로운 창의 스크롤 바를 disable하도록 허용. 추천하지 않음

특정 브라우저들만이 제공하는 기능(feature)들이 있음(대부분은 잘 안쓰임)
자세한 사항은 아래의 링크 참조
window.open in MDN

예시: 미니멀리스틱 창 (minimalistic window)

브라우저가 어떠한 기능들을 disable했는지 살펴보기 위해, 최소한의 기능만 설정된 창을 열어보자.

let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=0,height=0,left=-1000,top=-1000`;

open('/', 'test', params);

위의 코드에서 대부분은 윈도우 기능을 disable했고,
윈도우 포지션은 offscreen이다(left=-1000,top=-1000)
위의 코드를 실행시켜서 무엇이 벌어지는 지 살펴보자.

위의 코드를 실행시킨 결과 화면 캡쳐(크롬):

대부분의 브라우저는 "width/height이나 offscreen left/top의 값이 0인 경우"와 같은 이상한 것들을 수정해준다.
예를 들어, 크롬은 이상한 경우("width/height이나 offscreen left/top의 값이 0인 경우") 윈도우 창을 full width/height로 열어서, 새로운 창이 전체 스크린을 차지하도록 한다.

이번에는, 정상적인 poisition 옵션들을 넣고, 적당한 width/height/left/top 값을 넣어서 실행해보자.

let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,
width=600,height=300,left=100,top=100`;

open('/', 'test', params);

위의 코드를 실행시킨 결과 화면 캡쳐(크롬):

대부분의 브라우저들은
필요한 만큰 위와 같이 보여준다.

제외된 설정들에 대한 규칙들:

  • open call에 3번째 argument가 없거나 비어있으면, 디폴트 윈도우 파라미터가 사용됨
  • params 문자열이 있지만, yes/no 기능들이 빠져있으면, 빠져있는 기능들을 모두 no라고 간주함. (주의: yes로 하고 싶은 것은 반드시 표시해야 yes가 된다)
  • left/top이 params 문자열에 없을 경우, 브라우저는 가장 최근에 열었던 창의 위치와 가까이 열도록 함

윈도우에서 팝업 접근하기

open call은 새로운 창에 referecne(새로운 창을 참조할 수 있는 값)를 리턴한다.
리턴된 reference를 이용해서 새로운 창의 값(property)을 조작하거나, 위치를 변경하거나 하는 등 이상의 작업을 할 수 있다.

JavaScript로부터 팝업 콘텐츠를 생성해보자.

let newWin = window.open("about:blank", "hello", "width=200,height=200");

newWin.document.write("Hello, world!");

로딩 이후, 콘텐츠를 수정하였다.

let newWindow = open('/', 'example', 'width=300,height=300')
newWindow.focus();

alert(newWindow.location.href); // (*) about:blank, loading hasn't started yet

newWindow.onload = function() {
  let html = `<div style="font-size:30px">Welcome!</div>`;
  newWindow.document.body.insertAdjacentHTML('afterbegin', html);
};

파이어폭스 실행화면:

주의: window.open 실행 바로 이후에, 새로운 창이 아직 로드되지 않았다. (alert 실행을 통해 알 수 있음)
그래서, 그것을 수정하기 위해 onload를 기다린다.
또한, newWin.document를 위한 DOMContentLoaded 핸들러를 사용할 수 있다.

Same origin policy (같은 오리진 정책)
창(window)은 오직 같은 오리진(같은 프로토콜://도메인:port)에서 왔을 때는 자유롭게 콘텐츠를 접속할 수 있다.
그렇지 않으면,
사용자 안전상의 이유로,
메인 윈도우가 "site.com"이라는 오리진에서 왔고,
팝업창은 "gmail.com"에서 오는 경우는 불가능하다.
보다 자세항 사항은 아래의 챕터를 살펴보자(Cross-window communication): https://ko.javascript.info/cross-window-communication

팝업에서 윈도우 접근하기

팝업 창은 window.opener 레퍼런스를 사용해서 "opener" 윈도우를 접근할 수 있다.
팝업 창을 제외한 모든 윈도우에서는 "window.opener 레퍼런스"는 null이다.

아래의 코드를 실행하면,
opener(current) 윈도우 콘텐처를 "Test"로 바꾼다.

let newWin = window.open("about:blank", "hello", "width=200,height=200");

newWin.document.write(
  "<script>window.opener.document.body.innerHTML = 'Test'<\/script>"
);

위의 코드 실행화면(파이어폭스)

즉, 윈도우 간의 커넥션은 양방향이다: 메인 윈도우와 메인 윈도우로부터 생성된 팝업 윈도우는 서로 간의 reference(참조)를 갖는다!

팝업창 닫기

윈도우 창 닫기: win.close()
윈도우 창이 닫아졌는지 확인하기 위해서는: win.closed

기술적으로, close() 메소드는 어떠한 윈도우에도 사용할 수 있다.
하지만, window.close()는 대부분의 브라우저에서 무시된다.
window.close()는 오직 window.open()에 의해 생성된 윈도우(즉, 팝업창)에만 작동한다.

만약, 윈도우가 닫히면, closed 속성은 true가 된다.
이는 팝업창 또는 메인 윈도우가 여전히 열려있는지 아닌지를 확인할 때 유용하다.
사용자는 창을 언제든 닫을 수 있으며, 코드는 창을 닫는 것을 고려해야만 한다.

아래의 코드는 창을 로드하고 닫는다.

let newWindow = open('/', 'example', 'width=300,height=300');

newWindow.onload = function() {
  newWindow.close();
  alert(newWindow.closed); // true
};

위의 코드를 파이어폭스에서 실행한 화면 캡쳐:

스크롤과 리사이징

창을 move/resize하는 메소드들

  • win.moveBy(x,y)
    • 현재 위치에서 상대적으로 오른쪽으로 x픽셀만큼, 아래쪽으로 y픽셀만큼 이동
    • 음수값 쓸 수 있음
  • win.moveTo(x,y)
    • 윈도우를 스크린의 위치(x,y)로 이동
  • win.resizeBy(width,height)
    • 현재 사이즈에서 상대적으로 창의 크기를 주어진 width/height로 재조정
    • 음수 값 허용
  • win.resizeTo(width,height)
    • 주어진 사이즈로 윈도우 크기 재조정

window.onresize 이벤트라는 것도 있음

오직 팝업창만!
오남용을 예방하기 위해서, 브라우저는 이러한 메소드들을 차단한다.
부가적인 탭이 없는, 우리가 연 팝업창에서만 작동한다.

최소화/최대화 없음!
자바스크립트는 창을 최소화/최대화할 수 있는 방법이 없다.
창 최소화/최대화는 OS레벨의 기능이다. (프론트엔드 개발자가 할 수 없는 부분)
move/resize 메소드는 최대화/최소화를 위해 동작하지 않는다.

윈도우 스크롤링

"브라우저 창 사이즈와 스크롤" 챕터에서 윈도우 스크롤링에 대해 언급한바 있다.

  • win.scrollBy(x,y)
    • 윈도우를 현재 스크롤에서 상대적으로, x 픽셀만큼 오른쪽으로, y 픽셀만큼 아래쪽으로 스크롤.
    • 음수 쓸 수 있음
  • win.scrollTo(x,y)
    • 주어진 좌표(x,y)로 윈도우를 스크롤
  • elem.scrollIntoView(top = true)
    • elm.scroolIntoView(false)를 위해서 elem이 top(디폴트 값) 또는 bottom에 나타나도록 윈도우를 스크롤

window.onscroll 이벤트도 있다.

윈도우에서 focus/blur

이론적으로, 윈도우를 focus/unfocus하기 위해서 window.focus()와 window.blur()가 메소드가 있다.
또한, 방문객이 윈도우를 focus하거나 다른 곳으로 focus를 하는 순간을 캐치하기 위한 focus/blur 이벤트가 있다.

비록, 실용적인 측면에서 제약들이 있다.
왜냐하면, 과거에 악성 페이지들이 이를 남용했었기 때문이다.

아래의 코드를 살펴보자:

window.onblur = () => window.focus();

사용자가 윈도우 밖으로 전환(window.onblur)하려고 할 때, 다시 윈도우로 focus를 가져온다.
의도는 사용자는 윈도우 안으로 가두기(lock) 위함이다.

그래서, 브라우저들은 이와 같은 코드를 금지하기 위해서(이와 같은 코드를 사용하는 악의적인 페이지와 광고들로 부터 사용자를 보호하기 위해서) 많은 제약사항들을 제안하고 있다.
이러한 코드의 구현은 브라우저에 의존하고 있다.

예를 들면,
모바일 브라우저는 보통 window.focus()를 완젼히 무시한다.
또한, focusing은 팝업창이 별개의 탭의 형태로 실행될 때 작동하지 않는다. (새창으로 팝업이 생기는 경우는 동작)

여전히, focus가 효과적인 사례들이 있음:

  • 팝업창을 열었을 때, newWindow.foducs()를 실행하는 것은 좋은 생각이다. 몇몇 OS/브라우저의 조합의 경우들에서, 사용자가 새로운 위도우에 있음을 확실히 알릴 수 있는 긍정적인 효과가 있음
  • 방문자가 실제로 우리의 웹앱을 사용하고 있는지 트랙킹하고 싶다면, 우리는 window.onfocus/onblur를 트래킹할 수 있다. 이는 페이지 내의 활동, 애니메이션들을 지연/재개할 수 있도록 한다. 하지만, blur 이벤트는 방문자가 윈도우 창 밖으로 나왔음(switch out)을 의미함에 주의하자(하지만 여전히 관측될 수 있음). 윈도우는 백그라운드 이지만 여전히 visible하다.

요약

팝업창은 드물게 사용된다.
팝업창 대신 페이지 내에서 로딩/display하거나, iframe을 사용하는 방법들 등의 방법들이 존재하기 때문에.

만약 우리가 새로운 팝업 창을 열려고 한다면, 좋은 관례는 사용자에게 이를 알리는 것이다.
링크/버튼 주변에 "opening window" 아이콘을 표시함으로써 방문객들이 focus 이동이나 두개의 창을 모두 염려해 둘 수 있도록 할 수 있다.

  • 팝업 창은 open(url, name, params)를 호출해서 열 수 있다. 실행 결과, 새롭게 열린 창에 대한 참조값(refrence)을 리턴한다.
  • 브라우저는 사용자가 호출하지 않은 open 호출을 차단한다. 보통은 알람이 나타나서, 사용자가 이를 인지할 수 있도록 한다.
  • 브라우저는 기본적으로 팝업창 대신 새로운 탭을 연다. 하지만, 사이즈 값이 제공되면 새로운 팝업창을 연다.
  • 메인 윈도우와 팝업창은 같은 origin이라면, 서로 자유롭게 read/modify할 수 있다. 같은 origin이 아니면, 메인창과 팝업창은 서로의 위치를 바꾸거나 메시지를 주고 받을 수 있다.

팝업창을 닫기 위해서는 close()를 사용한다.
또한, 사용자가 창을 닫을 수 있다.
창이 close()에 의해 닫히던, 사용자가 창을 닫아서 닫히던, 닫히면
window.close()값은 true이다.

  • focus(), blur() 메소드는 윈도우를 focus/unfocus할 수 있게한다. 하지만 항상 동작하는 것은 아니다.
  • focus, blur 이벤트는 윈도우의 스위칭 in/out을 추적할 수 있다. 하지만 윈도우는 백그라운드 상태에서(blur이후)도 visible 할 수 있다.

끝😊

profile
#의식의흐름 #순간순간 #생각의스냅샷

0개의 댓글