In November 2023, we shipped a major upgrade to Smart Layout and in this series, we’re taking a look behind the scenes of how we made it happen. In the first post, the team set the scene and explained how we planned our work. In this post, they explain how they went about fixing issues and improving Smart Layout’s reliability and predictability.
As we laid out our plan to free Smart Layout from Symbols and make it available everywhere, we knew we had to make it… well, smarter.
For a long time, we’ve heard from customers — and experienced ourselves — that making a change to a Symbol with Smart Layout could cause something to move when it shouldn’t, or the opposite. Worse still, it could happen inconsistently.
If we attempted to make Smart Layout available everywhere first, and tackle these problems after, we’d only expand where they could happen and expose them to even more people. It would also make them much harder to fix later on.
Creating a larger surface area for problems, with more designs and people affected by them (as well as any further changes we made), would frustrate and disappoint customers who were looking forward to Smart Layout improvements. This was unacceptable to us, even if it meant delaying those improvements a little longer.
Identifying the issues
But what exactly were these problems? How many distinct ones did we have? When did they happen? What caused them? And could we spot any shared root causes underneath them all? This called for some detective work.
We started collecting many of the issues we’d accumulated and poured over them, one-by-one. In each case, we looked at sample documents from customers and broke them down to their bare essentials, identifying factors and steps that led to unexpected issues.
We started this work as a larger group; with colleagues from our Support team, as well as our co-CEO (Smart Layout’s original lead developer), and everyone in the project team. This helped us build shared language and understanding through every role in product development. We then continued as a smaller group, worked through 50+ issues, organizing them by severity and problem area.
At the end of a long and thorough investigation, we found a few problem areas to focus on:
- Inconsistent rules between different directions. As we mentioned in our first post, Smart Layout looks at how layers overlap along the layout direction. With this, a design with a left-to-right layout should work exactly the same as a mirror version with a right-to-left layout. However, this wasn’t always the case, which made the feature less dependable.
- Nested layouts along the same axis. Designers can nest Smart Layout containers inside each other, and Smart Layout allows us to place layers freely in relation to each other. This results in scenarios where multiple Smart Layout containers appear side by side, but with different directions along the same layout axis. In these cases, we didn’t always respect these different directions.
- Cleaning up space when removing layers. Removing layers from a layout presents an additional challenge. We not only have to account for space the layer itself took up, but also the space around it, otherwise the design will be left with excessive space and look wrong. While this did happen, it didn’t quite match expectations.
Beyond these key areas, we also had a grab bag of individual issues, some of which we identified as being important enough to fix on their own.
Setting up a safety net
Smart Layout has been around for over three years, finding a home in countless documents and Libraries used by large teams. This, combined with its freeform arrangement characteristics, meant we couldn’t just start making changes — even if they would be for the better. The risk of causing large-scale unintended side-effects was just too high.
To make sure we took two steps forward and no steps back, we wrote lots of more performant and easier to debug unit tests. This guaranteed that we wouldn’t inadvertently undo any current correct expectations. With these in place, as we implemented changes that made Smart Layout more consistent, predictable and easier to understand, we could keep everything compatible with how designers might’ve set it up.
As we fixed each individual issue, we not only fed the original scenario itself into the testing suite, but also variants for different layout directions, as well as related and subtly different layouts. At the end of the project we ended up with more than 400 additional unit tests for Smart Layout.
Diving into the detail
With our testing suite giving us a safety net for changes, we began tackling our key problem areas one-by-one. We started with the problems of consistent behavior across directions and nested layouts with different directions. These went hand-in-hand and meant we could tackle space cleanup — a much more isolated problem — later.
Problem area 1: Creating layout consistency, regardless of direction
The logic of Smart Layout doesn’t separately deal with left/right or top/bottom, but rather whether a layer is ahead or behind on any given layout direction. In other words, you’d expect a left-to-right layout to work the same way as a mirrored version with a right-to-left layout.
In a left-to-right layout, a layer overlapping the left edge (the leading edge) of the layer being changed would stay as-is. If it overlapped the right edge (the trailing edge) of the layer being changed, Smart Layout would resize it. You’d expect this to be the opposite for a right-to-left layout, but it wasn’t. In a right-to-left layout, we were always applying the rules based on whether something was to the left/right and totally ignoring that the layout direction was in reverse.
This was one of the areas where we had to weigh up breaking layouts in existing documents versus introducing a more consistent and predictable behavior. We went for the latter. Now, we always resize layers overlapping the trailing edge and always move layers after the trailing edge, according to the layout direction.
Problem area 2: Improving layout of layers overlapping along the layout axis
Our second area of focus was layouts with multiple layers overlapping along the same layout direction. Previously with Smart Layout, it wasn’t possible to have horizontally centered or right-to-left layouts inside another horizontal layout. This was a limitation that many customers experienced, preventing a whole range of possibilities with Smart Layout — and we knew we wanted to fix it.
Take a look at the example below to see what we mean. In this example, we have a table of columns with an overall horizontally centered layout. In the right column, we have a cell with a left-to-right layout. This works fine. In the center column we have a cell with a right-to-left layout for numbers, and in the right column, a cell with a centered layout for ratings.
Making this example work properly meant we had to improve Smart Layout’s logic to calculate and adjust the position of individual layers within these nested layouts to not only make nested layouts like this possible, but also make sure everything ended up where you’d expect.
Problem area 3a: Eliminating spaces between hidden layers
Our next problem area to solve was what happens when you hide a nested Symbol instance within a layout — and specifically, how we eliminate the space between layers when you do this. In our previous implementation, when you hid a layer, we used the space after that layer along the layout direction to calculate the position and dimension changes of other layers. This resulted in two issues:
- When you the hid last layer along the layout axis, there is no space after it along the layout direction to work with. And if the layers inside the Symbol had padding to the symbol’s bounds, when you hid the layer at the trailing end of a Symbol, we’d clear any space after it, but this would often be padding that you’d want to keep.
- The behavior was different for hiding the first and last layer in a stack-like layout, so changing the layout direction resulted in a different behavior. This was not desirable.
In a stack-like layout, with spacing between each layer, one solution could be to remove the space ahead of the layer you’re removing. However, this approach becomes problematic when you remove two or more layers. In this case, you’d need to remove the space ahead of both layers, to keep spacing consistent. This behavior isn’t easy for users to predict, especially once you take different layout directions into account.
Instead, we tried removing the space(s) which were smallest in size. It turned out that this was not only quite simple to implement, but also had the very interesting side effect of preserving the relative distances of the remaining layers! As bonus, this also preserves the Gestalt principle of proximity.
The example below shows this in action. Here we have a toolbar with three sections of items. Each section has a large space between them and smaller spaces between the items within it. In our previous iteration, the space we removed could be between the items or outside of them (depending on the item you hid), which would change the toolbar’s appearance in an unpredictable way.
Now, by removing the smallest adjacent space(s), hiding a single item in the toolbar group still keeps the grouping intact and removing all items of a group still keeps the adjacent groups separated. Better still, this approach has a predictable behavior regardless of the layout direction!
Problem area 3b: Preserving space when hiding layers
We were happy with our new approach to cleaning up excess space, but we also heard from customers whose layouts relied on removing a specific space — and not always the one our new setup removed. Dealing with this request presented a challenge for Smart Layout’s core principles.
As we outlined in our first post, a core principle of Smart Layout is to have minimal setup, and instead infer intent from the way a designer has set up their layout. When additional controls are necessary, we prefer options people already know, such as the Pin to Edge and Fix Size constraints. These are already available to any layer within a group, but also work in the context of Smart Layout.
We know the solution to the problem of preserving a specific space was finding some way to choose if a hidden layer preserves its space or not. We looked for a good heuristic to determine when to keep a hidden layer’s space, and for existing options that designers could use to set this, but nothing worked well for us. Ultimately, we decided to add a new explicit Smart Layout option — a checkbox labeled “Preserve space when hidden” — available to Symbols inside Symbol instances.
While we believe in having strong principles driving our product design philosophy, it’s important to take a non-dogmatic approach and remain flexible when that philosophy begins to impose limitations.
Shipping our improvements
While our improved and extended testing suite gave us confidence that we weren’t regressing in any way, we wanted to make sure our improvements aligned with designers’ expectations — starting with our own design team.
We placed our work in each area behind a corresponding feature flag in our nightly Sketch builds, which our designers use in their day-to-day work. With this, we could expose our changes and assess their impact. When problems occurred, we could toggle feature flags to easily find the culprit area — and give our designers an escape hatch while we fixed it.
Even with all of these safety nets in place, Smart Layout’s ability to work with any arrangement meant we couldn’t possibly account for the astounding variety of scenarios our customers could put it through. We knew we wanted to get this update into the hands of as many people as possible, but just like we did internally, we wanted to offer an escape hatch for anyone experiencing issues.
Our first ideas was to ship these updates in Beta releases only, but our Betas require effort to opt-in. Instead, we added a new Experimental Features settings panel to v95 of the Mac app. This allowed designers to try out work-in-progress features, share their feedback via the community forum, and switch them off whenever they needed to. We released our work under the Better Smart Layout Reliability feature option and, knowing that it was easy to switch off at any time, enabled it by default for maximum exposure.
In the end, negative feedback on this update was minimal, with very few regressions, which is exactly what we’d hoped for. Now, with the foundations of Smart Layout in a much better place, we could finally crack on with the final and most-anticipated stage of this project: taking Smart Layout out of Symbols, and bringing it to Groups and Artboards — but that’s for our next post.