이 글에서는 패셔너블한 웹사이트 디자인 방법과 얕은 것부터 깊은 것까지 HTML5와 브라우저 렌더링 메커니즘을 통해 고성능 사이트를 구축하는 방법을 소개합니다.
이 글은 브라우저 다시 그리기 및 성능 최적화에 대한 많은 원칙을 담고 있으며, 난이도는 중급 및 고급 수준입니다. .
소개
최근 시차 사이트가 대세입니다. 다음 사이트를 확인해 보세요.
Old Pulteney Row to the Pole
Adidas Snowboarding
BBC 뉴스 - 제임스 본드: 자동차, 캐치프레이즈, 키스
아직 모르신다면 사실 스크롤을 하면 페이지의 시각적 구조가 바뀌는 사이트들입니다. 일반적인 상황에서 페이지의 요소는 크기가 조정되거나 회전되거나 스크롤 위치로 이동됩니다.
시차 효과 데모 페이지
시차 웹 사이트를 좋아하는지 여부는 중요하지만 확실히 확인할 수 있는 것은 성능 블랙홀이라는 것입니다. . 그 이유는 스크롤할 때 브라우저가 새 콘텐츠가 나타나는 위치(스크롤 방향을 기준으로)에서 성능 최적화를 수행하려고 시도하며 일반적으로 브라우저의 시각적 업데이트가 덜할수록 더 좋기 때문입니다. 큰 시각적 요소가 페이지 전체에서 여러 번 변경되어 브라우저가 전체 페이지를 다시 그려야 하기 때문에 시차 웹사이트에서는 이러한 현상이 거의 발생하지 않습니다. (성능 블랙홀인 이유는 내 기사 "웹 스크롤 성능 최적화 실습"을 참조하세요.) ").
시차 웹사이트를 다음과 같이 요약하는 것이 합리적입니다.
1. 페이지를 위아래로 스크롤하면 배경 요소의 위치가 바뀌거나 회전하거나 크기가 조정됩니다.
2. 텍스트나 작은 그림과 같은 페이지 콘텐츠는 특별한 위에서 아래로 스크롤됩니다.
이전에 스크롤 성능과 이를 최적화하여 앱의 응답성을 향상시킬 수 있는 방법을 소개한 바 있습니다. 이 글은 이를 바탕으로 작성되었으므로 위의 글을 먼저 읽어야 합니다.
이제 질문은 시차 스크롤 웹사이트를 구축하는 경우 비용이 많이 드는 다시 그리기를 수행해야 합니까, 아니면 성능을 최대화하기 위해 채택할 수 있는 다른 방법이 있습니까?입니다. 옵션을 살펴보겠습니다.
방법 1: DOM 요소 및 절대 위치 지정 사용
아마도 대부분의 사람들이 선택하는 방식일 것입니다. 페이지에는 많은 요소가 있으며 스크롤 이벤트가 트리거되면 이러한 요소에서 많은 시각적 업데이트가 발생합니다. 여기에 데모 페이지가 표시됩니다.
개발자 도구 타임라인에서 프레임 모드를 활성화하고 위아래로 스크롤하면 비용이 많이 드는 전체 화면 그리기 작업을 볼 수 있습니다. 여러 번 스크롤하면 단일 프레임에 여러 스크롤 이벤트가 표시될 수 있으며 각 트리거 레이아웃이 작동합니다.
개발자 도구는 프레임에 수많은 그리기 작업과 여러 이벤트에 의해 트리거되는 레이아웃을 보여줍니다.
60fps(일반적인 모니터 새로 고침 빈도 60Hz와 일치)에서는 거의 16ms 안에 모든 작업을 수행해야 합니다. 이 첫 번째 버전에서는 스크롤 이벤트를 받을 때마다 시각적 업데이트를 수행해야 하지만 이전 기사에서 논의한 것처럼 "requestAnimationFrame을 사용하여 더 간단한 애니메이션 구현" 및 "웹 스크롤 성능 최적화 실습"과 일치하지 않습니다. 브라우저의 업데이트 리듬. 그래서 우리는 프레임을 놓치거나 한 프레임에 너무 많은 작업을 수행하게 됩니다. 이는 사이트를 불편하고 부자연스럽게 보이게 만들어 사용자의 불만을 야기할 수 있습니다.
스크롤 이벤트의 시각적 업데이트 코드를 requestAnimationFrame 콜백으로 이동하고 스크롤 이벤트 콜백에서 스크롤 값을 간단히 가져오겠습니다. 두 번째 데모에서는 이러한 변경 사항을 보여줍니다.
롤링 테스트를 반복하면 별것 아니지만 약간의 개선이 있을 수 있습니다. 그 이유는 스크롤에 의해 트리거되는 레이아웃 작업은 비용이 많이 들고 이제 레이아웃 작업은 프레임당 한 번만 수행하기 때문입니다.
개발자 도구는 하나의 프레임에 수많은 그리기 작업과 여러 이벤트에 의해 트리거되는 레이아웃을 보여줍니다.
이제 모든 프레임에서 처리할 수 있습니다. 하나 또는 수백 개의 스크롤 이벤트가 있지만 가장 중요한 것은 requestAnimationFrame 콜백이 트리거되고 시각적 업데이트를 수행할 때 사용할 최신 스크롤 값만 저장한다는 것입니다. 핵심은 스크롤 이벤트를 수신할 때마다 시각적 업데이트를 최적화하는 것에서 브라우저가 제공하는 적절한 순간에 이를 수행하는 것으로 전환했다는 것입니다. 이게 꽤 강력하다고 생각하시나요?
이 방법의 주요 문제점은 requestAnimationFrame을 사용하든 사용하지 않든 기본적으로 전체 페이지의 레이어를 생성하게 되며, 이러한 시각적 개체를 이동할 때 많은 비용이 드는 작업이 필요하다는 것입니다. 요소 다시 그리기. 일반적으로 다시 그리기는 차단 작업입니다(최적화되긴 하지만). 이는 브라우저가 동시에 다른 작업을 수행할 수 없음을 의미하며, 종종 브라우저의 16ms 프레임 처리 시간 제한을 초과할 수 있으며, 이는 성능 지연이 있음을 의미합니다. 데이턴 상황.
방법 2: DOM 요소 및 3D 변환 사용
절대 위치 지정 외에도 사용할 수 있는 또 다른 방법은 3D 변환(변환)입니다. 이 경우 3D 변환으로 처리된 각 요소가 새 레이어를 생성하는 것을 볼 수 있습니다. 대조적으로, 방법 1에서는 변경 사항이 있으면 페이지의 많은 부분을 다시 그려야 합니다.
이는 이 방법을 사용하면 상황이 매우 다르다는 것을 의미합니다. 3D 변환이 적용된 모든 요소에 대한 레이어가 있을 수 있습니다. 더 많은 요소를 변환하여 이 작업을 수행하면 어떤 레이어도 다시 그릴 필요가 없으며 GPU는 요소 이동과 전체 페이지 합성을 처리할 수 있습니다. 3D 대신 3D 변환을 사용하는 이유가 궁금하실 수도 있습니다. 그 이유는 2D 변환이 새 레이어를 얻는 것을 보장하지 않는 반면 3D 변환은 을 수행합니다.
3D 변환을 이용한 또 다른 데모입니다. 스크롤을 해보면 성능이 많이 향상되었음을 알 수 있습니다.
많은 사람들이 -webkit-transform:translateZ(0) 기술을 사용하여 놀라운 성능 향상을 볼 수 있습니다. (Yujie 참고: 이 방법에 대해서는 실제로 3D 변환을 사용하여 브라우저 하드웨어를 활성화합니다. 가속도는 국내 정보에서는 거의 언급되지 않는 일종의 Hack이지만, 중국에서는 모바일 앱 개발 성능 최적화, 해외에서는 "HTML5 웹 페이지 성능 향상"에 대한 기사가 많이 있습니다. "모바일 기기에서 HTML 및 JavaScript 성능 향상") . 이 방법은 이제 정상적으로 작동할 수 있지만 몇 가지 문제가 발생합니다.
1. 브라우저와 호환되지 않습니다.
2. 브라우저가 새 레이어를 생성하도록 합니다. 레이어 수가 많으면 다른 성능 병목 현상이 발생할 수 있으므로 드물게 사용해야 합니다.
3. 일부 Webkit 버전의 포트에서는 비활성화되어 있습니다.
따라서 이 방법을 채택할 경우 이는 일시적인 문제 해결 방법이므로 매우 주의해야 합니다. 완벽한 세상에서 우리는 그것에 대해 생각조차 하지 않을 것이고 브라우저가 매일 향상되면서 언젠가는 그것이 필요하지 않을 것이라는 것을 누가 알겠습니까?
방법 3: 고정 위치 캔버스 또는 WebGL 사용
마지막으로 고려해야 할 방법은 페이지에 고정 위치 캔버스를 사용하고 변환된 이미지를 넣는 것입니다. 위에 그려져 있습니다. 언뜻 보면 가장 효율적인 솔루션은 아닐 수도 있지만 여러 가지 이점이 있습니다.
더 이상 많은 합성 작업이 필요하지 않습니다. 페이지에는 캔버스라는 요소가 하나만 있으므로
하드웨어 가속을 통해 단일 비트맵을 효율적으로 처리할 수 있습니다. 우리를 위해 수행할 변환 유형은 개발 및 유지 관리가 더 관리하기 쉽다는 것을 의미합니다.
Canvas 요소를 사용하면 새 레이어가 제공되지만 레이어는 하나만 있는 반면, 방법 2에서는 3D 변형이 적용되는 모든 요소에 대해 새 레이어를 생성하므로 추가 작업이 필요합니다. 이러한 레이어는 합성됩니다. 함께.
이 방법의 시연을 보고 개발자 도구에서 관찰해 보면 성능이 더욱 향상된다는 것을 알 수 있습니다. 이 방법에서는 캔버스에서 drawImage API를 호출하고, 배경 이미지를 설정하고, 각 색상 블록이 화면의 올바른 위치에 그려지기만 하면 됩니다.
/** * Updates and draws in the underlying visual elements to the canvas. */ function updateElements () { var relativeY = lastScrollY / h; // Fill the canvas up context.fillStyle = "#1e2124"; context.fillRect(0, 0, canvas.width, canvas.height); // Draw the background context.drawImage(bg, 0, pos(0, -3600, relativeY, 0)); // Draw each of the blobs in turn context.drawImage(blob1, 484, pos(254, -4400, relativeY, 0)); context.drawImage(blob2, 84, pos(954, -5400, relativeY, 0)); context.drawImage(blob3, 584, pos(1054, -3900, relativeY, 0)); context.drawImage(blob4, 44, pos(1400, -6900, relativeY, 0)); context.drawImage(blob5, -40, pos(1730, -5900, relativeY, 0)); context.drawImage(blob6, 325, pos(2860, -7900, relativeY, 0)); context.drawImage(blob7, 725, pos(2550, -4900, relativeY, 0)); context.drawImage(blob8, 570, pos(2300, -3700, relativeY, 0)); context.drawImage(blob9, 640, pos(3700, -9000, relativeY, 0)); // Allow another rAF call to be scheduled ticking = false; } /** * Calculates a relative disposition given the page’s scroll * range normalized from 0 to 1 * @param {number} base The starting value. * @param {number} range The amount of pixels it can move. * @param {number} relY The normalized scroll value. * @param {number} offset A base normalized value from which to start the scroll behavior. * @returns {number} The updated position value. */ function pos(base, range, relY, offset) { return base + limit(0, 1, relY - offset) * range; } /** * Clamps a number to a range. * @param {number} min The minimum value. * @param {number} max The maximum value. * @param {number} value The value to limit. * @returns {number} The clamped value. */ function limit(min, max, value) { return Math.max(min, Math.min(max, value)); }
이 접근 방식은 큰 이미지(또는 캔버스에 쓰기 쉬운 기타 요소) 또는 큰 이미지를 처리할 때 매우 유용합니다. 블록 텍스트는 확실히 도전적입니다. 그러나 귀하의 웹사이트에서는 이것이 가장 적절한 솔루션임이 입증될 수 있습니다. 캔버스에서 텍스트를 처리해야 한다면 fillText API를 사용하고 싶을 수도 있지만 액세스 비용이 들고(텍스트를 비트맵으로 변환했을 뿐입니다!) 텍스트 줄바꿈 및 다른 문제. 이런 일이 발생하지 않도록 노력해야 합니다.
너무 많이 논의한 결과, 시차 작업에 캔버스 요소를 사용해야 한다고 가정할 이유가 없습니다. 브라우저가 지원한다면 WebGL을 사용할 수 있습니다. 여기서 핵심은 WebGL이 모든 API에서 그래픽 카드까지 가장 직접적인 방법이라는 점이며, 사이트 효과가 복잡할 경우 성능이 60fps에 도달할 가능성이 가장 높다는 것입니다.
WebGL을 사용하는 것이 과도하거나 널리 지원되지 않는다는 것이 가장 즉각적인 반응일 수 있지만 Three.js와 유사한 라이브러리를 사용하는 경우 언제든지 Canvas 요소를 사용할 수 있습니다. 동시에 코드를 일관되고 친숙한 방식으로 추상화할 수 있습니다. 우리가 해야 할 일은 Modernizr을 사용하여 해당 API에 대한 지원을 검색하는 것입니다:
// check for WebGL support, otherwise switch to canvas if (Modernizr.webgl) { renderer = new THREE.WebGLRenderer(); } else if (Modernizr.canvas) { renderer = new THREE.CanvasRenderer(); }
그런 다음 우리 대신 Three.js의 API를 사용하십시오. 프로세스 컨텍스트. 다음은 두 가지 렌더링 방법을 모두 지원하는 데모입니다.
이 접근 방식의 마지막 문제점은 페이지에 추가 요소를 추가하는 것을 특별히 좋아하지 않는 경우 Firefox 및 Webkit 브라우저에서 항상 캔버스를 배경 요소로 사용할 수 있다는 것입니다. 물론 이것이 보편적으로 적용되는 것은 아니므로 주의가 필요합니다.
점진적 저하
개발자가 다른 방법 대신 기본적으로 절대 위치 요소를 사용하는 주된 이유는 단순히 브라우저 지원의 문제일 수 있습니다. 이 접근 방식은 어느 정도 잘못된 것입니다. 오래된 브라우저의 경우 매우 열악한 렌더링 경험만 제공할 수 있기 때문입니다. 최신 브라우저에서도 절대 위치 지정을 사용한다고 해서 반드시 좋은 성능이 나오는 것은 아닙니다.
더 나은 해결책은 오래된 브라우저에서 시차 효과를 시도하지 않고 최고의 브라우저만 사용하여 올바른 API를 사용하여 사이트 효과를 렌더링할 수 있도록 하는 것입니다. 물론 Three.js를 사용하는 경우 필요한 지원에 따라 렌더러 간에 쉽게 전환할 수 있어야 합니다.
결론
절대 위치 요소부터 고정 위치 캔버스 사용에 이르기까지 크게 다시 그려진 영역을 처리하는 여러 가지 방법을 평가했습니다. 물론 취하는 접근 방식은 달성하려는 목표와 특정 디자인에 따라 다르지만 옵션이 있다는 것을 알아 두는 것이 좋습니다. 이 기사의 예에서는 상대적으로 느린 30fps 미만의 효과를 부드러운 60fps 효과로 최적화하는 데 성공했습니다.
위 내용은 HTML5를 활용한 고성능 시차 웹사이트 구축을 위한 그래픽 및 텍스트 코드에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!