Transcript
This transcript was autogenerated. To make changes, submit a PR.
Hi everyone. Today I'm here to tell you all how to use
less javascript in. It's going to be fun.
So let's get the big question out of the way first. Do I hate
JavaScript? Well, I build Polypane, which is
a browser for developers that's built using web
technologies. So I actually write a ton of
javascript all day, every day. Now this
talk won't be about polypane, so if a browser
specifically built for web developers sounds interesting to you, head over to Polypane
app. Now, with all the JavaScript I write,
you could say that I love JavaScript, but I
also love CSS, and I even love HTML
because it gives me the content editable attribute.
So the reason I love all of these technologies is
something called the rule of least power.
It's one of the core principles of web development, and it
means that you should choose the least powerful language suitable
for a given purpose. Now, on the web, this means preferring HTML
over CSS over JavaScript. Your javascript
can break, it can have an error, it can fail to load,
it takes actual resources to download and run,
and it can exclude keyword users and people using assistive
technologies. CSS and HTML, on the other hand,
are declarative, and that means that you use them
to tell the browser what to do and not how to do it.
Your browser will instead do the heavy lifting for you,
and your end user will have a better experience.
Now of course, the CSS can also filter load, but if your
HTML is solid and semantic, then people can still
access all your content. It really is the foundation.
And in recent times, both browser makers and
specification writers have ported a lot of functionality
to HTML and CSS that a few years ago needed
JavaScript. So that's what we'll be discussing
today. Now, the reason this is important is because
once you learn something on the web, you never have
to learn it again. Once you figured out how
to implement, for example, a slider in JavaScript
that then becomes part of your toolbox. And because it's the
web, that thing will keep working forever,
and there's never a reason for you to learn it again,
even if there are now better ways available in modern browsers.
So the techniques I'll be sharing today are cool,
and that's why I'm showing them. But what I want you to take away
is that just because you know that something needs Javascript,
that doesn't necessarily mean that it's still true in modern
browsers. You can make better websites if you check
every now and then. If that thing you're implementing really
still does need JavaScript. So let's get
started. It's going to be a bit of a grab bag of features,
new and old. Some of these you might know, some of these might be
new to you. There's going to be a couple of live demos, so if
you see me fumble about, just roll with it. Let's get
started. Now we'll start with custom toggles,
and when implementing them we often reach for a JavaScript
solution because that then handles the click events and the states
for us. But we can do the same with an ordinary checkbox and
the checked pseudoclass. That way we can have a
fully interactive toggle using CSS and native
browser APIs, and that means that the accessibility is
preserved. This is the HTML that we're going to use,
and as you can see, it's pretty simple. There's a label
and inside of it there's a checkbox. Now the neat thing
here is that having the input inside the label already gives us
stuff for free because the browser has associated this
input and this label, and now I can click anywhere in the label
to toggle the checkbox. This is something the browser
gives us for free. But of course we can't ship just this
checkbox because it doesn't look like a toggle. So we'll make it look like a
toggle and we can use all of this CSS
for that. Now none of this CSS is super
important except for this first line here,
appearance none. Now what appearance none does
is it tells the browser to stop treating the input
elements like replaced content. Replaced content in
browsers, which are form controls and images
are things that the browser will replace
from your HTML. So as it builds the web page and renders
the web page using your HTML and your CSS, when a
browser encounters replaced content, what it actually does is it reserves
that space in your HTML and then
adds a native form controller, adds an image on top
of it. So that's not really part of your web page.
And that's also the reason why form controls are historically difficult
to style. They're not really part of your
HTML page. Another effect of that is that
before and after pseudo elements don't work for replaced content.
Because before and after pseudo elements are part of your
element and that entire element gets replaced
so they disappear again with appearance none. We can
tell the browser to not replace our form controls.
We can tell the browser essentially,
let me be responsible for the styling of this element.
Don't use a native form control. I'm going to do
the work to make this look the way that it should look.
So that's what the rest of this HTML does. And by using
appearance none. We also get back that before pseudo
element. So we're using the regular input as
the background here, the gray part of the toggle,
and then we're using the before element to add the nib
inside of the toggle. Now we've added
the CSS, but everything is still functional,
so I can click to toggle the checkbox.
Now you'll have to trust me here, but it's really toggled.
Of course we need to make sure that the user also knows that
it's toggled and that's where the checked pseudoclass comes
in. To make that change visible, we use the checked pseudo
class. This will match whenever the input would normally show
the checkbox. So as I click,
the checked pseudo class resolves to true and we can
give our input green background and
move the nip to the right to indicate that the toggle
is currently on. Now there's one last thing
we need to do, and that is accessibility.
So we want to add an outline to the toggle when it's selected
by the keyboard. If you use your mouse, it's very clear which element
you're interacting with because your mouse is right on top of it. But that's
not the case with a keyboard, and we need to provide a
different indicator for keyboard users.
Now you might have used outline none in
the past for your input elements to get rid of that ugly
dotted line,
but that line, even if it was ugly, is important.
Modern browsers ship something called focus visible.
Focus visible only works when you interact
with an element using the keyboard instead of the mouse. So we
can use that to add our outline back in. Now,
as I toggle the checkbox using my mouse,
nothing happens. But as soon as I switch to the spacebar to toggle,
you can see that the outline appears because
it now matches focus visible. Historically,
outline wasn't very stylable, but that too has changed in
modern browsers. For one, as you can see, it follows the
border radius of the element, but we can also
offset it to move it a little away from
the element. Or if you use a negative offset into
the element, and that way we get quite a bit of stylability.
One other thing I want you to do is instead of using outline
none, I want you to use outline color transparent.
The effect will be the same because the outline won't be visible
for outline none because you've hidden it completely and outline
color because it's there, but it's transparent.
This changes, however, when a user uses forced color
mode. What forced color mode does on Windows is it
replaces all the colors on the screen, including the ones in your website,
with a palette that the user chose. That means that
your outline color transparent will be replaced with a
color that the user can see if they use forced color mode,
and that way we can give them additional hints without
having to show that color or that outline to everyone.
Now, I don't have time to go into forced color mode today,
but if you want to learn more, go to polypane app forced
colors, where I wrote about it extensively.
Now, while we're working with forms, have you heard of
data list? So, data list is the browser's
built in way to show a list of match suggestions as a user
types into an input. In other words, it's an autosuggest.
It works like this. You add a data list element to your HTML
with options and you then give it an id.
You will link that id using the list attribute on any
input element. Now, as I write into the
input element, you can see that the data list options
get filtered down to the suggestions matching what
I've already written. And you can also see there's a drop
down that shows you all the options to select.
Now, because it's an auto suggest, you can still type in
any other value, and that will work too. So that's
quite a bit of functionality for a single HTML element that
you would instead ship a very large JavaScript
framework or JavaScript library for.
Similarly, instead of shipping a JavaScript color picker
with like a full canvas renderer and a little
picker et cetera, you can let the browser handle it.
And because the browser has more rights than you as a
web page, they can even offer
more functionality. So now as I open the color picker,
which unfortunately doesn't get picked up, it seems.
No, it unfortunately doesn't get picked up by OBS, which I'm
using to record
this, but it shows a native browser control
with a canvas UI, with an rgb picker, et cetera, but also
with a color dropper icon. And if I click that color dropper icon,
what happens is that I can pick any color on
the screen, including outside of the browser, and have that
be the color a user selected. So that actually gives you
color picking functionality from your entire
screen, and that's just not something your browser
will ever let you as a web page do. Now another
thing that's nice about this input type color is that
it's unstyled, but instead of being white
it's sort of gray. And that's because we've
told the browser that this input actually uses a
dark color scheme. With the CSS color scheme
dark, and that then lets the browser switch
out the form controls from the default
white ones to the dark mode set that it ships
or that the operating system ships. So you can have
native form elements but still adhere
to whatever color scheme your user prefers.
Now if you have a website that uses both dark and
light mode, you can also cater for that using color scheme
dark space light, and then the browser will automatically switch between
them depending on which prefers
color scheme or light or dark mode is active
on the operating system. So that's pretty nice
for just a single line of CSS. Now on
to something a little bigger in page transitions,
when moving from one section of the page to another,
browsers jump by default. And this can be jarring and
disorienting because you no longer know where on the page you are.
It will be much nicer to scroll the user to the new location so
they have a sense of where they are now on the page.
Now in the past we might have used jquery for that,
and in just a few lines of code, plus hundreds
and hundreds of lines of jquery, we could get all the
links that link to another part of the page. And then
when you click it we find where they go to
the page and then we animate HTML to it. So that
was pretty awesome. But you no longer
need these jquery skills because we can achieve the same thing
with just a single line of CSS scroll behavior.
Smooth. Now this tells the browser to always scroll smoothly
when navigating to a fragment identifier, which is an id with
a hash in front of it as part of the URL. Now every
internal link is magically upgraded. Browsers will figure
out how long the animation should take and how fast they should scroll
based on how far they have to scroll and how much cpu power they have
available, et cetera. And that means that the animation is always snappy
and there's never a different part of your page that has to
wait on the main thread to finish this
animation before doing anything else. So as I click
the link, it gently scrolls down to wherever
I link to. Now don't worry,
this is also available in JavaScript in any of
the scroll APIs. So scroll to scroll by, et cetera.
By adding behavior smooth to the object
that you pass the function. So that still saves
you shipping a bunch of Javascript where
you would normally do the scroll animation yourself.
Now there's one important consideration though, and that is accessibility.
Because while for most people, jumping from one part of the page to another part
of the page is the jarring thing for people that have
vestibular disorders, it's the scrolling that actually poses
a problem, as it can make them nauseous and unwell.
Now browsers have a way of catering to these users with the preferred reduced
motion media query, and the way to implement that is
to only set smooth scrolling when the user doesn't
mind motion. So instead of disabling
scroll behavior when the user has prefers reduced motion reduced,
we want to use that as the default case, and then only when the user
indicates that they don't mind more motion with
prefers reduced motion, no preference do we add
the scroll behavior. So now we have smooth scrolling
for the people that want that. No smooth
scrolling for those that don't. And we're not shipping any javascript,
so that's a great start. But we can add more.
So what if we want to scroll to an element, but we want
to keep a little headroom, for example, to make sure that our fixed header doesn't
overlap the title we just scroll to. Well, CSS has
a solution for that called scroll margin. Scroll margin
and scroll padding, which also exists,
work just like regular margin and padding, except they're only applied when
scrolling to can element. So now as I scroll
to the target, it leaves room above
the element to make sure that it doesn't sit behind the header.
Now if I scroll back to top where I haven't set a scroll margin,
you can see that it ends up behind the header and I still have to
scroll down to read the first line again. Now that sure
beats manually subtracting the offset in Javascript before each animation.
Right. Now, as a finishing touch, what if we
want to highlight our target in some way to give it some extra prominence?
For that we could use JavaScript to add a class
to the target as soon as we click a link. But there's
a CSS solution too, the target pseudoclass.
Now when an element matches the fragment which is the
little bit in the URL after the hash,
which happens as a result of clicking can internal link
the target pseudo, CSS will be active and then the transition
will play. So now as I click to target,
we can see that the animation played while the
target was scrolling into view. So now we've built a way
to smoothly scroll to a specific section and highlight
it while keeping some space for the rest of the UI,
and we're doing it all without JavaScript.
What about another staple of JavaScript, scroll related
features? I'm talking about image carousels or
sliders. For that we have the scroll
snap APIs.
With scroll snap we can create sliders that snap to
their parent elements in different ways while accepting scroll input
like normal. So for the parent we have to tell it what the
scroll snap type is. And this takes two values,
an axis, which is x for horizontal or y for
vertical, and a snap type, which is mandatory for always
snapping or proximity. And that means it only
snaps when the edge is close enough. Now what
the edge is is something you define
on the children, on the child elements.
Here you have scroll snap align, and that takes a value
of start, end or center, and it tells you what
to snap to. Now, for left to right languages,
start is left, but this is different in other scripts.
And as you can see, I now scroll.
And as I scroll it follows my
scrolling one to one and it's a
regular native scroll. But as soon as I release the
mouse you can see that it snaps to the edge.
Now by changing the scroll snap align to center, we get
center aligning. So now as I scroll
it will automatically center the element.
Now I want you to notice that all of these cards
have different sizes, and I want you to take a moment to
think how much Javascript you would need to
center this scroll area for randomly
sized cards. And then look back at the screen and see
that we get all of that with a single line of CSS.
Scroll snap align, center. Now there's a
whole range of cool tricks you can do with this, like animations,
overscroll effects, and other things that I don't
have time for. But this presentation by Adam Argal
goes into the nitty gritty of scroll snapping.
So check that out if you want to learn more onto two
UI elements that we often solve with JavaScript,
that we can also just use HTML for an accordion
and a modal. So having an accordion on
your page can help you keep the content organized by showing
the titles of sections and only expanding the full section when a
user clicks on them. Now there's a pair of native HTML elements
that does exactly this, which is the details and summary elements.
All contents except the summary will be hidden by default
until I click the summary and then the rest is
made visible as well. Now of course it's very
common to have the first bit
of the accordion, the first details open,
so that people know that there's more content to see and
that's very easy to do in HTML as well, because you can just add the
open attribute to your details. Now if
you've been writing react or anything else that uses JSX,
you might look at this and think okay, that's great,
but now it's just open forever. Luckily in HTML
that's not the case, because open is just the initial
state and it will update
automatically as we open and close the
dialog or the details element. In terms of
styling, that triangle is a marker pseudo element
and you can use CSS to style it, though it
only supports a subset of CSS like colors and sizes. You can't
move the marker to another place on the page that doesn't
work, but you can, for example, switch out
the triangle with an emoji of your choice,
and then we can use that open attribute because it updates
on the fly and switch out the
design or pick a different emoji like I've done here
so you can style it essentially just the way you want it,
or just the way your designer designed it.
Now a gotcha here is that even though the summary is clickable
like a link or a button, it doesn't get a different cursor
like a link, or it also doesn't look, well,
buttony. So without getting into only
links should have pointer cursors. I think you can
improve the discoverability of your accordions by
adding a hover effect and a pointer cursor to your
summary, so that people know that it's actually something I can
click and clicking it makes something happen on the page.
Now for this next one dialog I am going to cheat
a little, because for now it does need a
tiny bit of JavaScript. The dialog element in
HTML is like a better alert or a confirm or a prompt.
It implements a modal dialog for you, and it takes care of all the things
that matter. It helps keep focus inside
of the dialog so you can't tap out of it.
It shows a backdrop to make sure that the dialogue is what
the user focuses on. It helps
prevent setting that issue so you no longer have to worry about chat widgets
popping up over your dialogues. And it also handles
closing the element for you. And the best thing is that unlike
alert, prompt and confirm, it doesn't block your main javascript thread
because it's a regular HTML element. It's not a
bit of browser UI. So to create a dialog you
use a dialog element, but in the dialog
you add a form with the method dialog.
Now a dialog will be completely hidden from view. And to show
it you can call the show modal function it exposes.
For example, after clicking a button now
as I click the button it calls show modal and
it opens up this dialog.
Now this dialog doesn't come with any
UI that we don't ship ourselves, so there is no close
button for example, and I can click anywhere I want and nothing
happens. The browser expects us to implement this UI
ourselves and that's where that form comes in with the method
dialog. So any submit button in
that form, or any form submission
which you can trigger by a submit button will tell the browser
that it can now close the dialog.
So that's what that form does. And it's
important to note that this dialog sits on top of everything and
with on top of everything, I really mean on top of
everything because this dialog is no longer part
of your HTML page, but it sits on something called the
top layer. And the top layer is a new concept in browsers
that sits on top of your HTML page and you
can promote elements to the top layer.
That means that even the highest set index will still be below
this top layer and you never have set index writing.
So that's how easy it is to implement a custom confirm
dialog. But what if you want to show
multiple options? For example, you have a save UI where
it's safe and cancel. Well you can add multiple
buttons to that dialog with different values and
then listen to the close event. Then when
the close event is called you can get the
chosen value with dialog return value.
So now as I show the modal there are two buttons and depending
on which button I click the return value will
be wrong or correct. Now lastly, you can style
the dialog however you want with rounded corners, drop shadows,
whatever. It's just a regular HTML element.
But you can also show a backdrop that overlays the rest
of the page so it sits between your dialogue and the rest of the
page, for example to dim it to make the dialogue stand
out more. And you can do that with the backdrop pseudo element.
Now the backdrop automatically takes the full size of the viewport
without you needing to do any calculations.
So all you really need to do is add a background image or
other background property. Like for example here I've added
a backdrop filter to blur the page, but you can really do
anything you want here. Now you've probably already heard
of container queries, but if not, imagine if
media queries didn't look at the browser width but at the
width of a parent element. Container queries are
going to replace a ton of custom settings on all of your components.
So container queries provide a built in way of
changing the layout of a component depending on which parent element
they're in and how much space there is available in
that element. So if you use a component based framework,
it will save you passing a prop to change your component depending on the location.
For example, here we have one container,
and depending on if it has a lot of room
in the horizontal direction, in the inline size
or not a lot of room, we flip the flex
direction from having two columns to just a
single column. Now one thing I want to call out here is
that it's the size of the image,
which I've written down as 50 CQW.
You're probably already familiar with viewport units like VH,
VW V min and Vmax that give you a percentage
of the entire screen. Now for container queries, we now
have CQW for width,
CQH for container query height, et cetera that
give you percentages of the container dimensions.
Now, container queries are relatively new, but once it gets more
widespread adoption among developers, it's going to unlock a
whole new way of doing responsive design because you no longer
need to keep track of where on the page you use a component because
the component itself is now responsible for its responsive
design. So as the component moves around the
page as well as on different screen sizes, it can adapt
automatically. All the things I mentioned up to
now are available in browsers today, but I also
wanted to give you a quick overview of some upcoming features.
Each of those could be a full presentation on their own, so I'm
not going to do any of them justice,
but I just want to show you the cool things that are coming,
like quote unquote soon, starting with masonry
layout. So instead of using masonry js or packery
JS, this native masonry implementation will apply
a masonry layout to grids like the Pinterest layout.
It's available in Firefox behind the feature flag, and it's in
Safari's tech preview. And if you want to learn more,
check out this meshing magazine link that is shown on
the screen now and is also in the slides now.
Another very cool upcoming element is select list
because if you've ever implemented your own custom select using javascript,
you basically did a
poor job because it's incredibly hard to do
a good select and take care of all the keyword interactions,
of all the accessibility, of all the different ways
that the browser subtly implements, selects,
but a regular select element is super limited,
so you kind of have to regular select
can't even contain icons or whatever.
So enter select list. This new element
has all the logic and the semantics of a regular
select, but every part is completely
stylable. Now when I say it
implements all the logic and semantics of a regular select,
that means that I can just add a select list element
to the page and have it behave like a
regular select, but I can also go wild
and style it. The select list itself contains
a number of parts that you can style separately using the new
parts pseudo function. So apart from button and
list box you can also style each value, the selected value,
the drop down marker and more. It's all HTML,
so you can style the list box however you want. So for example,
do you want to create a grid layout that just works?
Do you want rounded corners that also just works?
Do you want to create a full fledged emoji picker?
Yeah, go ahead. A date picker also works.
However, it's still very early days for this element and
it's still under development. In fact, it hasn't been
called select list for that long because less
than a month ago it was select menu and they
changed the name. Recently. They're still working on the right
implementation for this element. However, if you want
to play with it, you can try it out in polypane and if you set
the right feature flag in other recent chromium browsers.
The hash selector can also replace a ton of JavaScript
because it allows us for the first time to style elements
based on their relation to other elements.
Now regular CSS selectors will only allow you to style based on
their parent on where they are in
the tree. But with the hash selector you can style
based on child elements or siblings, or entirely different
parts of the dom. In other words,
they allow you to style parent elements based on their children,
which is why they've been called the parent selector. At this moment
it's available in Chrome and Webkit, so it's not quite ready
for regular usage. But it's in Firefox's nightly,
and that means that it's very close to being
available in all browsers. So while there are hundreds
of really really cool examples, I'm going to give you just one.
There is a form where a user can select out of a list of options,
and when they choose other, a new input
field appears where people can fill in their own value.
Now, instead of adding a JavaScript listener to the radio element
and then hiding and showing we can do the same with this CSS
selector. So now as I click other,
what happens is that normally other
text has display none, but then we add this
has part to the selector.
So when other is checked has
starts to match and
then the rest of the CSS selector also matches and we
can style other text and show it. So that's
zero listeners. It's easy to follow CSS and there's
no javascript needed. Now that really scratches
the surface in terms of what has can do. If you want to learn more
and read up on other examples I wrote an article about
hasis and where that you can read over on the polypane
blog at Polypane app where is has
now? As a last example, scroll driven
animations are now available in chromium and
what they do is they let you link animations
in CSS to scroll positions.
Previously, if you wanted to do any sort of animation on scroll
or like a parallax effect, you'd have to use JavaScript,
for example the excellent Greenstock library. But with this
spec scroll driven animations you can do all of that in CSS.
So this example uses no
javascript at all. If you want to learn more
you can go to brem us because that is a
blog with a ton of cool scroll driven examples.
But that's about all the time I have for this particular demo
because I'm at the end of my presentation. So those
are the things you can do in modern browsers that no
longer need JavaScript and some that you'll be able to
use soon. I think we have a great future
ahead of us once these features land in browsers, and instead
of managing things with JavaScript, we can let the browser deal with it
based on the rules we declare with CSS and HTML.
So I hope all of you now like or even love CSS and
HTML a little bit more. All the live demos are of
upcoming features are courtesy CEO of
Polypane Shipping with experimental features turned on. You can
find me on Twitter as at kiliovalkov and you can find Polypane
at Polypane app. Thanks for listening and watching.