Search code examples
framerjs

FramerJS layer with dynamic height (importing layers from sketch)


At a high level, we’re trying to understand the best way for Framer to render a layer with a dynamic height.

We’re importing our designs into Framer from Sketch. We’re building a simple question and answer page. Each page has 1 question and the user will work through 20 questions, one question page after another.

Here’s a rough version of the design: page design with dynamic height sections

The header, footer, and prompt are always the same height. The question and answers section change based on the question and answers we want to render.

We see three possible solutions:

  1. Create 20 different sketch templates/cards, each one representing a rendering of a different question (for example card1 would be listing question1 with answers1). When the first question is answered we render the next sketch card to show question2 with answers2. To be clear, I’m suggesting that each card contains everything: the header, question, prompt, answers, and footer.
  2. Have 1 sketch template/card that is the full rendering of the header, question1, prompt, answers1, and footer. Have a bunch of mini template/card layers that are also imported into Framer. There would be a layer for each question and a layer for each set of answers. When Framer tries to load question 2, it would load the full rendering of question1 with answers1 (and header,footer,etc), and swap the layer containing question1 with question2, and swap the layer containing answers1 with answers2. There’s a problem, question2 is smaller than question1, so now there’s a large white-space between the questions and prompt layer. So, programmatically go through the layers in Framer and properly align them using align.
  3. Have several small layers (header, question1, question2, …, question20, prompt, answer1,...,answer20, footer) and using Framer build the page by adding each layer one after another. Also write CSS to match the design pixel perfect.

Problems: Our issue with #2 is there’s a lot of upfront work to reposition ‘all the layers’. As far as we can tell, Framer copies all the sketch layers and positions them based on their absolute position with x and y coordinates. Since all layers are positioned absolutely it would have to go through each layer and re-apply align depending on how they’re positioning in reference to eachother. This really seems cludgey and as far as we can tell there’s no helper function in Framer to help achieve this. Sure, we can write something that works through the parent tree and re-aligns siblings, but this feels way too error prone and not in the spirit of building prototypes with Framer.

Our issue with #3 is this just feels like building the website and this doesn’t feel like prototyping. There’s a lot of pixel pushing since we can’t directly import the pixel-perfect sketch design. We want to quickly update the prototype when designs change. We expect the design will change frequently because we’re running a lot of user tests and getting great feedback. This method would have me spend considerable amounts of time churning each time a design is changed to ‘redesign’ my prototype.

Thoughts? Are we missing something obvious? Thanks for reading and thanks for your time.


Solution

  • We ended up solving this with approach #2. In summary: swap the layer and reposition all the layers below, also go through all the parents and resize as necessary (for example if the new layer is smaller than the old layer we're swapping with we'd need to shrink the parent layers by the difference).

    The general approach was:

    • Use TextLayer to create a new layer with the new question text
    • Measure the size difference between the original sketch question text layer and our new TextLayer
    • Resize the parent layers based on the difference calculated in #2
    • Remove the original sketch layer
    • Insert the new TextLayer in the same x and y coordinates as the original sketch layer

    Code gist: https://gist.github.com/MrNickBreen/5c2bed427feb8c701d5b6b1fbea11cb4

    Special thanks to Niels for the suggestion which helped me figure this out.