Controls of the Week: HorizontalPanels and VerticalPanels for basic CSS3 flexbox layouts today
March 19, 2012
It’s really, really common in UI to place a panel on one or both sides of a main content area, on the left and right or on the top and bottom:
The CSS Flexible Box Layout Module, a.k.a. “flexbox”, is intended to address layouts like the ones above. For a general introduction to flexbox layout, see CSS3 Flexible Box Layout Explained. This feature hasn’t gotten as much use as it could; as shown on When can I use, it’s not supported on the current (as of this writing) versions of Internet Explorer. Moreover, the flexbox spec changed a while back; only Chrome supports the final spec.
The flexbox layout module can handle many layouts and needs beyond the two shown above, but the two above are common enough that they represent a good starting point.
- Each layout has a stretchable main content panel.
- A horizontal layout can have a panel on the left, right, or both. Similarly, a vertical layout can have a panel on the top, bottom, or both.
- The control needs to be able to handle arbitrary content in the panels. If the content changes, the layout should adjust in response.
- Each layout comes in two forms: one with a constrained height (in which the content is generally scrollable) and one with no height constraint (i.e., grows as tall as necessary). In practice, the unconstrained form comes up much more often in the horizontal layout. (In the vertical case, the unconstrained form is really just a stack of divs, so no special layout is necessary. However, controls such as TabSet come in both height-constrained and unconstrained forms, and it’d be nice to be able to position the tabs using a vertical layout in either case. So even the unconstrained vertical layout comes up in some, albeit rare, situations.)
HorizontalPanels and VerticalPanels controls
I’ve posted HorizontalPanels and VerticalPanels controls that address the layouts described above. They can each handle up to one panel on either side of the content area.
As browser implementations come up to snuff, the components can be updated to take advantage of native CSS flexbox support (including, eventually, the new syntax). You can build a UI using these layout components that will work today (as far back as IE 8), knowing that your UI will capitalize on flexbox support as it become more available.
The HorizontalPanels and VerticalPanels controls derive from a base class called SimpleFlexBox, which sniffs out support for display: box and its variants. In testing, it seemed only WebKit’s flexbox implementation is worth using today. As of this writing, the Mozilla implementation seems too flaky overall to depend upon. And even on WebKit, I hit what looks like a bug preventing the use of automatic scroll bars in a height-constrained flexbox panel with horizontal orientation, which is a pretty common use case. This means HorizontalPanels can’t always use flexbox layout, even on Chrome. And while I’m interested in testing these controls on IE 10, Microsoft has tied the IE 10 preview to the Windows 8 preview, and I’ve already wasted too much of my life fiddling with Windows betas to care about trying Windows 8 before it’s ready. (Weren’t all the tying-IE-to-Windows shenanigans supposed to end with the DOJ consent decree?)
I did hit a weird cross-browser issue in IE9: when I view the VerticalPanels demo in IE9 under Large Fonts, the border for the main content area doesn't quite touch the border for the bottom panel. This can happen in IE9 because elements that size to text content can end up with fractional pixel heights. Since IE9 doesn't support flexbox, in the constrained height scenario SimpleFlexBox needs to examine the height of the top and bottom panels so it can adjust the metrics on the main content area. SimpleFlexBox requires on jQuery's height() function to do this, which turns out to always report integral pixel values. Under certain cases, then, it's possible to end up with a sub-pixel gap between the main content area and the panels — and the gap can become visible if the browser or display is scaling things up (as with Large Fonts). IE9 can report fractional heights via window.getComputedStyle(), but it doesn't seem worth this trouble just to support IE9 under various display edge cases. IE8 reports integral heights, and IE10 should support flexbox, leaving only IE9 with this issue. A simple workaround would be to avoid setting interior borders on the main content area if you're also setting them on the panels.
In any event, it’s nice to be able to wrap up a bunch of browser-dependent styling or code into a reusable component that can handle the details so the component user doesn’t have to. And, IMO, I’m not altogether sure that universal flexbox support will actually eliminate all need for controls like HorizontalPanels or VerticalPanels. Use of those controls in your code can arguably make it easier to clearly state your intent. While the CSS flexbox spec is very, um, flexible, the resulting CSS is not particularly easy to read. I preferred the Dock=“Left” syntax of Microsoft’s DockPanel control to the flexbox syntax, and have tried to mirror the former in designing the API for HorizontalPanels and VerticalPanels. Compare: to set the content of the left panel of HorizontalPanels control, you can stuff that content into a property called “left”. To achieve the same result in CSS3, you omit the “box-flex:” property to ensure the panel won’t stretch. I think the former is easier to read and maintain. Even once everyone has a flexbox-capable browser, these controls might still find use as more legible wrappers around the underlying CSS.