5 min read
Next in trending

Sizing (Web) components

by adding a Trojan horse into your CSS rules.

Sizing (Web) components

by adding a Trojan horse into your CSS rules.


When using a UI Framework, I think it’s quite important that you can easily customize it. This is especially true for Web Frameworks where there isn’t really a “style guide” like on platforms like iOS or Android.

You use a framework because you don’t want to reinvent the wheel, but you still want to give it a twist to make it your own.
Illustration by Nacho Diaz

So when it comes to changing the size of a component, for example making a Slider bigger for touch input, it might get tedious fiddling with all the widths/heights, border-radi.. etc. So how can we make it easier? Well, by sneaking a Trojan horse into your components and use it to control all the size related CSS properties.

What Trojan horse? Good ol’ font-size, hooked up to EM based units.

Let me show you in an example: For every CSS property that has a direct impact on the component’s size, you use the EM unit.

.Component {
width: 5em;
height: 2em;
border-radius: .5em;
border: 1px solid gold;
}

Note that the border is set to 1px since it should stay always like that, unrelated to size changes.

In some cases you need to override the font-size that comes from the UA style sheet. For example when you use a <button> or <input> element. You can add a font-size of 100%, 1em or inherit to make it inherit from its parent. Or use something like normalize.css which already takes care of that.

.Button {
font-size: 100%;

border-radius: .5em;
border: 1px solid gold;
}

With that setup, the resizing can begin. Because EM’s are tightly coupled to the font-size, we now can change all the em units at once by just changing the font-size. This allows you to scale up/down a component and keep all the proportions intact.

Example used: Digit components

Benefits

  • Super easy and quick, no fiddling with width/heights. It even cascades down to a component’s sub-component.
  • It keeps all proportions intact
  • If you need to, you can still override width/height etc. as usual.
  • You’re pretty flexible what to change. It could be on a global level html {…}, only a certain .Component {…}, encapsulated which cascades down .Header {…}, just in a single case .MyComponent {…}, or even inline in the markup.
  • It’s great for setting the size programmatically. For example a user could change them in the settings.

Potential issues

  • Since browsers still snap to whole pixels when using EMs, it could have some rounding errors so that it’s off by 1px. Not a big problem with larger sizes, but you might notice it when going really small.
  • Wrapping your head around how the font-size translates to the real width/height might not be that easy. For example if you set a component to a font-size of 20px, it doesn’t mean its height is also 20px. So if you wanna change it to a specific size, you need to calculate it or just try it out.

FAQ

Here a few questions that came up (post on the side if you have more).

Why not using REMs?

I once did a test to see how that would work. It works, you can scale everything up/down by just changing the root font-size. But there is the problem: It scales everything. If you want finer control, you’re out of luck. By using font-size on a per component level it allows you to size them all individually. Or you can encapsulate it to only certain parts of your App. For example only make all components bigger that are inside the toolbar.

Why not use a CSS preprocessor?

Good question. By using Sass/LESS/Stylus etc. you could nicely abstract the sizing and not be dependent on the font-size. But a simple answer: Maybe you can’t or won’t use a CSS preprocessor. Another and maybe the only real reason: As seen above in the benefits, you can change the font-size dynamically (while the App is running). And the size is not locked into a fixed unit when compiling with a CSS preprocessor.

Why not use transform: scale()?

That wouldn’t affect the surrounding and might overlap other elements that are nearby.


Feedback

I haven’t tested this in the wild, so I’m not sure how it will work out in practice. I guess this technique is quite old and has been used before, so if you have experiences with it, I’m curious if you ran into any issues.

I also submitted a Pull Request to the Digit components. Once (if) it gets approved, you could test it out together with the MontageJS framework.


Update I

Took a quick look at some of the other web frameworks out there:

* Pure uses em’s with default font-size of 100%.
* Foundation uses em’s with default font-size of 1em.
* SUIT uses em’s with default font-size of inherit.
* Topcoat uses rem’s with default font-size in px.
* Bootstrap uses px’s everywhere.

So as far as easier resizing goes, I like how Pure, Foundation and SUIT are doing it.

Update II

Originally I used a default font-size of 16px in the example. But some people in the comments and on twitter pointed out it’s better to just let it inherit from its parent. Initially I was concerned about that and wanted to make the size consistent no matter where you drop a component. But on a second thought, I think they are right. So I changed the post to reflect that.

Interestingly, Pure uses 100% and Foundation 1em and SUIT inherit. Anyone know if there is any difference? Just a matter of taste? I think I prefer 100%, so that’s what I used in the example above.

Update III

On the same topic, Jeremy wrote a good post called Confused About REM and EM? One thing that he suggests that I think is a good idea is using REMs for margin/padding. That way the spacing stays the same when changing the size of components. Might depend on the environment a component is used, like being inside a toolbar where spacing should remain consistant.