Никита Дубко, Яндекс
Никита Дубко, Яндекс
от фр. animation «оживление; одушевление»
/* Intrinsic reasons that can be known right away by the layer. */
V(3DTransform) \
V(Video) \
V(Canvas) \
V(Plugin) \
V(IFrame) \
V(BackfaceVisibilityHidden) \
V(ActiveTransformAnimation) \
V(ActiveOpacityAnimation) \
V(ActiveFilterAnimation) \
V(ActiveBackdropFilterAnimation) \
V(ScrollDependentPosition) \
V(OverflowScrollingTouch) \
V(OverflowScrollingParent) \
V(OutOfFlowClipping) \
V(VideoOverlay) \
V(WillChangeTransform) \
chromium//src/third_party/blink/renderer/platform/graphics/compositing_reasons.h
V(3DTransform)
...
V(OverflowScrollingTouch)
...
V(WillChangeTransform)
chromium//src/third_party/blink/renderer/platform/graphics/compositing_reasons.h
position: absolute
формируется по краям padding box
ближайшего родителя, у которого position
не static
;position: absolute
или position: fixed
также может формироваться по краям padding box ближайшего родителя, у которого: transform
не равен none
;perspective
не равен none
;will-change: transform
или will-change: perspective
;filter
не равен none
;contain
равен paint
..gallery__item {
animation-name: scroller-overflow-hack;
animation-fill-mode: forwards;
animation-duration: 1ms;
}
@keyframes scroller-overflow-hack {
0% { opacity: .9999; }
100% { opacity: 1; }
}
@media screen and
(prefers-reduced-motion: reduce),
(update: slow) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
}
}
Designing Safer Web Animation For Motion Sensitivity
const element = document.querySelector('.my-element');
element.animate([
{'--some-color': 'red', 'opacity': 0 },
{'--some-color': 'blue', 'opacity': 1 },
], {
direction: 'alternate',
duration: 5000,
iterations: Infinity,
});
Using the Web Animations API
document.getAnimations().forEach(
function (animation) {
animation.playbackRate *= 0.5;
}
);
// animator.js
registerAnimator(
'scroll-position-animator',
class {
constructor(options = {}) {
this.coef = options.coef || 1;
}
animate(currentTime, effect) {
effect.localTime = currentTime * this.coef;
}
});
Houdini's Animation Worklet, Surma
// app.js
await CSS.animationWorklet.addModule("animator.js");
new WorkletAnimation(
'scroll-position-animator',
keyframeEffect,
scrollTimeline,
{ coef: 1.2 }
).play();
const keyframeEffect = new KeyframeEffect(
document.querySelector('#target'),
[
{ transform: 'translateX(0)' },
{ transform: 'translateX(500px)' }
],
{
duration: 2000,
iterations: Number.POSITIVE_INFINITY
}
);
const scrollTimeline = new ScrollTimeline({
timeRange: 2000,
scrollSource: document.querySelector('.source'),
orientation: 'vertical',
startScrollOffset: '200px',
endScrollOffset: '500px'
});
<animateMotion
xlink:href="#circle"
dur="1s"
begin="click"
fill="freeze"
path="M0,0c3.2-3.4,18.4-0.6,23.4-0.6c5.7,0.1,10.8,0.9,16.3,2.3 c13.5,3.5,26.1,9.6,38.5,16.2c12.3,6.5,21.3,16.8,31.9,25.4c10.8,8.7,21,18.3,31.7,26.9c9.3,7.4,20.9,11.5,31.4,16.7
c13.7,6.8,26.8,9.7,41.8,9c21.4-1,40.8-3.7,61.3-10.4c10.9-3.5,18.9-11.3,28.5-17.8c5.4-3.7,10.4-6.7,14.8-11.5
c1.9-2.1,3.7-5.5,6.5-6.5" />
A Guide to SVG Animations (SMIL)
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
function draw(time) {
const w = canvas.width;
const h = canvas.height;
ctx.fillStyle = '#111';
ctx.fillRect(0, 0, w, h);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
Можно применять для отрисовки свойств:
background-image
border-image
list-style-image
content
-webkit-mask-image
cursor
registerPaint('my-paint', class MyPaint {
static get inputProperties() { return ['--foo']; }
static get inputArguments() { return ['<color>']; }
static get contextOptions() { return { alpha: true }; }
paint(ctx, geom, properties, args) {
// Можно рисовать почти как на обычном canvas
}
});
/* style.css */
.my-element {
--foo: deeppink;
background-image: paint(my-paint);
}
// app.js
CSS.paintWorklet.addModule('my-paint.js');
const element = document.querySelector('.elem');
const styleMap = element.attributeStyleMap;
console.log( styleMap.get('font-size') );
// CSSUnitValue {value: 2.5, unit: "em"}
const computedStyleMap = element.computedStyleMap();
console.log( computedStyleMap.get('font-size') );
// CSSUnitValue {value: 25, unit: "px"}
const styleMap = element.attributeStyleMap;
const transformValue = new CSSTransformValue([
new CSSTranslate(
CSS.px(50),
new CSSMathSum(CSS.em(1), CSS.px(5))
)
]);
styleMap.set('transform', transformValue);
if (window.CSS && CSS.number) {
// В вашем браузере CSS Typed OM работает
}
elem.offsetLeft
, elem.offsetTop
, elem.offsetWidth
, elem.offsetHeight
, elem.offsetParent
elem.getClientRects()
, elem.getBoundingClientRect()
elem.scrollBy()
, elem.scrollTo()
window.getComputedStyle()
inputElem.focus()
function frame() {
const element = document.querySelector('.block');
element.style.width = element.offsetWidth * 2;
};
requestAnimationFrame(frame);
will-change: top, left, bottom, right;
.child {
transition: opacity .3s linear;
}
.parent:hover .child {
will-change: opacity;
}
.child:hover {
opacity: .5;
}
var el = document.getElementById('element');
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);
function hintBrowser() {
this.style.willChange = 'transform, opacity';
}
function removeHint() {
this.style.willChange = 'auto';
}
document.querySelector('.block')
.addEventListener(
'scroll',
() => {...},
{ passive: true }
);
Improving scrolling performance with passive listeners
transition-delay: 50ms;
animation-delay: 50ms;