Rendering data for pie charts, donut charts, pie menus, and general arcs is not as intuitive as rendering flex or grid layouts of the same information. Solutions for this often rely on SVG, JS, and are usually bespoke setups which doesn’t mesh well with flexible layouts. In this post I’m suggesting that minimal additions to the flex and grid layouts can create a powerful new set of layouts for developers.
Below on the left is a normal flex-direction: column
. On the right is a similar layout with the addition of flex-radial: start; flex-radius: 50px 100px;
display: flex;
/* all the normal flex styles are the same, like flex-direction, flex-wrap, align-items, justify-content, etc */
flex-radial: start; /* or end. Defines where the radius is on the left, right, top, or bottom relative to the flex-direction. For row, start and end correspond to the top and bottom respectively. For column, start and end correspond to left and right respectively. */
flex-angle: 0deg 360deg; /* "start end" is one format. More complex formats for later would be the ability to skip angular areas. So 315deg 45deg, 135deg 225deg would fit item first between -45 to 45 degrees then spill-over to 135 to 225 degrees effectively only having items on the left and right sides. */
flex-radius: 0px auto; /* or 1fr. These define the inner and outer radius. Using a flex value would allow say a pie chart to automatically resize to its container elegantly */
box-sizing: inner-radius; /* or outer-radius (or content-box or border-box) */
box-items: radial; /* or none. Controls how items rotate around the center point. Radial means their box model rotates and takes the shape of a sector. If none is supplied then the box model stays axis aligned positioned around its center. Using none can cause items to overlap. */
text-orientation: first-line; /* or middle-line, last-line, per-line, or existing values. Controls how the baseline is defined inside of the box model. All of the options except the existing options align the baseline(s) pointing toward the center. If none is used the text keeps its orientation. */
For children of the layout these options can be overridden:
text-orientation: first-line; /* or middle-line, last-line, per-line, or existing values. Only when writing-mode: horizontal-tb */
Two examples of the text-orientation are below. One could imagine a webpage that rotates items into view with a simple transform animation.
Margin and padding are handled differently based on the above box-items properties. I haven’t worked out what changes would be required. In theory with say a negative left margin (and border-radius) you could have something that looks like:
In that example the text-orientation is set to the default “mixed”.
Angle Units
Items inside of the layout would have the option to use angle units for their lengths along the main-axis:
So if you used flex-direction: column
you could then define the height of an element as height: 20deg
. These are also valid units for the flex-basis
. This would allow one to easily divide sectors up by specific degree increments. (In general if you want the items to be equal size though you can just use 1fr).
Grid
Everything defined above for flex would work the same for grid except the properties are all prefixed with grid-
instead of flex-
.
Animation
Since all of these properties are CSS styles they can be animated to achieve a wide variety of effects. Simple things like pie menus that grow when you click a button would be trivial. Or by animating the flex-angle on a pie chart from 0deg 0deg to 0deg 360deg you would see a radial swipe.
Accessibility
- I’m not very familiar with this topic, or it’s requirements so I could be totally off base. I think having this layout could potentially be more accessible than alternatives people usually do with complex CSS, SVG, and JavaScript-focused solutions to manually position elements. (Some of which involve absolute positioned items obfuscating the DOM). Since it’s a layout and doesn’t touch the underlying DOM it means simply disabling radius with no other changes unwraps the layout and can be readable. Turning a pie-chart into a stacked bar chart(? I don’t know if that’s what those are called).
Possible issues:
- Doesn’t support spiral designs. So imagine you have
flex-wrap: wrap
with a hundred items of fixed size. With this system you’d simply see rings of items. Could add a radial function to allow spirals. Maybe for later. - Text overflow is complicated by having to clip with a sector rather than a simple box. The main use case I see is having short snippets or labels being used, but it’s possible people put longer paragraphs.
- Implementation complexity. Most layouts and rendering deal with boxes. A radius requires that the background, borders, box-shadow and tons of other things have variants to render arc versions. In this idea alone one could create a sector and apply a border-radius which generates geometry that doesn’t currently exist. Granted it’s just a vector object and Skia can definitely render it, but it’s a lot of changes for toggling just one CSS property.
Other applications:
- A speedometer with speed markers could be created easily with this.
- A shield/armor/health indicator in a game that follows an arc. A radial-grid could render stacked shield on top of the armor arcs. (Could render and animate a rainbow of colors also if that’s easier to visualize).
- A radial build menu in an RTS. A radial-grid could create a tiered menu.
- A commo rose
Proposal
I am way outside of my element to be able to write a layout proposal. If someone is interested in this idea feel free to turn it into a real proposal. I’ve created this post ad-hoc (like the property names) with initial ideas to get a discussion going since it’s something I’d actively use if implemented. (I searched for a bit and couldn’t find anything similar suggested).
Conclusion
Anyone have any use cases I’m missing or added properties that would make this more powerful? Any criticism toward this approach would be appreciated also. I believe my approach of integrating it into the existing flex and grid layouts is ideal, but I could be wrong. In my thinking it would work with subgrid also, but I digress as that gets into edge cases.