[js] IE 버전감지와 호환성모드의 처리

Detector는 브라우저의 다양한 설정이나 버전, 기능을 사전이 감지하여 실제 자바스크립트 코드를 작성할 때 환경에 맞게 작동하게 분기할 수 있는 기준을 제공합니다.

주요한 감지 대상은 다음과 같습니다.

  • 브라우저의 종류와 버전
  • OS의 종류와 버전
  • 화면의 크기와 색상표현력
  • DOM, CSS의 기능지원범위
  • 플래시의 버전과 사용여부
  • HTML5관련 다양한 기능 사용여부

수 많은 감지항목이 있지만 그 중에 가장 중요한 항목은 브라우저의 종류와 버전입니다. 존레식은 최대한 브라우저에 의존하지 말고 객체탐지를 통해 기능이 사용가능한가에 의존한 코드를 만들어 제이쿼리의 유지보수를 용이하게 했다고 그의 책에서 밝히고 있습니다(….만 실무를 해보라지!) 제이쿼리로 안되는 미묘한 상황들은 결국 브라우저에 대응하는 수 밖에 없습니다. 하지만 양날의 검은 브라우저가 끝없이 늘어나고 버전업하면서 달라지기 때문에 감지에 대응하는 코드도, 그 감지 방법도 끝없이 대응해야한다는 점입니다.

 
 

브라우저 감지의 백미 IE!

다른 브라우저를 감지하는 것도 쉽지 않지만 IE의 감지는 감지의 최고봉입니다!

http://ligo.kr/f7

위의 김나람님의 글을 보시면 IE 호환성과 관련된 문제를 어떻게 해결하는지 설명하고 있습니다.

평소 쇼핑몰도 자주 제작하는 제 입장에서 현재까지 시장에서 IE 는 무조건적인 선택입니다. 결제모듈이 전부 IE 가 아니면 안돕니다.

근데 실무를 뛰어보면 IE 의 버전과 상관없이 모든 IE 는 호환성모드로 들어온다고 가정해야 합니다. 왜냐면 호환성모드로 두지 않으면 각종 결제나 기존 사이트 이용이 불편하기 때문에 대부분의 유저가 호환성 모드를 켜서 들어온다는 것이죠.

호환성모드에서는 일단 버전이 7으로 고정됩니다.

따라서 IE는 호환성모드일 때와 아닐 때의 버전 감지법이 다릅니다. 또한 윈도우모바일과 IE 11 의 특수한 상황을 합체하면 경우는 더욱 복잡해집니다.

이 글은 전체 브라우저 감지를 다루는 것이 아니라 오직 IE 부분만 다루겠습니다. 더 자세하고 다양한 감지 방법은 오픈소스로 진행 중인 bsDetector 프로젝트를 참고하시면 도움이 될 수 있습니다.

http://ligo.kr/yf

 
 

호환성보기 모드를 감지하기

이것은 위에 링크를 건 블로그에 매우 자세하게 설명되어있는데 요약하자면 다음과 같습니다

  1. IE7 의 agent 에는 trident 라는 문구가 들어갈 수 없다
  2. IE8이상은 msie 7이라는 문구가 들어갈 수 없다.
  3. 따라서 msie 7과 trident가 동시에 등장하면 호환성 모드다

즉 우선 이걸 통해 호환성보기인지 아닌지는 감지가 된다는 거죠. 이를 코드로 표현하면 다음과 같습니다.

var agent = navi.userAgent.toLowerCase();

if( agent.indexOf('msie 7') > -1 && agent.indexOf('trident') > -1 ){
	//호환성모드
}else{
	//그냥모드
}

호환성 모드는 의외로 간단히 감지가 되었습니다. 이제 버전감지로 가죠.

 
 

IE감지와 호환성보기 모드가 아닐 때의 버전감지

설명의 순서가 좀 반대지만 우선 IE인지 아닌지를 감지해야 합니다. 호환성보기모드에 대한 감지도 그 다음이죠. IE인지 감지하는 방법은 msie가 있거나 trident가 있으면 됩니다.

코드로보면 아래와 같습니다.

function detectIE(){
	var agent = navi.userAgent.toLowerCase();

	//ie가 아니다!
	if( agent.indexOf('msie') == -1 && agent.indexOf('trident') == -1 ) return;

	if( agent.indexOf('msie 7') > -1 && agent.indexOf('trident') > -1 ){
		//호환성모드
	}else{
		//그냥모드
	}
}

호환성보기가 아닐 때의 처리는 무척 간단합니다(알고보면..) IE11은 msie라는 문자열을 제거했습니다.

http://ligo.kr/zj

이 공식 ms의 문서를 보시면 다음과 같은 문구가 나옵니다.

일반적으로 특정 브라우저 또는 브라우저 버전을 검색하면 안 됩니다. 이러한 테스트의 기본 가정은 브라우저를 업데이트할 때 가양성 결과를 초래하는 경향이 있습니다. 대신 필요할 때 기능을 검색하고 점진적 기능 향상을 통해 필요한 기능을 지원하지 않는 브라우저나 장치를 위해 간소화된 환경을 제공합니다.
드물긴 하지만 IE11을 고유하게 식별해야 하는 경우도 있습니다. 이렇게 하려면 Trident 토큰을 사용합니다.

(뭐가 드물어 장난해!)

암튼 이런 이유로 호환성보기 모드가 아닐 때의 버전감지는 다음과 같습니다.

//msie가 없으면 11이다!
if( agent.indexOf('msie') == -1 ) return  11;

//아니면 msie 옆에 있는 버전을 보내주자!
return parseFloat(/msie ([d]+)/.exec(agent)[1]);

 
 

호환성보기 모드일 때의 버전감지

이제 호환성보기에서 버전감지를 어떻게 해야하나를 생각해보죠. 이때는 이미 agent로 얻을 수 있는 버전은 7밖에 없으므로 7이 아니라는 사실만 알 수 있습니다. 그렇다면? 객체감지를 통해서 버전픽스를 해야겠죠.

IE의 각 버전에는 다음과 같은 특징이 있습니다.

  1. IE8 – Canvas가 없다
  2. IE9 – css의 trainsion이 안된다.
  3. IE10 – webGL이 안된다.

IE 12 가 나오면야 11 과 어떻게 구분해야 할지 고민해 봐야겠지만 현재로서는 이렇습니다. 이걸 이용해 코드를 분기해보죠.

var bStyle = document.body.style;
var canvas = document.createElement('canvas');

//canvas가 없어 - 8
if( !('getContext' in canvas) ) return 8;

//transtion이 불가 - 9
if( !('msTransition' in bStyle) && !('transition' in bStyle) ) return 9;

//webGL이 없어 - 10
if( !canvas.getContext('webgl') ) return 10;

//아니면 11, 나중에 12나오면 여길 분기
return 11;

 
 

결론

호환성보기 모드는 결국 객체 탐지를 통해 분기하고 있습니다. 그런 이유로 안전한 탐지 타이밍은 DOM로딩 이 후 입니다. 전체적으로 합쳐진 코드는 다음과 같습니다.

function detectIE(){

	var agent = navi.userAgent.toLowerCase();

	if( agent.indexOf('msie') == -1 && agent.indexOf('trident') == -1 ) return;

	if( agent.indexOf('msie 7') > -1 && agent.indexOf('trident') > -1 ){

		var bStyle = document.body.style;
		var canvas = document.createElement('canvas');

		if( !('getContext' in canvas) ) return 8;
		if( !('msTransition' in bStyle) && !('transition' in bStyle )) return 9;
		if( !canvas.getContext('webgl') ) return 10;
		return 11;

	}else{

		if( agent.indexOf('msie') == -1 ) return 11;
		return parseFloat(/msie ([d]+)/.exec(agent)[1]);

	}
}