[MUSIC PLAYING]
ADAM ARGYLE: I'm Adam Argyle.
JASON MILLER: I'm Jason Miller.
We're here to talk to
you about Smooth Moves.
When we were thinking of what
to talk about at CDS this year,
we wanted to demonstrate
some techniques
for optimizing performance
of existing applications.
So we were trying
to think of what's
an app that Google doesn't have,
something not in our portfolio.
It took us a while to
come up with something,
but I think we kind of
hit the nail on the head.
ADAM ARGYLE: A chat app,
they don't have a chat app.
JASON MILLER: No, it's French.
This is an app for cats.
Sorry, I knew this slide
would be really confusing.
So it's a chat app.
We've been working on an app
that actually facilitates
communication between cats.
ADAM ARGYLE: Meow.
JASON MILLER: We
know cats are working
on this uprising
against humans of sorts,
and we figured that's
sort like an opportunity
for an app that
helps out with this,
with the planning and whatnot.
ADAM ARGYLE: Yeah, so this
is what our app looks like.
The design is sort of a mix a
typical material stuff and take
some inspiration from Android
messages, among others.
And we wanted the UI to be
realistically complex and well
designed, so that it would
be challenging enough
for the browser and we could
measure our optimizations.
And obviously, the text that's
in there, that's cat ipsom.
I don't speak feline.
I don't know what's going on.
JASON MILLER: I do, but
I refuse to make a demo.
ADAM ARGYLE: So next, we turned
on the performance monitor,
because it looked
good on my machine.
We're like, let's measure it.
It seems to look like
everything's decent enough.
JASON MILLER: Yeah.
So, we saw a bit
of jank and some
of the early user feedback we
got was that the app felt slow.
We applied a bunch
of the techniques
that Katie and Hussein
talked about in their talk
earlier today.
But it wasn't cutting it.
And there was
something else wrong.
So we decided to load the
video up on a Nexus 5.
It's really useful to have a
device like this sitting around
as you develop for the web.
As developers, we often
have the privilege
of fast devices on
fast connections.
And that can kind of
trick us into thinking
that we're meeting
our performance goals,
when we're actually not
out in the real world.
So watching the video, you
can see it's far from smooth.
ADAM ARGYLE: Many types
of jank are present.
JASON MILLER: So
smooth, it's a word
we hear a lot when we're
talking about user interface.
ADAM ARGYLE: It's
true, and it can
be difficult to
describe since it's
sort of an invisible metric.
If your app is smooth, no
one really notices anything
is wrong.
JASON MILLER: Right.
ADAM ARGYLE: So then,
what does that really
mean that smooth is.
We thought smooth
could destructure
into these attributes
really well.
So let's break them down.
JASON MILLER: Cool.
ADAM ARGYLE:
Smoothness is something
we believe happens when
the user feels connected
to the app that they're
using, like they're directly
controlling it, a sort
of physical connection
to the interface.
When the application doesn't
respond quickly to input,
it breaks this connection, and
we feel distanced from the task
at hand.
It's best when it
feels like magic paper.
JASON MILLER: Right.
Yeah, so when an application
animates irregularly,
it actually distracts
us, by breaking something
called the illusion of motion.
You can see the illustration
of what I'm talking about up
here on the right.
The eye responds to light
changes at 10 times per second.
So if we show the eye a sequence
of 10 images per second,
we can actually still see
each individual frame.
ADAM ARGYLE: Yeah.
JASON MILLER: So the
brain doesn't necessarily
interpret that as motion.
If we increase this to
20 frames per second,
somewhere in and around
the red orb there,
we start to interpret
this as motion,
because we've exceeded two times
the number of light changes
we can detect.
And this effect
increases as we approach
60 frames per second, where we
start to see some diminishing
returns.
ADAM ARGYLE: Yep.
JASON MILLER:
Basically, smoothness
relates to the human
perception of performance.
It's a measure of the
question, is this application
keeping up with me?
ADAM ARGYLE: Or
does this app feel
like it's helping me
get something done,
or is it getting in my way?
The way the user feels when
interacting with software
is really important.
Because we've all been
in situations like this.
I mean, he was obviously
trying to send a tweet.
And it just wasn't working out.
JASON MILLER: He probably should
have used some newer hardware.
ADAM ARGYLE: Yeah, well,
he's breaking it now.
JASON MILLER: So this is
backed up by statistics too.
In a 2017 study,
46% of people who
had an interruptive
mobile experience
said they wouldn't purchase from
that brand again in the future.
And in that same study, they
found that 79% of people
said they're more likely
to revisit or share
a mobile site that
was easy to use.
ADAM ARGYLE: And another
metric, and it's a good one,
100% of Adams say they
doubt a thing's reliability
if it hiccups while
performing its task.
Maybe you agree.
JASON MILLER: Right.
So anytime we talk about the
perception of performance,
it's useful to frame things
using the RAIL model.
RAIL provides a
set of goals that
cover the four ways we
all perceive performance
and speed when using software.
Those are Response,
which is reacting
to events in 100 milliseconds,
Animation, which is producing
frames in 16 milliseconds, Idol,
which is maximizing idle time,
and Load, which is loading
in under one second.
And these are based off of like
a few years, a few decades,
actually, worth of research.
So they're very
unlikely to change.
ADAM ARGYLE: And you know what
this slide looks like to me
is click, run, swipe, and load.
JASON MILLER: Yeah, we could
have used a different acronym
there, I guess.
ADAM ARGYLE: We'll get there.
JASON MILLER: Cool,
so there's times
that we have to
hit for all these.
ADAM ARGYLE: And we believe
responding to user input
quickly is the first and
arguably most important thing
to do in your app for it to feel
or appear smooth and snappy.
JASON MILLER: Right, even
sticking to RAIL's goals
though, idle work can
potentially delay input
by up to 50 milliseconds,
which we're going
to hear about in a second.
But we recommend responding
to input in 50 milliseconds
in order to have the combined
time never exceed 100.
That's why you'll see the
difference between the goal
and the guideline.
Animation has a similar story.
So there's more
than just our code
that has to run in order to
get a frame on the screen.
To account for a reasonable
amount of browser rendering
overhead, we recommend
shooting for 10 milliseconds
of your JavaScript time
to produce that frame,
leaving six left
over for the browser.
ADAM ARGYLE:
Browser are so cool.
We're talking about six
milliseconds, 10 milliseconds,
who could do anything
in that amount of time?
And the browser's
doing crazy stuff.
JASON MILLER: Right.
ADAM ARGYLE: It's so rad.
JASON MILLER: So in order to--
in addition to deferring
as much work as possible,
it's also good to defer your
working 50 millisecond chunks.
This is where that response
metric gets its differentiation
from.
So if you have 50 millisecond
blocking idle tasks,
there's a chance
that any one of those
could cause input to be queued
for 50 milliseconds, which
means if you need
to respond in 100,
you only have 50
milliseconds left.
So that's where that
metric comes from.
ADAM ARGYLE: And the load
goals, based on research,
is showing that we
generally lose focus
after about one second.
We start to feel
a bit disconnected
from the activity we're doing.
And then at 10 seconds,
we become frustrated,
we go grab a
sledgehammer, and probably
light something on fire.
JASON MILLER: That's how
that picture happened.
So RAIL's guideline
for load is kind
of right in the middle
of those two numbers.
We set it up five seconds.
And this is a good
metric for something
like a page load,
where you're waiting
for a decent amount of
new content to come in,
even a whole screen's
worth of content.
For little interactions,
though, like the sending button
in our chat app,
it's actually best
to shoot for that
one second goal.
There's only a small
amount of content
being changed on screen.
So it's not as
perceivable to the user.
ADAM ARGYLE: Yep,
and with RAIL we
have a nice mental
model for figuring out
why the app feels slow.
And it helps us set
a useful challenge.
And you'll notice on each
slide, as we continue here,
there'll be a little
badge in the top right.
It's have an R, an
A, an I, and an L,
add it'll pertain
to the RAIL model.
JASON MILLER: Right.
So, we're pretty confident that
we can meet RAIL guidelines
on a $1,500 laptop, or maybe
some other very popular laptop.
ADAM ARGYLE: Yeah, that's
a cush laptop there.
Kind of looks like it's on
John Snow's bed or something
like that.
JASON MILLER: Yeah, I've
never seen "Game of Thrones."
I assume that's a reference
to "Game of Thrones."
So we could do it on the laptop.
But can we meet our guidelines
on a sub $100 phone?
ADAM ARGYLE: Uh, duh,
the web is awesome.
JASON MILLER: Yes,
so we want our apps
to be smooth everywhere.
And what we need to
do to ensure that is
to optimize for the
lowest common denominator.
We need to be 60 frames per
second on low-end hardware.
ADAM ARGYLE: So before we
embark on a challenge like this,
though, we need to be able to
measure whether we're meeting
those guidelines or not.
JASON MILLER: Right.
So all the tools that we
have available to measure
these things, live
in Chrome DevTools.
ADAM ARGYLE: DevTools.
JASON MILLER: Right.
We have seen a bunch
of them earlier today.
In Paul, Elizabeth's TALK
they talked specifically
about DevTools.
We're actually going to show a
couple of features in DevTools
that are maybe a little
bit less commonly
used, some of them potentially
even lost to the sands of time.
So let's get into them.
ADAM ARGYLE: The
first tool is down
in the drawer, which you can
pull up using the Escape key.
It's the rendering panel.
It lets you visualize
important things
that we're going to get into
today, like painting layer
borders and live SPF meter.
JASON MILLER: Right.
The second useful
tool is up in three
dot menu in the upper right.
It's called Layers.
It shows a real time view of the
layers that make up your page.
We're going to deep dive
into this in a little bit.
ADAM ARGYLE: [INAUDIBLE]
JASON MILLER: But it's useful
to remember that DevTools
has you covered here.
ADAM ARGYLE: The next tool's
back down in the drawer again.
It's the graphs
we showed earlier,
called the Performance Monitor.
And here you can
monitor various aspects
of your app's performance,
chart it over time.
Plus, it looks so
good on a dark theme.
I just love that.
It's pretty useful
to find hiccups.
JASON MILLER: Right.
Finally, there's Lighthouse.
And we've seen a
couple of times today
this used for tracking
load performance metrics.
But you could actually
find it slightly useful
to find runtime metrics in
Lighthouse, particularly
for input response delays.
So Lighthouse doesn't track
for very long after page load.
But it does for a little bit.
And this might be exactly
the kind of heads-up
you need to figure
out that there
are some optimizations left
for you to do on your website.
ADAM ARGYLE: Cool, all
right, it's business time.
We're equipped with some
tools and strategies on how
to investigate performance.
Let's dive in.
JASON MILLER: Let's dive in.
So we came up with three
types of optimizations
that we hope will help address
common performance issues.
We have efficient animations,
reading and then writing,
and then sort of a
grab bag of things
that we're calling lazy winds.
So that's sort of a mix.
So we'll start off with
efficient animations.
Animating things
effectively in the browser
really requires a somewhat
deep understanding
of how browsers render.
Let's say we want to
build like the chat UI
that we showed in the intro.
ADAM ARGYLE: Chat UI.
JASON MILLER:
Right, chat, sorry.
We want to write some HTML, give
it a bunch of fancy styling,
and then arbitrary
magic happens and you
have pixels on a screen.
That level of
understanding is not enough
for us to be able
to optimize here.
So let's dig into it.
We start off with some HTML.
This all gets passed and
turned into a tree structure
that we call the Dom.
You're familiar with the Dom.
And this sort of
preps us to the point
where we're ready to render,
which is a four-step process.
The first step is
style calculation.
So the browser needs to compute
all the styles for the elements
that you see, which is resolving
things to their final values,
resolving CSS custom properties,
inherited values, et cetera.
And it does this by going
through all the elements
and figuring out which CSS
properties apply to them.
With those values
calculated, we can figure out
the positions of where all those
elements are on the screen.
So you see those are represented
as boxes up here on the right.
The cost of this calculation
step varies quite a bit.
Some types of layouts
are multi-packs,
which means that they
need to be laid out
multiple times before they're
in their final resting state.
And other types, like position
absolute, are just static.
So they only need
to be one pass.
So that computed layout
has enough information
to break things up into pieces
that we call paint layers.
Here in the painting process,
we walk through all the paint
layers and we convert
the layered information
that we had into Draw commands.
And these sort of look
like the 2D canvas API,
if you've used that.
So Chrome takes these
and it sends them over
to its graphics layer,
which is called Skia.
And those get
rasterized and sent back
as image representations.
ADAM ARGYLE: Wait a second,
Chrome, they're skias?
I thought they
were snowboarders.
JASON MILLER: No, all skias.
OK so, with the paint
layers rasterized,
the last step is
to composite them.
So this step takes all the
rasterized essentially images
at this point and lays them
out on top of each other
in order to make things
look like the final page.
So what you get is the
result on the right,
which is what we wanted.
This whole process
applies anytime
you have page updates that
are triggered by JavaScript
manipulating the Dom.
So let's say we want to
update the left property
of a div, left
position of a div.
The browser is going to
have to recalculate styles.
It's going to have to redo
the layout, because they have
changed, paint all the
paint layers that changed,
and then composite them together
to form the resulting page.
Yeah, lot of work.
ADAM ARGYLE: A lot of work.
JASON MILLER: And then if we
set the transform property
for some contrast,
transform opacity
and filter are all what's
called compositable properties.
So modifying these doesn't
actually trigger layout
and can often bypass paint.
So you go straight from style
recalculation to compositing.
ADAM ARGYLE: [INAUDIBLE]
JASON MILLER: Yeah,
so a lot less work.
These things, they get
really important when
you're animating.
On every frame we are now
potentially computing layout,
if you set something
like width or left.
And this is a lot of work
for the browser to do.
This is going to be
a low frame rate.
Animating something
like color, layout
isn't required
because you're not
changing the bounds of the
position of the element.
So on each frame, you're
recalculating styles, painting,
and compositing.
You skip the layout step.
A little better.
This used to be a
performance concern.
But in modern
graphics pipelines,
it's actually pretty fast.
Finally, animating
compositable properties,
like transform
opacity, all that work
is handled by the compositor.
So this is really good
for things like responding
to pan gestures.
Because it's important
to keep that pipeline as
short as possible.
The one thing to
keep in mind, though,
is that compositing is not free.
If you're on resource
constrained devices,
you really need to watch
your composited layer count.
If it gets too high, you
can hit memory [INAUDIBLE]..
ADAM ARGYLE: You pretty
much have jank permanently.
JASON MILLER: So we had a send
button in our application,
and depending on
whether it was enabled
or disabled, whether there
was text in the text field
beside it, it would have a
large or a small box shadow
and change its color.
So originally, we just did a CSS
transition on the box shadow.
Box shadows are
paint-based animations,
because they physically
cannot affect layout.
And that meant that on every
frame, what we had to do
was send a bunch of new
commands over to Skia,
like we saw in those demos.
So here's an
example of what that
might look like in a
three-frame animation.
And you see it's pretty much
repeating the same process
each time with new variables.
We tried switching this
to a composite animation.
And the way we did that was
we duplicated the button
using a pseudo element.
And then the foreground
was the element
and the background was a pseudo
element with the same shape,
but a box shadow applied to it.
And then all we have to do is
change the opacity of the box
shadow pseudo element
behind the button,
and we can get any of the
frames of the animation we
want between 0 and 100 using
just composited animations.
So any frame can be constructed
from just those two paints.
We do not need to repaint.
You can see this in action too.
So looking at DevTools--
ADAM ARGYLE: I love this GIF.
It's so cool.
JASON MILLER: Yeah, we've
got a paint-based animation
on the top.
That's just box shadow.
The center one is animating the
opacity of a shadow element.
And then the bottom one is
sort of the penultimate,
this is animating
the transform's scale
of the shadow.
ADAM ARGYLE: Hey, why the
middle one paint at the end
and at the end.
JASON MILLER: Yeah, so
paints at the beginning,
paints at the end.
This is when it's being
promoted and then demoted
to a composited layer.
ADAM ARGYLE: That was so quick.
It was barely promoted.
JASON MILLER: Right.
ADAM ARGYLE: That's a bummer.
JASON MILLER: So we
did this experiment.
The profiler told us that
this was a good idea.
Obviously, there's a lot less
main thread work going on
in the second two animations.
These are in order.
And so this might be
something we would want to do.
Except if we're targeting
really low-end mobile devices,
where they might not
have the best GPUs.
The reason why this is
good is because GPUs
are really good at
transforming composited layers.
It's important to remember that
this is not a silver bullet,
though.
You always want to make
sure that you profile,
and that your performance
improvements on desktop
don't become problems on mobile.
ADAM ARGYLE: Measure.
JASON MILLER: And
please, we don't
have context for this
particular slide,
but please don't
animate max height.
This is something that feels
really easy and really good
when you do it, but it can
be really, really brutal
down the line for performance.
ADAM ARGYLE: I also don't
think that's what people even
wanted to do.
It's like you
didn't want to take
something that was
squishy and all warped
and make it unwarped.
I think you really wanted to
reveal the element, right?
JASON MILLER: And I think when
we were doing our performance
optimizations, we just
switched our max height
animation to be slide in.
ADAM ARGYLE: Slide in.
JASON MILLER: We just
used [INAUDIBLE]..
ADAM ARGYLE: Better anyway.
JASON MILLER: OK, so we talked
about efficient animations.
But there's another
whole aspect of rendering
that's really important
if you want to hit that
60 frames per second target.
And that's this idea of
reading and then writing.
To understand this, we
need to take a trip down
to the rendering assembly line.
ADAM ARGYLE: Yeah.
JASON MILLER: So
ideally, when we
look at an app in the
performance tab of DevTools,
we see little chunks
of this sequence.
And these are the frames.
In an ideal situation,
there's a lot of whitespace
in between these, which
means that you don't
have a lot of idle time work.
Your app is sort of
main thread jank free.
ADAM ARGYLE: This looks
like Jake Archibald's socks.
JASON MILLER: I think those are
the color profile we went with.
Yeah, so we peeked at the
anatomy of a frame earlier.
We have style recalculation,
layout, paint, compositing.
We didn't really
dig into the script
portion, that
initial portion that
leads off this whole thing.
And as it turns out,
it's really important.
Not all scripts
are created equal.
So our interaction with the
Dom affects every other step
in the rendering process.
And we can split
out the two types
of scripting into two groups.
We have read and then write.
On the left, you can see
some examples of properties
that are Dom layout reads.
Some of these are pretty
obvious, offset top,
obviously if you want to
know where the element is,
you need to lay it out.
Some of these are not
so obvious though.
Inner text inserts,
it's a string.
It's kind of like text content.
But there's new lines
in it based on layout.
If you have paragraphs or
elements with display block,
the string has new lines in it.
And it's impossible to return
that string without calculating
layout first.
If you're using inner
text in your app,
and you're not using it
specifically for that feature,
I would strongly recommend
going with text content.
On the right is maybe a
little bit more obvious.
If you change CSS layout, add
elements, mutate the Dom tree
structure, you're going
to trigger layout.
ADAM ARGYLE: I wish it was
as simple as like getters
on the left and
setters on the right.
JASON MILLER: Yeah.
ADAM ARGYLE: Yeah.
JASON MILLER: So let's say we
have a timeline like before,
but this time there's
two bits of script that
are going to run.
The first sets the width
of an element to 10 pixels.
The second script, maybe
it's a different script,
asks how much space is
left aside beside fu--
how much space is
left beside that div?
And in order to do
this, it's going
use the offset width property.
This is where things fall apart.
We hadn't had a chance to
calculate style and layout.
So we have to do that
synchronicity now,
which is going to be forced.
So we have to block the main
thread, do all that work,
and then come back to the script
that asked for that width.
And the worst part is,
that script actually
did this to
conditionally then set
the width of fu,
which invalidates
the layout and the style
calculations we did,
which means that they
have to happen again.
ADAM ARGYLE: I smell code smell.
JASON MILLER: Right.
So this is a problem.
And this is really common.
You might be tempted to
use request animation
frame to fix this.
That's actually often
a good strategy.
Let's see how that would work.
So request animation
frame callbacks fire
just before the browser does
all of its rendering work.
And let's say we might read
some values synchronously
in the script block on the left.
And then cue an
animation frame callback
where we do our Dom right,
[INAUDIBLE] read and then
write, using this raf callback.
For really well-behaved code,
this is actually an awesome way
to give the browser more
control over and insight
into your rendering code.
ADAM ARGYLE: It's like polite.
You're like hey, [INAUDIBLE]
JASON MILLER: Right.
So if you pop open the profiler
on an arbitrary website,
you might find this
technique in play, where
it's not actually panning out.
And the reason for
that is deferring
reads using request animation
frame doesn't really
fix this problem.
It's still going to trigger
forced synchronous layout
inside of the raf callback,
which can sometimes be worse.
ADAM ARGYLE: That's tricky.
JASON MILLER: Yeah,
so we're going
to end up in the same
situation we had before.
So reading properties that
require layout information
before modifying layout
is an important thing
to keep in mind when
interacting with the Dom.
This brings us to our variety
portion of the show, which
we have called lazy wins.
ADAM ARGYLE: All right,
and so earlier we
were talking about smooth, and
it was described as connected,
silky, and asynchronous.
I feel like this crowd is
savvy about the topic of synch
versus asynch and how to be
polite to threads or a thread.
But it's not often enough that
we are considerate of our users
thread.
They're often pressed for
time and resources as well.
So we should do our best to keep
their thread free of locking.
Our first version had
synchronous interactions,
just like the animation here.
It's kind of painful
to watch, right.
You're like, hey--
JASON MILLER: I hope it's done.
ADAM ARGYLE: So here's
a demo of us sending.
It's called rough moves.
You'll like that.
Notice how this one, we have
a new message or thought,
can't be started until the
previous one is finished.
And it's not too bad when
you send one message,
but when you're
sending many, you're
going to be super disruptive.
The user interaction
implementation
was easier for the
engineers because they
could handle the flow
being synchronous about it.
It's sort of like
less work for me.
But we redid it.
And so here's the same thought
process being typed out.
And these messages
are being sent
using asynchronous, almost
sort of known as optimistic
interactions.
And the user is never blocked.
They're free to
express themselves
at the rate at which they
desire and are capable.
And this can increase
the perceived performance
of your application
because it doesn't
appear to stall or think too
hard about certain tasks.
Measuring smoothness
as a UX metric
can be a difficult thing
to quantify or qualify,
but luckily the experts at
Google have devised a fantastic
framework for evaluating
the quality a UX,
and therefore, its
perceived performance.
It is called Heart.
And I wanted to
throw this in there,
because it's the sort
of mix of lazy wins,
because it can help you
measure the impact of your UI
interaction paradigms.
JASON MILLER: Cool.
So one quick way to improve
your application's performance,
is to just find a
browser primitive
that is more efficient
than something
manual you're doing today.
A great example of this
would be position sticky.
The manual implementation
of position sticky
requires querying for
layout information
while you're scrolling,
in the scroll handler.
This is really expensive.
This triggers all the
bad performance problems
we saw before.
Another one would be to
leverage native scrolling,
by swapping out your custom
scroll implementation,
scroll smoothing implementation,
for scroll interview
with behavior smooth.
This is relatively new.
This feature is awesome.
It made building our
chat UI really easy.
The only thing that we had to
do, we were firing at a lot,
so we actually de-balanced it,
using request idle callback.
So we only scroll into view once
the main thread's settled down
and messages have
stopped being fetched.
ADAM ARGYLE: That was
a really slick one too.
Because on an old device--
we had a test where we
hammered messages in there.
We sent like 30 of them over
the span of three seconds.
And an older device
was able to not be
overwhelmed because we
were nice about asking
when to smooth scroll.
JASON MILLER: Right.
ADAM ARGYLE: So the
messages would pour in it
and then smooth
down to the bottom.
JASON MILLER: It'll wait.
ADAM ARGYLE: It'll wait,
and on a nice machine,
they just poured right in,
because it was powerful enough.
It was easy.
JASON MILLER: OK, so
just like scrolling,
panning is a gesture
where we expect
to feel like we're physically
pushing content around
on the screen.
We want to have that
connection between our thumb
and the pixels.
In a well-built custom
panning implementation,
touch input received by the
browser is sent to the page,
and then the JavaScript
input handling code
responds by updating probably
the transform property
on an element, and then that is
rendered by sending that back
to the compositor, which
results in pixels on the screen.
So this actually
works pretty well.
But we can do better.
In browser scrolling,
optimal browser scrolling,
we don't have to wait for
JavaScript event handlers
to complete.
We could just directly translate
that layer on the compositor.
Events will eventually
get sent over to the page,
but in an ideal setup where
passive event listeners are
being used, they could
be fire and forget.
And this is going to get
your shortest time to pixels.
So here's an example
of that manual kind
of panning, the first kind.
It's a simple carousel.
These are my pets by the way.
My wife required
that I said that.
So it's using pointer events.
And it sets a transform
property on the layer.
There's some problems
with this, though.
So we're getting composited
animation, which is good,
but the implementation
is non-trivial.
Especially if you want
to integrate really
well with the browsers own page
scrolling, if you're panning,
and the person's thumb starts
to move more up than left
or right, you really need
to cancel that animation.
ADAM ARGYLE: Get that
uncanny scrolly valley.
JASON MILLER: Yeah, right.
So another option
here would be to use
something called scroll snaps.
So this is really elegant.
Basically, instead of all
the manual implementation,
you just put two CSS
properties on that carousel.
The first is scroll snap type.
We just said we want to do it
in the x-axis and always snap.
And the second is
scroll snap align,
which just tells it to snap to
the beginning of each image.
ADAM ARGYLE: So cool.
JASON MILLER: And what
this looks like is this.
So this requires a lot
less code to implement.
It's still composited,
but this one
doesn't rely on the
main thread at all,
and it feels natural
on each platform.
Because the easing, rather than
being manually implemented,
is just the platform's
native scroll easing.
ADAM ARGYLE: Yeah, you get the
bounce at the end for free.
You get to throw it.
I mean, the whole nine.
JASON MILLER: So to
sum things up, make
sure you're keeping
the browser's rendering
pipeline in mind
when you're animating
and always try to
avoid animating layout.
Sync up your Dom
access so you read
properties that require layout
information before mutating
the Dom and causing layout.
ADAM ARGYLE: And consider
using optimistic interactions,
because they can
sometimes be better
than optimizing
rendering, especially
if you're just getting started.
JASON MILLER: Right.
And finally, take
advantage of places
where you can offload the most
performance critical work,
and rendering to the browser.
If you can leverage something
like scroll snapping
or position sticky to
implement your designs,
that might be the biggest
performance win of all.
ADAM ARGYLE: It's a lazy win.
JASON MILLER: Right, cool.
So thanks everybody.
Thank you.
[MUSIC PLAYING]
