Svelte-Cubed: 여러 장치에서 액세스 가능하고 일관된 경험 만들기
이 짧은 기사에서 우리는 관련 없는 두 종류의 주제를 살펴볼 것입니다. 그러나 둘 다 사용자 경험 개선이라는 범주에 속합니다.
prefers-reduced-motion
를 사용하여 장면에서 사물을 조건부로 애니메이션/전환합니다getDelta()
를 사용하여 장치 프레임 속도가 다른 사용자에 대해 동일한 동작을 렌더링함시작하기 위해 파트 2가 중단된 REPL은 다음과 같습니다.
https://svelte.dev/repl/9b3b351fe187421b84a6f1616e2c9e3d
조건부 모션: prefers-reduced-motion
왜 중요합니까?
Not everyone likes decorative animations or transitions, and some users outright experience motion sickness when faced with parallax scrolling, zooming effects, and so on. The user preference media query prefers-reduced-motion lets you design a motion-reduced variant of your site for users who have expressed this preference.
- prefers-reduced-motion: Sometimes less movement is more의 Thomas Steiner( )
그리고 우리는 모든 사람이 우리의 장면을 즐길 수 있기를 원하므로 먼저 Svelte 구성 요소에서 사용할 수 있도록 JavaScript에서 이 기본 설정을 감지하는 방법을 알아봅시다. 저는 그의 게시물A Svelte store for prefers-reduced-motion에서 설명한 Geoff Rich( )의 접근 방식을 사용할 것입니다.
새 자바스크립트 파일
stores.js
에서 Geoff의 모든 코드를 훔쳐서(나중에 참조할 수 있도록 인용하세요!) 붙여넣을 수 있습니다.import { readable } from "svelte/store";
/*
Source: Geoff Rich,
"A Svelte store for prefers-reduced-motion",
URL: https://geoffrich.net/posts/svelte-prefers-reduced-motion-store/
*/
const reducedMotionQuery = '(prefers-reduced-motion: reduce)';
const getInitialMotionPreference = () => window.matchMedia(reducedMotionQuery).matches;
export const reducedMotion = readable(getInitialMotionPreference(), set => {
const updateMotionPreference = event => {
set(event.matches);
};
const mediaQueryList = window.matchMedia(reducedMotionQuery);
mediaQueryList.addEventListener('change', updateMotionPreference);
return () => {
mediaQueryList.removeEventListener('change', updateMotionPreference);
};
});
reducedMotion
저장소는 값이 변경되면 애플리케이션의 어느 위치에서든 구독하고 반응할 수 있는 부울을 제공합니다. 어떻게 사용할 수 있습니까? 음, 우리가 애니메이션을 적용할 때마다 우선 기본 설정을 확인하고 필요에 따라 조정할 수 있습니다. 모션은 트위닝된 저장소와 SC.onFrame()
콜백의 두 소스에서 나옵니다.첫째: 사용자가 움직임 감소를 선호하는 경우 트위닝된 저장 기간은 0이 됩니다(즉, 값 a에서 값 b로 즉시 이동).
import { reducedMotion } from "./stores"
let scale = tweened(1, {duration: $reducedMotion ? 0 : 2000, easing: elasticOut});
그게 다야? 그게 다야!
두 번째: 사용자가 움직임 감소를 선호하지 않는 경우 모든 프레임에서 회전을 업데이트할 수 있습니다.
if(!$reducedMotion){
SC.onFrame(() => {
rotate += .01;
})
}
어떻게 테스트할 수 있습니까? Geoff는 다음을 다루었습니다.
Here's how to simulate the setting in Chrome DevTools and where to enable the setting in various OSes and Firefox
devtools의 설정만 시뮬레이션하고 있기 때문에 devtools를 열어두고 REPL을 새로 고쳐서 상황이 어떻게 변하는지 확인해야 합니다.
장치 간 가변 프레임 속도 처리
그 모든 단어는 무엇을 의미합니까? 훨씬 더 똑똑한 사람들이 나보다 더 잘 설명할 수 있지만, 한 번 시도한 다음 더 나은 설명을 알려 드리겠습니다.
일부 컴퓨터/모니터 설정에는 강력한 그래픽이 있고 일부는 그렇지 않습니다. 예를 들어, 8면체는 각 프레임에서 0.1라디안으로 회전합니다. 따라서 초당 60프레임(fps)으로 실행되는 설정은 Octahedron이 초당 0.1라디안으로 60번 회전하는 것을 관찰하는 것입니다. 30fps로 실행되는 덜 강력한 설정은 Octahedron이 초당 0.1라디안으로 30번만 회전하는 것을 보는 것입니다. 그것들은 매우 다른 경험입니다!
보다 정확하고 심층적인 설명은 Lewy Blue( )의 오픈 소스 책 Discover three.js에서 체크아웃The Animation Loop 장을 참조하십시오. three.js를 처음 사용하는 경우 시간을 내어 전체 책을 살펴보는 것이 좋습니다!
기본적으로 현재 프레임 속도를 기반으로 하드 코딩된 값
SC.onFrame
을 표준화하는 방법이 필요합니다. threejs Clock과 메서드getDelta()
를 사용하고 값에 델타를 곱하면 됩니다.const clock = new THREE.Clock();
SC.onFrame(() => {
rotate += .01 * clock.getDelta();
})
와우, 느립니다. 그러나 모두에게 느립니다! 이제 회전 값을 조정하여 원하는 속도를 얻을 수 있습니다(0.5 시도).
다음 기사에서는 Octahedron 친구에서 벗어나 하나 이상의 glTF 모델을 장면에 로드하는 방법을 살펴보겠습니다!
참조
REPL: https://svelte.dev/repl/c301f0ac026d45bdbf4facf55b921d1f?version=3.48.0
Octo.svelte
<script>
import * as THREE from "three";
import * as SC from "svelte-cubed";
import { tweened } from "svelte/motion"
import { elasticOut } from "svelte/easing"
import { reducedMotion } from "./stores"
let scaleType = "MEDIUM";
let scale = tweened(1, {duration: $reducedMotion ? 0 : 2000, easing: elasticOut});
// reactive statement to update scale based on scaleType
$: if (scaleType === "SMALL"){
$scale = .25;
} else if (scaleType === "MEDIUM"){
$scale = 1;
} else if (scaleType === "LARGE") {
$scale = 1.75;
}
let rotate = 0;
if(!$reducedMotion){
const clock = new THREE.Clock();
SC.onFrame(() => {
rotate += 0.5 * clock.getDelta();
})
}
</script>
<SC.Canvas background={new THREE.Color('seagreen')}>
<SC.AmbientLight
color={new THREE.Color('white')}
intensity={.5}
/>
<SC.DirectionalLight
color={new THREE.Color('white')}
intensity={.75}
position={[10, 10, 10]}
/>
<!-- MESHES -->
<SC.Mesh
geometry={new THREE.OctahedronGeometry()}
material={new THREE.MeshStandardMaterial({
color: new THREE.Color('salmon')
})}
rotation={[rotate, rotate, rotate]}
scale={[$scale, $scale, $scale]}
/>
<!-- CAMERA -->
<SC.PerspectiveCamera near={1} far={100} fov={55}>
</SC.PerspectiveCamera>
<SC.OrbitControls />
</SC.Canvas>
<div class="controls">
<label>
SMALL
<input type="radio" bind:group={scaleType} value="SMALL" />
</label>
<label>
MEDIUM
<input type="radio" bind:group={scaleType} value="MEDIUM" />
</label>
<label>
LARGE
<input type="radio" bind:group={scaleType} value="LARGE" />
</label>
</div>
<style>
.controls {
position: absolute;
top: .5rem;
left: .5rem;
background: #00000088;
padding: .5rem;
color: white;
}
</style>
store.js
import { readable } from "svelte/store"
/*
Source: Geoff Rich,
"A Svelte store for prefers-reduced-motion",
URL: https://geoffrich.net/posts/svelte-prefers-reduced-motion-store/
*/
const reducedMotionQuery = '(prefers-reduced-motion: reduce)';
const getInitialMotionPreference = () => window.matchMedia(reducedMotionQuery).matches;
export const reducedMotion = readable(getInitialMotionPreference(), set => {
const updateMotionPreference = event => {
set(event.matches);
};
const mediaQueryList = window.matchMedia(reducedMotionQuery);
mediaQueryList.addEventListener('change', updateMotionPreference);
return () => {
mediaQueryList.removeEventListener('change', updateMotionPreference);
};
});
Reference
이 문제에 관하여(Svelte-Cubed: 여러 장치에서 액세스 가능하고 일관된 경험 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/alexwarnes/svelte-cubed-creating-an-accessible-and-consistent-experience-across-devices-42ae텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)