Front End 최적화
Technique안녕하세요 lovefield 입니다.
오늘은 Front end가 할 수 있는 최적화에 대해서 설명을 해드리려 합니다.
우선 Front end 작업은 Designer의 영향을 어마어마하게 받습니다.
그렇기에 정말로 최적화를 하기 위해서는 Designer의 협력이 필요하며, Designer가 Front end에 대해서, 나의 디자인이 어떻게 표현되는지에 대해서 알고 있어야 한다고 생각합니다.
기본적으로 저는 플렛 디자인을 선호하며 css로 표현하기 가장 쉽기 때문입니다.
아, 그리고 IE는 브라우저 취급을 안 해줍니다. 하하하하IE 사라져버려
HTML
최대한 불필요한 요소의 사용을 줄입니다.
HTML 요소가 많을수록 시스템 적으로 느려지기 때문인데요.
실제로 유저가 체감할 수 있는 정도는 아니지만, 1000개, 10000개 의 불필요한 요소가 있다면?
소규모 사이트의 경우는 몰라도 대규모라면 랜더링 하는 속도는 차이가 날 수 밖에 없겠죠.
다음 탭 구조를 예로 들어보죠.
<div class="wrapComTap">
<div class="wrapComT">이번 주 식단표</div>
<div class="wComM">
<div class="day">
<ul class="list">
<li class="day01">
<a href="javascript:void();" onclick="javascript:onmouseclick(1);">월</a>
</li>
<li class="day02">
<a href="javascript:void();" onclick="javascript:onmouseclick(2);">화</a>
</li>
<li class="day03">
<a href="javascript:void();" onclick="javascript:onmouseclick(3);">수</a>
</li>
<li class="day04">
<a href="javascript:void();" onclick="javascript:onmouseclick(4);">목</a>
</li>
<li class="day05">
<a href="javascript:void();" onclick="javascript:onmouseclick(5);">금</a>
</li>
<li class="day06">
<a href="javascript:void();" onclick="javascript:onmouseclick(6);">토</a>
</li>
<li class="day07">
<a href="javascript:void();" onclick="javascript:onmouseclick(7);">일</a>
</li>
</ul>
</div>
</div>
<div class="wComB">
<ul>
<li class="day01">
<div>
<p class="time bold">점심</p>
<p class="content">잡곡밥,미역국,탕수육,스팸,김치,콩나물무침,오댕볶음,닭강정</p>
</div>
</li>
...
</ul>
</div>
</div>
이야..정말 불필요한 게 많은 코드입니다.
좀더 시맨틱 하게 바꿔보죠.
<section class="timetable">
<h1>이번 주 식단표</h1>
<div class="btn_area">
<button data-day="0">월</button>
<button data-day="1">화</button>
<button data-day="2">수</button>
<button data-day="3">목</button>
<button data-day="4">금</button>
<button data-day="5">토</button>
<button data-day="6">일</button>
</div>
<div class="item" data-day="0">
<p><strong>점심</strong></p>
<p>잡곡밥,미역국,탕수육,스팸,김치,콩나물무침,오댕볶음,닭강정</p>
</div>
...
</section>
정확한 디자인이 없어서 예시이므로 자잘 한 것들은 넘어가겠습니다.
먼저 해당 탭 영역에 대한 캡션은 heading
태그로 변경합니다.
탭 버튼 영역은 리스트가 아니므로 div
하나로만 감싸며 ul>li
구조는 버립니다.
a
태그는 페이지 이동에만 쓰여야 하며 href
에는 javascript
가 들어갈 수 없으므로 버리고 button
으로 대체합니다.
그리고 컨트롤을 위한 data-day
값을 사용합니다.
실질적으로 보여지는 부분에도 공통적인 뷰이므로 ul>li
구조를 버리고 공통 클래스를 가져갑니다.
그리고 역시 컨트롤을 위한 data-day
값을 사용합니다.
자 간결해졌죠?
CSS
css
에는 less
, sass
와 같은 전처리기와 OOCSS
, SMACSS
, BEM
와 같은 방법론이 존재합니다.
그 중 저는 SMACSS
를 조금 변형 해서 사용하고 있습니다.
방법은 다음과 같습니다.
Base(Reset)
body,h1,h2,h3,h4,h5,h6,p,blockquote,pre,dl,dd,ol,ul,fieldset,legend,figure,menu{margin:0;padding:0;border:0}
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}
table,th,td{border-spacing:0;border-collapse:collapse}
ol,ul,li{list-style:none}
h1,h2,h3,h4,h5,h6{font-size:1em;font-weight:normal}
body{background:#f5f8f9;color:#333;font:normal 12px/1.3 'Open Sans','Noto Sans',sans-serif}
input,textarea,select,button{margin:0;padding:0;border-radius:0;color:#333;font:normal 12px/1.3 'Open Sans','Noto Sans',sans-serif;outline:0;vertical-align:middle}
a:link,a:visited,a:hover,a:active{text-decoration:none}
a,button,input[type="submit"],input[type="button"],input[type="reset"]{border:0;background:transparent;cursor:pointer}
img{max-width:100%;border:0;vertical-align:top}
제 git 블로그의 reset css 입니다.
Layout
header{position:fixed;top:0;left:0;right:0;height:60px;background:#fff;border-bottom:2px solid #f0f3f7;z-index:100}
header .logo{float:left}
header .gnb{float:right}
.container{min-height:100%;padding:61px 0 0;box-sizing:border-box}
.container .layout{padding:30px 0 0}
.container aside{float:left;width:220px}
.container section{float:right;width:-webkit-calc(100% - 240px);width:calc(100% - 240px);padding:0 0 100px}
footer{padding:20px 0;border-top:2px solid #f0f3f7;line-height:1.5}
제 git 블로그의 layout css 입니다.
블로그가 단순해서 8줄정도로 다 사용 중입니다.
Module
.user{padding:10px;background:#fff;border-radius:10px;box-shadow:2px 2px 0 #f0f3f7;overflow:hidden}
.user .imgarea{width:160px;height:160px;margin:10px auto 0;border-radius:50%;overflow:hidden}
.user .profile{padding:10px 0 0}
.user .profile h3{font-size:18px;font-weight:bold}
.user .profile p{margin:5px 0 0}
.user .link{margin:10px 0 0;padding:10px 0 0;border-top:1px solid #38b7ea}
.user .link a{display:inline-block;margin:0 5px 5px 0;padding:5px;background:#38b7ea;color:#fff;;border-radius:5px}
.title01{background:#fff;border-radius:10px;margin:0 0 20px}
.title01 h2{float:left;height:40px;padding:0 15px;font-size:16px;font-weight:bold;line-height:40px}
.title01 .category_menu{float:right;height:40px}
모듈입니다, 각각의 모듈을 클래스 단위로 묶어서 사용하며 중복코드가 상당수 사집니다.
타입이나 색상 등 조금씩 다른 부분인 추가 클래스로 만들어줍니다.
Active도 있지만 저는 Module안에 포함시키는 편입니다.
다음은 렌더링입니다.
전역선택자 *
는 모든 태그를 선택합니다. 즉 HTML상에서 태그가 하나 추가될 때마다 시스템적으로는 느려집니다.
!important
는 강제 스타일 적용입니다. 셀렉트 우선순위에 의한 상속을 무시해 유지보수와 확장성에 방해가 됩니다. 또한 렌더링 방식에 있어서 안 좋은 것으로 알고 있습니다.
IE
핵의 사용은 비표준 브라우저인 IE
를 지원하기 위한 것으로 CSS3와 웹 표준을 지향해 불필요한 렌더링 방식을 줄여야 할 것 같습니다.
vendor prefix
는 구버전 브라우저를 지원하기 위한 코드입니다 현재는 어쩔 수 없이 사용하는 상태입니다.
Javascript
javascript
는 HTML
과 CSS
에 비해 가장 용량을 많이 차지하는 녀석이죠?
역시 CSS
와 같은 맥락으로 모듈화를 합니다.
$('.tap01 .btn_area button').click(function(){
var val = $(this).attr('data-num');
$('.tap01 .btn_area button').removeClass('act');
$(this).addClass('act');
$('.tap01 .tap_item').removeClass('act');
$('.tap01 .tap_item[data-num="'+ val +'"]').addClass('act');
});
$('.tap02 .btn_area button').click(function(){
var val = $(this).attr('data-num');
$('.tap02 .btn_area button').removeClass('act');
$(this).addClass('act');
$('.tap02 .tap_item').removeClass('act');
$('.tap02 .tap_item[data-num="'+ val +'"]').addClass('act');
});
위와 같은 코드는
$.fn.tap = function(){
var self = $(this),
btn = self.find('.btn_area button'),
item = self.find('.tap_item');
btn.click(function(){
var val = $(this).attr('data-num');
btn.removeClass('act');
$(this).addClass('act');
item.removeClass('act');
item.filter('[data-num="'+ val +'"]').addClass('act');
});
}
$('.tap01').tap();
$('.tap02').tap();
이렇게 해 재사용성을 높여줍니다.
네이티브로도 가능한 코드들이니 특별한 설명은 생략하겠습니다.
불필요한 depth 도 제거해줍니다.
$('.wrap .container section .contact_form .btn_area .submit')
는 아래와 같이
$('.contact_form .submit')
이벤트 바인딩은 확실한 요소만 걸어줍니다. 여러 요소에 바인딩 하는 것과 사용할 요소에만 바인딩 하는 것은 다릅니다.
$('a').click();
는 아래와 같이
$('.link01').click();
이벤트를 바인딩할 요소가 너무 많거나 동적 요소에 대해 바인딩할 때. 즉, 이벤트 바인딩 시점에는 해당 요소가 존재하지 않고 나중에 추가될 때 이벤트 위임방식(delegate)을 사용합니다.
$('.parent').on('click', 'a:not(.acitve)', function(event) { /* do somthing */});
Animation 은 setTimeout
이나 setInterval
보다는 requestAnimationFrame
을 사용합니다.
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
requestAnimationFrame(fn());
브라우저에게 2만건의 데이터를 처리하라고 하면 당연히 뻗을 것입니다.
특수한 상황에서 큰 데이터를 처리할 때는 Web Worker
를 사용하시면 됩니다.
Design
간단한 불릿이나 간단한 표현 같은 것은 css로 표현 가능한 디자인으로 변경해줍니다.
장점
- 1b의 이미지라도 브라우저가 표현하기 위해서는 서버에 리퀘스트가 발생할 수 밖에 없습니다.
- 그에 반에 css로 처리하면 리퀘스트 발생을 줄여 트래픽을 줄일 수가 있습니다.
단점
- 그라데이션이나 그래픽적인 디자인 요소는 표현하기 힘듦
icon -> font,svg 처리
위의 이미지와 같이 img보다는 font를 사용해 img 리퀘스트를 줄여줍니다.
혹은 SVG를 이용해 아이콘을 그려도 됩니다!
font icon 제작 방법
- 디자이너가 일러스트로 제작합니다. (아트보드 분리)
- 디자이너 혹은 개발자가 일러스트파일을 SVG로 저장합니다.
- http://fontello.com/ 와 같은 사이트에서 변환한다.
- 사이트에 적용!
장점
- img 와 비교해 사이즈 별로 전혀 깨지지 않습니다.
- img에 비해 서버 리퀘스트 발생이 적으며 비교적 가볍게 사용할 수 있습니다.
- 모든 디자인 요소를 사용할 수 있습니다.
단점
- 그라데이션 표현이 불가능합니다.
- 그래픽적 표현이 불가능합니다.
- IE 하위 호환성을 고려해야 합니다.
img font -> web font 처리
이건 말할 것도 없겠죠?
JS animaction -> CSS3 animation
장점
- JS가 동작하는 리소스보다 가볍습니다.
- CSS3로 표현 불가능한 것은 거의 없습니다.
단점
- IE 10 미만으로는 호환성을 고려해야 합니다.
Minify
minify는 실질적으로 작업을 할 때 minify를 고려하는 것 보다는 작업 후에 툴을 이용해 minify 후 배포하는 것이 좋습니다.