Google I/O 2016에서 웹쪽 주제로는 첫 번째 세션이었던 High performance web user interfaces 를 요악합니다.
- Progressive Web Apps
- 여러 기능을 사용하기 위해서는 HTTPS가 필요
- push messaging, offline 혹은 좋지 않은 접속 상태 (by service worker)
- 사용자는 native app처럼 생긴 앱은 native app 처럼 동작하기를 기대한다.
- 동작(behaves)은 두 가지로 나뉜다. - performance, interaction
- Performance
- RAIL
- 퍼포먼스를 고려할 때 사용자를 중심에 두고 생각하는 모델
- Response (0.1 sec), Animation (16ms), Idle (50ms), Load (1 sec)
- 현실에서 중요도는 L > A > R > I 로 생각된다.
- Add to homescreen에서 실행되거나 PWA에서는 중요도가 R = A > I > L 라고 생각.
- add to homescreen에서 실행되는 경우에는 service worker가 기본으로 설정되어 있어야 하기 때문
- SW에서 오프라인이거나 연결상태가 좋지 않을 경우 로딩을 컨트롤 할 수 있다.
- 매일 실행하는 앱에서는 스크롤이 잘 되거나, 반응성이 좋거나 하는 것이 더 중요하다.
- App이 아니라 site의 경우에도 user interface의 반응성이 좋은 것은 중요
- Three components의 성능을 높이는 사례를 볼 것임
- sidenav, dismissable card, expanding and collapsing view
- sidenav
- pointer-events: none;
- 미리 준비되어 있어야 하고 언제든 동작 가능해야 하는데 사용자가 클릭하자마자 동작해야 하므로 렌더트리 내에 포함되어 있어야 한다. 그렇지 않다면 렌더트리에 포함될 때 layout, styles, painting 이 트리거 된 후에야 움직일 수 있다. 따라서 hidden 되어 있지 않고 렌더트리에 포함되어 있으려면 모든 엘리먼트의 최상단에 있어야 하는데 그렇게 되면 다른 엘리먼트를 클릭할 수 없다. 따라서 pointer-events를 none으로 설정하면 클릭이 아래에 깔린 엘리먼트로 넘어가게 된다. 화면에 노출될 때는 auto로 변경
- sidenav가 자체의 composite layer를 갖도록 한다.
- composite layer: 페이지의 특정한 부분을 페이지의 다른 부분과 분리하는 것
- will-change: transform; 사용 (예전에는 translateZ(0) 사용)
- 필요한 곳에만 쓸 것. 메모리 과다 사용 문제, compositing에 걸리는 시간 최소화.
- 터치로 sidenav를 움직일 경우 document에 이벤트 처리를 위임한다.
- requestAnimationFrame 사용
- touchmove 이벤트 핸들러에서 event.preventDefault()를 사용한다.
- 기본적으로 크롬에서는 touchmove 이벤트를 발생시키는 회수를 줄인다. 손가락으로 가리키는 모든 이벤트를 받고자 한다면 preventDefault()를 사용해야 함.
- Supercharged 동영상 http://bit.ly/side-nav
- swipeable cards
- this.onStart = this.onStart.bind(this);
- prototype을 instance로 복사하면서 현재 instance와 바인딩한다.
- 호출하면 항상 현재 instance를 참조하고 addEventLister에서 this.onStart으로 등록/제거가 가능
- onStart에서 style.willChange를 지정해서 별도 레이어로 분리 (필요할 때만 분리한다는 점이 중요)
- 손쉬운 easing 패턴
- value += (target - value) / strength
- Supercharged 동영상 http://bit.ly/swipeable-cards
- Expand and Collapse
- 이건 좀 어려운데 width, height, top, left를 변경하면 매 프레임마다 layout 트리거 되고 paint도 트리거됨
- layout은 dom size에 비례하여 시간이 증가
- transform을 쓰면 layout만 트리거 할 수 있다. (그래서 발표자가 좋아함) (참고: 크롬에서만..)
- FLIP 방법을 적용
- First, Last, Invert, Play
- First: 초기 상태의 position을 얻는다. (getBoundingClientRect)
- Last: 애니메이션을 마지막 프레임으로 옮겨간다. 그리고 마지막 상태의 position을 얻는다. (getBoundingClientRect)
- Last로 갈 때 layout, style이 강제로 트리거 된다. Layout은 나쁜데 이렇게 해도 괜찮은가?
- 단 한 번만 layout함. RAIL의 도움을 얻을 수 있다.
- Invert: Last에서 First로 되돌리는 값을 얻어 transform 시킨다. 그리고 transform에 transition을 설정.
- Play: transform = 'none' 으로 설정하면 카드가 늘어나게 된다.
- FLIP 주의점
- scales은 자식 엘리먼트를 변경시킨다. 형제 엘리먼트를 고려해야 할지도
- first 에서 last로 가는 과정은 layout과 style을 발생시키므로 조심해야 함
- 성능에 덜 민감하고 Responsive Web Design에도 유용
- 렌더링 퍼포먼스에 대해 알고 싶다면
- http://bit.ly/render-perf
- 데모에 나온 UI를 더 자세히 살펴보고 싶다면
- http://bit.ly/supercharged-ui
이 동영상에는 코드에 대한 설명이 많아 모든 내용을 요약하지는 않았습니다. 보다 상세한 내용이 궁금한 분은 동영상을 확인하기 바랍니다.