[VIDEO GAME MUSIC]
Hey, everyone.
What's up?
It's Rob Dodson.
Welcome to a very special I/O edition of "Polycast."
Today, we're going to talk about styling and theming elements
and how all that just got way better
in the new release of Polymer.
I really think you're going to enjoy this,
so let's check it out.
So I'm going to start with a little story about Polymer 0.5,
because this is an issue that tripped up a lot of folks.
In Polymer 0.5, if you had a component that
had some internal styles and then
you had some more specific CSS styles in the document,
when you took that component over to polyfilled browsers
like Safari or Internet Explorer,
you might see one thing and then in Chrome,
where there's native Shadow DOM, you
would see something different.
In other words, if you had more specific CSS in the document,
it could totally wreck your component.
And this tripped up a lot of beginners who were just getting
started with Polymer and thought perhaps it just
didn't work in all browsers, which is not the case.
It's just it's very, very difficult to properly polyfill
CSS scoping.
So let me give you an example of what this looks like,
just so you can kind of internalize it.
In one of the previous episodes of "Polycast,"
we created this quick alert tag here,
which is basically like a little notification
you might send to a user.
And in that episode, I wanted to style this div down here,
so I used this alert style.
But imagine if, instead of using a class selector here,
if I just styled the div element by itself.
Now, this is totally fine.
This would give us that same example.
The problem is just that it's not very specific.
And so what could happen is my buddy
might be working somewhere else in the site,
totally oblivious to what I'm doing.
And he might create an alert class, as well, just
to target some other element on the page.
And he could style it with some weird fonts and background
colors and what have you.
And then, when I go in the next morning,
I look at my quick alert tag, it's all busted.
It's in Comic Sans.
It looks all messed up.
And for a lot of folks, they saw this
and they just thought, oh, this stuff just doesn't work.
But really, the problem is, you just can't very effectively
polyfill CSS scoping.
It's a pretty tricky thing to do.
But the team decided perhaps there
could be a better alternative to what we currently had.
And so I'm happy to introduce you to the new custom style
tag.
Now, this is a type extension of the style element.
If you recall in a previous episode,
we talked all about type extension elements
and how they work.
And the cool thing about the custom style tag
is it allows you to put your document CSS inside of it
and these styles are basically not going
to be able to affect or mess up any of the components
that you have on your page in polyfilled browsers.
It's a really great way to get lower bound style
scoping in Polymer in the newest release.
I think it's pretty awesome.
So now you know how to protect your elements
from document-level styles in polyfilled browsers,
the next thing I want to show you
is how to actually theme whole element sets using
some cool new techniques.
Now, in last year's I/O, I showed off a couple of ways
that you could theme an element using
some shadow piercing selectors.
So there was ::shadow pseudo element,
which would allow you to pierce one level into the shadow
boundary and in this example, target the slider knob thing
inside of my paper slider.
There was also the deep combinator,
which allows you to pierce infinite levels of shadow
boundaries.
And in this case, I'm targeting all the little ink effects
inside of here by actually hitting the ID.
But there are some problems with ::shadow and /deep/.
First and foremost, they totally break encapsulation.
In those examples, I had to know specific ID names of elements
inside of my web components to target them,
which means if the author moved those things around or changed
the names at any point, my theme would break.
Also, ::shadow and /deep/ kind of screw up some potential
performance gains.
There's this idea that you can improve style recalculation
using Shadow DOM, if it wasn't possible to pierce inside
of it.
But that sort of goes out the window.
And lastly, and I think this is pretty important,
both ::shadow and /deep/ are sort of imprecise tools.
They're kind of like sledgehammers.
In particular, /deep/ is kind of a main offender here,
because it can pierce so many levels and do so many things.
So the team thought that perhaps there
would be a better way to do theming and styling
in the new release of Polymer.
And one of the areas that we've been exploring
is around CSS variables.
So let me show you an example of how this could work.
I've got an element that I've created here called UI message
and it is pretty generic.
It's got a container and then a header and content area
inside of it.
And it's just got some data bindings to these properties
down here that I've created.
Now, I'm going to hide my JavaScript definition,
just so I can focus on the markup up here.
And I want to add some styles.
So I'm going to target the host and give it an inline block
style.
I'm also going to target that container
and set its background color to gray and with a little bit
of padding.
And this is going to give me a very generic-looking sort of UI
message thing.
Now, it's pretty boring, but let's say
someone actually wanted to use this in their project.
And the first thing they wanted to do
was change that header color.
So to do that using CSS variables,
we can actually target the header class,
target the color property, and then give it a variable here.
So I'm saying that the value of UI message header color
should set my color property.
Now, I know that this syntax is pretty funky,
but this is the syntax-- this is the standard syntax for CSS3
variables.
And the cool thing about this is it
allows the author to expose a styling
point to the outside world.
But someone using this component doesn't actually
need to know specifically where this variable is being used.
They just know that there's a header color variable
somewhere that gets applied.
So elsewhere, I'm creating a theme for this component.
I've got a custom style element.
And it's very important that if you're using variables,
that you place them inside of custom style elements,
because it gives Polymer one place to look
for these variable declarations.
I'm going to target the UI message tag,
I'm going to target that variable,
and I'll pass in a value of white.
And what that's going to do is give me a header that is white.
Now, this is really cool, because as a consumer
of the element, I don't need to know anything
about the internals.
I can just set a value for that variable
and then the author can choose to use it however they wish.
But there's a catch here.
If we have to define a variable for every single property
inside of our element, then we're
going to end up with thousands of variables and no time
and we definitely don't want that.
So this is where things actually get kind of interesting.
The Polymer team's been working on an experimental new theming
system that takes advantage of CSS custom properties.
It's experimental, like I said, but totally awesome.
So I want to show you how that works.
Now, one of the things that would be cool
is if we could pass in not just one variable at a time,
but actually pass in a whole bunch of properties
all at once.
There is a concept similar to this in CSS
preprocessors like SaaS or Less called mixins.
And this is something that the Polymer team
has been working with the CSS standards body
to add to the current spec.
It's this idea of taking custom properties that
allow you to pass in whole bags of values all at once.
So let me show you how that works,
because it's pretty cool.
So let's take our header thing here
and instead of just doing this one variable,
I'm going to create a few what are called custom properties.
So I've still got my sort of default styles
that I started with my container,
but now I'm using this syntax to say,
hey, I want to apply a custom property called UI message
container theme.
I'm going to apply a UI message header theme and a content
theme.
And what this allows me to do is go back to my theme file
and replace this one variable with those custom properties.
Notice that there's a semicolon on the end here.
This is important for the syntax and something
that I often leave off.
And now, I can actually pass in just whole bags of properties
that I would like to override the default
styles in that element.
Now, I borrowed these styles from the Symantic UI Library
just to show that you can go hog wild here.
You can pass in as much CSS as you could possibly imagine.
And what this is going to do is take
our totally boring, vanilla UI message
and turn it into something that's
actually much more pleasant.
So over in my Code Editor, I've got a Bower JSON file fired up
and I am in my dependencies listing Polymer 0.9 RC.1 as one
of my dependencies.
Now, it's been a few weeks since this has been recorded,
so you're probably safe at this point
to just go ahead and replace this with the actual 0.9.0 tag.
And once you've got that in place, you can install it.
It'll pull down the latest version of Polymer.
And over in my UI message file, this
is the same element that I was showing over in the slides.
And the first thing I'm going to do
is create a little header variable.
And that's just going to allow me
to change the color of this header down here.
I can create a My Theme HTML file and add a custom style
element to that.
I can create a My Theme HTML file and add a custom style
element to that.
And inside of here, I'm going to target the UI message element
and I'll pass in a value for that variable.
And now when I'm ready to use these guys,
I can just import the definition for my UI message
and import the theme that I just created.
And then, I can just drop the UI message tag on the page
and that theme is going to be applied to it.
So if I hop over to Chrome, we'll see my message
and we see that updated header color.
Now, let's try to do this with some custom properties.
So we'll go back to our element definition.
And instead of just the one variable,
I'm going to use the @ apply syntax
to create custom properties for container theme, header
theme, and content theme.
And then, back in My Theme HTML file,
I can replace this one variable with those custom properties.
Again, note the semicolons here.
I always forget to include those.
And then, I'll just Paste in a bunch of CSS styles.
Again, these are the styles that I borrowed from Symantec UI,
but you can see that-- pass in whatever you want,
box shadow and color and opacity, what have you.
All of these are going to be applied
and they're going to override the defaults that
are in that UI message element.
So you go back to Chrome and Refresh the page.
And now, things are looking much nicer.
Now, this is a huge improvement over where
we were with theming and styling in previous versions
of Polymer.
And personally, I'm just really excited to see
what you all build with it.
That's it for today.
Be sure to click little subscribe button.
Leave me questions down in the comments.
As always, thank you so much for watching
and I'll see you next time.
[VIDEO GAME MUSIC]
Hey there, Polycasters, Rob here.
Q&A time-- a Lucas Ciruzzi sends in three questions.
The first is, is the underscore notation
mandatory when you're defining an observer in your properties
object?
It's a good question, Lucas.
The underscore is actually not mandatory.
That's just something that we include
to signify that a function is private
and that we don't want the outside world calling
that method.
But by no means is it required.
It's just sort of a stylistic thing.
Second question-- how would you implement an attribute change
listener on a native web component, so something that
isn't using Polymer or anything like that, just
a vanilla custom element?
To do that, you can use the attribute change callback.
That is a lifecycle callback that every custom element has.
And that callback is going to give you
three arguments, the attribute name that changed,
the old value, and the new value.
Last question is, how does the read-only property
affect a custom element when I change that protected
property from the outside using something like set attribute?
In that case, what you're going to see
is the DOM element is going to update,
but the property inside of it is going to remain the same.
So if you have a binding to that property or something
like that, that binding is going to stay exactly as it was.
So great questions, Lucas.
Thank you for sending those in.
If you have questions, please leave them for us
down in the comments.
We'll try to answer them all-- maybe feature you on the show
and give you some swag.
As always, thanks so much for watching
and I'll see you next time.