How-to: Use the stretch unit in Subform


#1

Stretch units

Some size or spacing values in Subform might look a little unfamiliar. Learn what these values mean---and how to use them to create responsive designs.


Basics

In digital design, sizes are typically specified in pixels, like a box that has a width of 100px. Using pixels is pretty straightforward when you know the exact size you want. Responsive designs, though, have elements that need to grow or shrink based on the size of the screen or browser window.

In Subform, you can specify sizes that respond to the size of their parent by using the stretch unit, s. While 100 is an absolute value, 1s is a relative one. Its exact size can vary, depending on its relationships with other elements.

Imagine you have two boxes, both set to a width of 1s. Instead of being fixed, the boxes now stretch in width to take up all the available space, even as the artboard resizes:

In this case, both boxes are dividing up the available space evenly. What if you wanted the first box to be three times as wide as the second one? Change its width to 3s:

The first box will now always be three times wider than the second box, but they both still stretch out to make sure all of the available space is used up.

Stretch values are based on some simple math. If you add up both of the stretch values in this example, you'd have 3s + 1s = 4s. This means that the available space is divided up into 4 total segments.

The first box's width is 3s, so that accounts for 3/4, or 75%, of the available space. The second box is 1s, so that's 1/4, or 25%, of the available space.

If you add another box to this example, the math changes slightly:

Add up all the stretch values now and you'll have 3s + 1s + 1s = 5s, or 5 total segments. The first box's width is 3s, so that's 3/5, or 60%. The other boxes are 1s, so that's 1/5, or 20% each.

What happens if you only have one box? In that case, it doesn't matter if the width is set to 1s or 22s, because it's the only element dividing up the space. 1/1 or 22/22 always equals 100%.


Stretch vs. percentage

It can seem easier to just use percentage values when you're creating responsive designs. For example, if you wanted one box to be three times as wide as the other, you could just set the widths to 75% and 25%:

That's pretty simple, but what happens if you decide to add some more boxes to the stack?

Since the first two boxes add up to all of the available space (75% + 25% = 100%), there isn't any more room to add in three more boxes. The new boxes overflow the container and aren't visible. You can still see their selection outlines when selected via the tree.

To fix this, you'll have to change the percentage values of your original two boxes to account for the three new ones. Rather than manually do this calculation every time you make a change, you can use stretch values instead. Here's what it looks like when you add three boxes to the original example, using stretch values:

3 + 1 + 1 + 1 + 1 = 7. The first box is 3/7 or 42.85%. The others are 1/7 or 14.28%. Add or remove boxes and Subform will automatically recalculate the widths for you. Much better than doing the math yourself, right?


Minimum & maximum sizes

Stretchable elements often need to have bounds: a minimum and/or maximum size that the element shouldn't be able exceed.

In Subform, you'll sometimes see default values like 1s_20. The first part, 1s, tells the element to stretch. The second part, _20, represents the minimum size. No matter how little space is available for the element, it will never shrink to less than 20:

Maximum sizes work the same way, but instead of using an underscore, they are indicated with a caret:, like 1s^400.

Minimum and maximum values can be specified together. A width of 1s_20^200 means that the element should stretch, but never be smaller than 20 or larger than 200.


Mixing stretch & other units

Elements that stretch can be used in conjunction with fixed size elements.

The leftmost box is set to a fixed width of 200. The right two boxes, both set to 1s, are dividing up the remaining available space: what's left after the 200 is accounted for.

Similarly, stretch elements can also work in conjunction with elements set to percentage sizes:

Here, the leftmost box is set to a percentage with of 50%, it will always take up 50% of its parent element. The right two boxes, both set to 1s, divide up the remaining 50%.

Note: Percentages are always based on the size of the parent element. If the parent is 100, a value of 100% will always equal 100, 50% will always equal 50, and so on. Unlike stretch values, percentage values don't take into account the size or spacing of sibling elements.


How-to: Get started with Subform
#2

#3

Do you mean "...a fixed width of 200." @Ryan ?


#4

Another question from me :slight_smile:

So "1s_20" means 1 stretch but minimum 20 pixels?

I already started to like this stretch idea -but still I need some time to get used to it.


#5

Yep, that's exactly right.

For example, if you have four boxes set to be 1s wide on an artboard that's 60 wide, each box would be 15 wide.

1s + 1s + 1s + 1s = 4s. So each box is 1/4 or 25% of the parent. 25% of 60 pixels is 15 pixels.

Now, if one of those boxes was actually set to 1s_20, Subform knows that you never want that box to be less than 20 pixels wide. Instead of drawing the box as 15, it will ignore the 1s part of the value and use the _20 part, giving the box an effective width of 20 pixels.


#6

Nice, but I'm unable to find this too-special-caracter "^" on my keyboard for max-width...


#7

Shift+6 on your typical QWERTY layout...


#8

@vuntsid Can you tell me what keyboard layout you are using?


#9

Is it possible to set a maximum value without having to specify a minimum value? Using your example, could the width of the element be set to 1s_^200 so that it stretches up to 200 but is able to shrink down to whatever minimum is needed?


#10

Yep, you can add one or both of min and max. Your syntax is a little off, here are some examples:

1s / Stretch, no min or max
1s_20 / Stretch, min of 20
1s^200 / Stretch, max of 200
1s_20^200 / Stretch, min of 20, max of 200


#11

A post was split to a new topic: Sizing input box controls


#13

@vuntsid We’re knee deep in keyboard shortcuts this week, so I looked up the mapping for the ^ character on an Estonian keyboard layout.

You should be able to type it using the right alt key (sometimes labeled as AltGr) and Ä, so alt-Ä or AltGr-Ä.


#14

Thank you for this! This is a really powerful feature for layout. This feels much closer to implementation than any other design tool I’ve used. I have a couple of thoughts on improving the syntax.

Have you considered aligning the stretch unit s with the CSS fraction unit fr? We’re so close to the metal with this layout tool anyway might as go all the way. The CSSWG even admits they should have used fr instead of plain numbers for flex shorthands.

Additionally, you could use the admittedly more verbose minmax function for setting the minimum and maximum sizes. I’m not a huge fan of secret strings and it would also help with the transition to actual implementations. Plus it provides designers with a similar syntax if they decide to jump into the actual CSS.


#15

One or two other people have mentioned this, as well. We have some concerns about it conflating CSS Grid semantics with Subform’s semantics (they’re not a 1:1 match). The closer the syntax, the more you want all the parameters to be the same… and then we’re in an uncanny valley of CSS layout.

The grid layout module spec in particular is really quite complex. It’s awesomely powerful, but the complexity comes at a learnability cost. Based on testing so far, we’ve decided to prioritize simplicity of learning and use over matching the spec(s) feature-for-feature.

That said, improving the discoverability/learnability of min/max (and other available units) is on the todo list. There are some aspects that can be handled in the UI (the syntax, the actual inputs, etc) and there are some layout semantics that likely need to be addressed at the same time.

We’re knocking out some direct manipulation features first—we want to see how far we can get there, before refining the inputs and syntax.