Retina-дисплеи (и другие экраны с высокой плотностью пикселей, High DPI) характеризуются увеличенным количеством физических пикселей на единицу площади. Это приводит к более чёткому отображению графики, но одновременно предъявляет повышенные требования к качеству визуальных ресурсов и точности анимаций.
В контексте ScrollMagic это особенно важно, поскольку библиотека активно используется для создания визуально насыщенных эффектов прокрутки, где малейшие артефакты становятся заметными.
Ключевая характеристика — devicePixelRatio (DPR):
window.devicePixelRatio
Значение:
1 — стандартные дисплеи2 и выше — Retina / High DPIЕсли используются изображения с недостаточным разрешением, на Retina-экранах они выглядят размытыми.
Особенно это заметно при:
pin в ScrollMagic)ScrollMagic рассчитывает позиции элементов на основе CSS-пикселей. При дробных значениях и трансформациях возможны:
Высокая плотность пикселей увеличивает нагрузку:
Рекомендуется использовать изображения в 2x (или 3x) размере:
<img src="image@2x.png" width="500" height="300">
Или через srcset:
<img
src="image.png"
srcset="image@2x.png 2x, image@3x.png 3x"
alt=""
>
Это позволяет браузеру автоматически выбрать нужное изображение.
SVG идеально подходит для ScrollMagic-анимаций:
<svg width="100%" height="100%">
<circle cx="50" cy="50" r="40" />
</svg>
Анимации через transform:
Пример с GSAP:
gsap.to(".box", {
x: 100,
y: 50,
scale: 1.2
});
Вместо:
// менее эффективно
element.style.left = "100px";
Для избежания размытия:
x: Math.round(value)
Или:
gsap.to(".box", {
x: Math.round(100.5)
});
Это особенно важно для текста и тонких линий.
new ScrollMagic.Scene({
triggerElement: "#trigger",
triggerHook: 0.5
})
На Retina-дисплеях дробные значения могут вызывать нестабильность. Иногда предпочтительно использовать:
triggerHook: 0
// или
triggerHook: 1
для более предсказуемого поведения.
Метод setPin() может вызывать проблемы:
scene.setPin(".element");
Возможные артефакты:
transform: translateZ(0).element {
transform: translateZ(0);
}
will-change.element {
will-change: transform;
}
.element {
transform: translate3d(0, 0, 0);
}
Canvas требует отдельного внимания:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio || 1;
canvas.width = canvas.offsetWidth * dpr;
canvas.height = canvas.offsetHeight * dpr;
ctx.scale(dpr, dpr);
Без этого Canvas будет выглядеть размытым.
При использовании видео в ScrollMagic:
scene.setTween(video, { currentTime: 10 });
Важно:
Параллакс-эффекты особенно чувствительны к качеству:
gsap.to(".bg", {
y: "-50%"
});
Рекомендации:
background-size: coverТекст может терять чёткость при анимациях:
gsap.to(".text", {
scale: 1.1
});
На Retina:
gsap.to(".text", {
opacity: 0.5
});
transform-origin:transform-origin: center center;
scale: 1.02
@media
(-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
.image {
background-image: url("image@2x.png");
}
}
Позволяет подгружать более качественные ресурсы.
ScrollMagic часто обновляет состояние при прокрутке. На Retina это дороже.
Рекомендации:
width,
height, top)transform и opacitynew ScrollMagic.Scene(...)
Большое количество сцен:
Лучше объединять анимации.
Использование индикаторов:
scene.addIndicators();
На Retina они выглядят иначе:
Ошибка: использование обычных PNG Результат: размытые параллакс-слои
Ошибка: анимация через left/top Результат: лаги и дергание
Ошибка: игнорирование devicePixelRatio в Canvas Результат: мыльная графика
Ошибка: масштабирование маленьких изображений Результат: потеря качества
Оптимальный стек:
const controller = new ScrollMagic.Controller();
new ScrollMagic.Scene({
triggerElement: ".section",
duration: 500
})
.setTween(
gsap.to(".box", {
x: 200,
force3D: true
})
)
.addTo(controller);
force3D: true:
Контрольные признаки корректной работы:
Наличие хотя бы одного отклонения указывает на необходимость оптимизации под High DPI.