Scaling Text Made Easy: Framer’s Fit Text Feature

We launched a new feature called “Fit Text,” which allows you to create bold headings that scale to fit any container. This feature supports multiple lines, inline formatting, and min and max widths, all while maintaining high performance. In this post I explain how we pulled this off.

The Challenge: No Native CSS Solution

I started by exploring existing libraries, but they all had a flaw: they needed to measure the text that needed to stretch before rendering. This is a deal-breaker for us, since Framer sites are statically generated and need to render perfectly in any browser before JavaScript runs. Next, I tried font-size: 100vw, which works great if the text fills the screen. However, it becomes challenging if you want the text to fill an arbitrary container. To do this, you need to build a complex CSS calc expression that represents the size of all ancestors expressed as percentages of the total vw. Although this is doable (and something that Framer already does to optimise image quality) it would make it tough to create a component that contained text with a vw size, since it would be hard to know the ancestors size inside the isolated component code.

The Solution: SVG with viewBox and foreignObject

I discovered that an SVG with a viewBox and support for HTML in SVG via a foreignObject element, could provide a scaling effect. This trick requires knowing the exact bounding box of the text and committing it to the viewBox, then rendering the text inside the SVG in a foreignObject. The foreignObject means that screen readers and SEO have no problem finding the text inside. The caveat is that the viewBox of the SVG needs to be updated whenever the size of the text changes, and it needs to kept in sync; otherwise, the text will become cut off or uncentered. This probably rules out this solution for most custom sites. It's simply not feasible to determine this viewBox any time any text is edited, or its properties that effect its size change.

The Automation: Framer to the Rescue

Luckily for us, Framer can automate this process, removing the hassle of having to manually update a viewBox anytime the text changes. Whenever you set text to “Fit”, Framer measures the text at its current font-size, gets the bounding box, saves it, and renders an SVG around your text with a viewBox. Every time you edit the text, Framer repeats that process to ensure the viewBox stays relative to the text. Framer can even support a seamless editing experience by converting the text size back to pixels whenever you open it in the text editor by doing some basic math based on its current width. When you finish editing, Framer puts the viewBox back, and it’s effortlessly scaling again without any performance impact on the canvas.

The Result: Butter Smooth Resizing

When you deploy your site, the viewBox is already calculated, so Framer can statically generate the site, and the text will render at the exact right size even before JavaScript is loaded. This results in no flashes, resizing, or fade-ins, and buttery smooth resizing.

The Future: Container Queries

In the future, we plan to switch to container queries once they are fully supported by the browsers that Framer supports. You can use the cqw unit the same way you can use a vw unit, but cqw is relative to the container. This would work for components, since it removes the need for a complex CSS calc statement.

Fit Text is an excellent example of how Framer can abstract engineering work that would be hard to implement on a case-by-case basis and instead lets you focus on shipping fantastic sites. It’s exciting to see what people will build with this new feature.

The Challenge: No Native CSS Solution

I started by exploring existing libraries, but they all had a flaw: they needed to measure the text that needed to stretch before rendering. This is a deal-breaker for us, since Framer sites are statically generated and need to render perfectly in any browser before JavaScript runs. Next, I tried font-size: 100vw, which works great if the text fills the screen. However, it becomes challenging if you want the text to fill an arbitrary container. To do this, you need to build a complex CSS calc expression that represents the size of all ancestors expressed as percentages of the total vw. Although this is doable (and something that Framer already does to optimise image quality) it would make it tough to create a component that contained text with a vw size, since it would be hard to know the ancestors size inside the isolated component code.

The Solution: SVG with viewBox and foreignObject

I discovered that an SVG with a viewBox and support for HTML in SVG via a foreignObject element, could provide a scaling effect. This trick requires knowing the exact bounding box of the text and committing it to the viewBox, then rendering the text inside the SVG in a foreignObject. The foreignObject means that screen readers and SEO have no problem finding the text inside. The caveat is that the viewBox of the SVG needs to be updated whenever the size of the text changes, and it needs to kept in sync; otherwise, the text will become cut off or uncentered. This probably rules out this solution for most custom sites. It's simply not feasible to determine this viewBox any time any text is edited, or its properties that effect its size change.

The Automation: Framer to the Rescue

Luckily for us, Framer can automate this process, removing the hassle of having to manually update a viewBox anytime the text changes. Whenever you set text to “Fit”, Framer measures the text at its current font-size, gets the bounding box, saves it, and renders an SVG around your text with a viewBox. Every time you edit the text, Framer repeats that process to ensure the viewBox stays relative to the text. Framer can even support a seamless editing experience by converting the text size back to pixels whenever you open it in the text editor by doing some basic math based on its current width. When you finish editing, Framer puts the viewBox back, and it’s effortlessly scaling again without any performance impact on the canvas.

The Result: Butter Smooth Resizing

When you deploy your site, the viewBox is already calculated, so Framer can statically generate the site, and the text will render at the exact right size even before JavaScript is loaded. This results in no flashes, resizing, or fade-ins, and buttery smooth resizing.

The Future: Container Queries

In the future, we plan to switch to container queries once they are fully supported by the browsers that Framer supports. You can use the cqw unit the same way you can use a vw unit, but cqw is relative to the container. This would work for components, since it removes the need for a complex CSS calc statement.

Fit Text is an excellent example of how Framer can abstract engineering work that would be hard to implement on a case-by-case basis and instead lets you focus on shipping fantastic sites. It’s exciting to see what people will build with this new feature.

The Challenge: No Native CSS Solution

I started by exploring existing libraries, but they all had a flaw: they needed to measure the text that needed to stretch before rendering. This is a deal-breaker for us, since Framer sites are statically generated and need to render perfectly in any browser before JavaScript runs. Next, I tried font-size: 100vw, which works great if the text fills the screen. However, it becomes challenging if you want the text to fill an arbitrary container. To do this, you need to build a complex CSS calc expression that represents the size of all ancestors expressed as percentages of the total vw. Although this is doable (and something that Framer already does to optimise image quality) it would make it tough to create a component that contained text with a vw size, since it would be hard to know the ancestors size inside the isolated component code.

The Solution: SVG with viewBox and foreignObject

I discovered that an SVG with a viewBox and support for HTML in SVG via a foreignObject element, could provide a scaling effect. This trick requires knowing the exact bounding box of the text and committing it to the viewBox, then rendering the text inside the SVG in a foreignObject. The foreignObject means that screen readers and SEO have no problem finding the text inside. The caveat is that the viewBox of the SVG needs to be updated whenever the size of the text changes, and it needs to kept in sync; otherwise, the text will become cut off or uncentered. This probably rules out this solution for most custom sites. It's simply not feasible to determine this viewBox any time any text is edited, or its properties that effect its size change.

The Automation: Framer to the Rescue

Luckily for us, Framer can automate this process, removing the hassle of having to manually update a viewBox anytime the text changes. Whenever you set text to “Fit”, Framer measures the text at its current font-size, gets the bounding box, saves it, and renders an SVG around your text with a viewBox. Every time you edit the text, Framer repeats that process to ensure the viewBox stays relative to the text. Framer can even support a seamless editing experience by converting the text size back to pixels whenever you open it in the text editor by doing some basic math based on its current width. When you finish editing, Framer puts the viewBox back, and it’s effortlessly scaling again without any performance impact on the canvas.

The Result: Butter Smooth Resizing

When you deploy your site, the viewBox is already calculated, so Framer can statically generate the site, and the text will render at the exact right size even before JavaScript is loaded. This results in no flashes, resizing, or fade-ins, and buttery smooth resizing.

The Future: Container Queries

In the future, we plan to switch to container queries once they are fully supported by the browsers that Framer supports. You can use the cqw unit the same way you can use a vw unit, but cqw is relative to the container. This would work for components, since it removes the need for a complex CSS calc statement.

Fit Text is an excellent example of how Framer can abstract engineering work that would be hard to implement on a case-by-case basis and instead lets you focus on shipping fantastic sites. It’s exciting to see what people will build with this new feature.