Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a SVG-based Stretchy Type block #32

Draft
wants to merge 27 commits into
base: trunk
Choose a base branch
from
Draft

Conversation

DAreRodz
Copy link
Collaborator

@DAreRodz DAreRodz commented Oct 25, 2024

Co-authored by @SantosGuillamot

What?

This PR adds a Stretchy block that makes its text fill all the available width. It's built on top of #5.

The PR changes the block implementation, using SVGs to maintain the text ratio and some JavaScript code to update it whenever the text changes.

Features:

  • It reacts to changes in the container width, not only the viewport size.
  • It also reacts to changes in the text content.
  • It behaves visually the same way in the editor and the front end.
  • It Has the same support options as the Paragraph block.
  • Paragraph blocks can be easily converted into Stretchy blocks, and vice-versa.
  • It doesn't use the Interactivity API but should support it.
  • It can "work" without JavaScript (* see How? section).
Screen.Recording.2024-10-25.at.15.35.58-1.mov

How?

The implementation uses the following APIs, listed with the global usage % of browsers that support them:

The main idea is to use an SVG wrapper with foreingObject around the HTML code of the block content. With the SVG wrapper, we can use the viewBox property to make a scalable SVG that maintains its size ratio.

In addition, it uses ResizeObserver and a span wrapper with width: fit-content to monitor changes in the SVG content. That way, we can react to any changes that modify the text dimensions and update viewBox accordingly. This only happens when the text size ratio changes.

(*) The viewBox property is computed in the editor and persisted in the HTML. This effectively sets an initial value for viewBox without JavaScript, which mitigates the problem of scaling the SVG with code. However, that value is not 100% reliable, as different users could see different fonts with different sizes for the same text.

Alternatives

Window 'resize' event + computed font-size
This approach only reacts to changes in the viewport size, meaning that the size won't be re-computed when the element content changes dynamically or when the parent container dimensions change. Also, the font-size prop should be updated anytime the available width changes per frame.

ResizeObserver (95.37%) + computed font-size
This approach is similar to the above, but it uses a ResizeObserver in the parent container rather than subscribing to resize events on window. It can react to the available width, although it still has to update font-size per frame.

Container Query Units (90.97%) + ResizeObserver + computed var(--ratio)
This one is similar to the SVG approach. The difference is that it uses container query units to set a font-size value relative to the container's width. The text's height/width ratio is re-calculated whenever the text changes and the font-size value updated accordingly.

CSS custom properties (89.97%) + Container Query Units
This only-CSS solution could be based on Roman Komarov's Fit-to-Width Text technique. We tested it in the feature/stretchy-type-paragraph branch. It's reliable in most cases, but some fonts seem to be adjusted incorrectly.

@DAreRodz DAreRodz marked this pull request as draft October 25, 2024 12:22
@DAreRodz DAreRodz marked this pull request as ready for review October 25, 2024 13:39
@DAreRodz DAreRodz marked this pull request as draft October 25, 2024 13:40
@tommusrhodus tommusrhodus mentioned this pull request Oct 30, 2024
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants