交互流体排版
Interactive Fluid Typography

原始链接: https://electricmagicfactory.com/articles/interactive-fluid-typography/

## 流体排版:使用 CSS 调整字体 流体排版旨在在不同屏幕尺寸之间创建平滑缩放的字体大小,避免在断点处出现突兀的跳跃。 传统上,这涉及使用 `calc()` 和 `vw` 单位基于基础屏幕宽度和字体大小计算比例。 近期 CSS 的进步,特别是 **类型化算术** (Chrome 140+),彻底改变了这一过程。 最初,无单位值对于兼容性至关重要。 现在,类型化算术允许直接计算,例如 `calc(10em / 1px)`,从而能够根据视口宽度动态调整排版比例。 像 **Utopia** 这样的工具可以帮助生成这些流体值,并提供预定义的刻度。 然而,一个关键的改进是计算一个 `--screen-normalizer` 变量,以便在定义的范围内流体地调整基础字体大小 *和* 排版比例。 这允许实时原型设计,并使用 CSS 变量轻松缩放。 未来的 CSS 函数有望提供更大的灵活性,可能允许自定义函数根据设计系统步骤生成大小。 虽然目前仅限于 Chrome,但可以使用 `@supports` 实现回退解决方案。 这种方法可以实现和谐的排版,并能美观地适应任何屏幕尺寸。

Hacker News新 | 过去 | 评论 | 提问 | 展示 | 工作 | 提交登录 交互流体排版 (electricmagicfactory.com) 30 分,由 list 6 小时前发布 | 隐藏 | 过去 | 收藏 | 5 条评论 redblue 4 小时前 [–] 我讨厌像这样的网站。我尝试放大或缩小,它们却小心地破坏我的操作。回复 wtallis 3 小时前 | 父级 | 下一个 [–] 对于一个网站来说,使用我屏幕垂直空间 12% 来放置一个固定的一行导航标题,其中仅包含四个链接,这似乎很合适。阻碍内容似乎是主题。回复 kragen 2 小时前 | 父级 | 前一个 | 下一个 [–] 我没有遇到在这个网站上放大和缩小的任何问题。回复 leephillips 9 分钟前 | 根 | 父级 | 下一个 [–] 我也是。redblue,你是什么意思?回复 InvisGhost 3 小时前 | 父级 | 前一个 [–] 说得好!回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

What we call fluid typography are a set of tricks in CSS that allows to adapt the type size and leading when the screen size changes. So instead of having fixed breakpoints where the font-size abruptly, we want to have a smooth increase between different screen sizes, removing blind spots near the breakpoints where the font was disproportionally big or small.

The most basic implementation of fluid typography is to take a base size and a base screen width. If we divide the screen size (100vw) by the base size, we will have a ratio that will tell us how big is the screen related to the base size. Until recently, we had to take care in order not to multiply or divide two numbers with units, as this created an error. This has been solved in Chrome 140, creating exciting possibilities as outlined in this post by Amit Sheen, but support is still not baseline as I write this lines, so we will then just have to take care using unitless numbers for our base-screen-size and our base-font-size, in order to be able to operate with vw. This point is important and we'll come back to it later.

      --base-screen-size: 1200;
--base-font-size: 16;
--typographic-ratio: 1.618;

.font-size-base {
  calc(
    var(--base-font-size) * (100vw / var(--base-screen-size))
  )
}

.font-size-md {
  calc(
    var(--font-size-base) * var(--typographic-ratio)
  )
}

.font-size-lg {
  calc(
    var(--font-size-md) * var(--typographic-ratio)
  )
}
    


Font size medium

0px * 0 = 0px



Font size large

0px * 0 = 0px



With this setup, we can have a text-size equal to 16px in our desired base-size that will grow and shrink linearlly with the size of our viewport. This has the obvious drawback that size will grow and shrink indefinetely, making it not very usable as it is. We could restrict that behaviour with @media-queries, setting it fluid between two breakpoints, and setting it fixed on the rest, but fortunately modern CSS allows to write this in a much more elegant way.

Clamp to the rescue

With clamp() function, we can directly set a minimum and maximum size and setting it fluid in between. This method is a good approach, and we could even set different type sizes taking the same value as base and multiplying this value by your favourite typographic ratio—like for example the Golden Ratio (1.618).

      --base-screen-size: 1200;

--base-font-size-min: 14;
--base-font-size: 15;
--base-font-size-max: 16;

--typographic-ratio: 1.618;

.font-size-base {
  font-size: clamp(
    calc(1px * var(--base-font-size-min)),
    calc(var(--base-font-size) * 100vw / var(--base-screen-size)),
    calc(1px * var(--base-font-size-max)),
  )
}

--font-size-md {
  font-size: calc(var(--font-size-base) * var(--typographic-ratio))
}

--font-size-lg {
  font-size: calc(var(--font-size-md) * var(--typographic-ratio))
}
    


Font size medium

0px * 0 = 0px



Font size large

0px * 0 = 0px



However this method has the drawback that for small screens we generally want to set smaller jumps between our different typesizes, so ideally we would set a different typographic ratio. In order to do that we would have to create a breakpoint where all the types would change abruptly, making that part of the design a little bit junky. Also, it is not very obvious at between which viewport widths is the fluid part going to kick in.

Fluid scale generator

In order to overcome this, Andy Bell points out in its phenomenal course Complete CSS a way to generate a typographic scale setting different ratios between screen sizes. So for example, we can create a scale for screens up until 400px that will have a 1.414 ratio, and then from screens from 400px to 1200px the ratio will increase the bigger the viewport, until a maximum of 1.618. In order to do that, we can use the values generated by Utopia website. As Utopia already generates the fluid values for each of our steps, we just have to generate then and paste them in our code.

      --step-0: clamp(0.875rem, 0.8125rem + 0.25vw, 1rem);
/* Step 1: 19.796px → 25.888px */
--step-1: clamp(1.2373rem, 1.0469rem + 0.7615vw, 1.618rem);
/* Step 2: 27.9915px → 41.8868px */
--step-2: clamp(1.7495rem, 1.3152rem + 1.7369vw, 2.6179rem);
/* Step 3: 39.58px → 67.7728px */

.font-size-base {
  font-size: var(--step-0);
}

.font-size-md {
  font-size: var(--step-1);
}

.font-size-lg {
  font-size: var(--step-2);
}
    


Font size medium

0px * 0 = 0px



Font size large

0px * 0 = 0px



Now we are in control of everything, we can define the minimum and maximum sizes where our fluid typography will work, and we can also define a different scale for small viewports what will steadily grow—or shrink if that is desired—until reaching the scale we set for larger viewports. Also, it allows us to use rem instead of px, which should be considered a best practice for accesibility. This makes our typography fit and look harmonious in every screen size.

However, there is a price we are paying, we're losing all control in our CSS, and each time we want to change our ratios, add and/or remove different steps or setting different screen limits, we will have to calculate back at Utopia's website and paste it in our code. Also, we lose the ability to try different values in our CSS and see them updated live in our browser.

The missing piece: Typed Arithmetic

As we introduced before, CSS Typed Arithmetic shipped in Chrome 140, allowing us “to write expressions in CSS such as calc(10em / 1px) or calc(20% / 0.5em * 1px)”. This small addition is crucial, as now we can change our unitless typographic ratio based on screen width. Taking as a base the slope formula that Utopia also uses, we will calculate a --screen-normalizer variable that will allow us to adjust both our font-size and our typographic-ratio to the viewport size withing our predefined bounds.

      --base-font-size-small: 14px;
--base-font-size-large: 16px;

--lower-ratio: 1.414;
--upper-ratio: 1.618;

--lower-bound: 400px;
--upper-bound: 1200px;

--screen-normalizer: clamp(
  0,
  (100vw - var(--lower-bound)) / (var(--upper-bound) - var(--lower-bound)),
  1
);

--fluid-base-size: calc(
  var(--base-font-size-small) +
  (
    var(--base-font-size-large) -
    var(--base-font-size-small)
  ) *
  var(--screen-normalizer)
);

--fluid-step: calc(
  var(--lower-ratio) +
  (
    var(--upper-ratio) -
    var(--lower-ratio)
  ) *
  var(--screen-normalizer)
);

.font-size-base {
  font-size: var(--fluid-base-size);
}

.font-size-md {
  font-size: calc(var(--font-size-base) * var(--fluid-step))
}

.font-size-lg {
  font-size: calc(var(--font-size-md) * var(--fluid-step))
}
    


Font size medium

0px * 0 = 0px



Font size large

0px * 0 = 0px



This opens a whole world of possibilities, as now we can easily switch between different type scales and sizes live from your console, which we find really handy for prototyping. Having all your spacing relative to just two measures makes it trivial to generate different additional type or space sizes when needed. In case I need a font size a half-step bigger or smaller than any of my current sizes, we just have to multiply or divide by the square root of my --fluid-step variable.

      --fluid-base-size: calc(
  var(--base-font-size-small) +
  (
    var(--base-font-size-large) -
    var(--base-font-size-small)
  ) *
  var(--screen-normalizer)
);

--fluid-step: calc(
  var(--lower-ratio) +
  (
    var(--upper-ratio) -
    var(--lower-ratio)
  ) *
  var(--screen-normalizer)
);

--fluid-step-half: pow(var(--fluid-step), 0.5);

.font-size-sm {
  font-size: calc(var(--fluid-base-size) / var(--fluid-step-half));
}

.font-size-base {
  font-size: var(--fluid-base-size);
}

.font-size-demi {
  font-size: calc(var(--fluid-base-size) * var(--fluid-step-half));
}

.font-size-md {
  font-size: calc(var(--font-size-base) * var(--fluid-step))
}

.font-size-lg {
  font-size: calc(var(--font-size-md) * var(--fluid-step))
}
    

Font size xs

0px / 0.000 = 0px





Font size demi

0px * 0.000 = 0px



Font size medium

0px * 0 = 0px



Font size large

0px * 0 = 0px



As of today, this is still just supported in Chrome, but we can start using it having Utopia generated classes as fallback using @supports rules.

      --step-0: clamp(0.875rem, 0.8333rem + 0.2222vw, 1rem);

.font-size-base {
  font-size: var(--step-0);
}

@supports (transform: scale(calc(1px / 1px))) {
  --fluid-base-size: calc(
    var(--base-font-size-small) +
    (
      var(--base-font-size-large) -
      var(--base-font-size-small)
    ) *
    var(--screen-normalizer)
  );

  .font-size-base {
    font-size: var(--fluid-base-size);
  }
}
    

The future: CSS functions

While already in the baseline support, CSS functions still don't support some mathematical functions as pow() or clamp(). When that time comes, it will be even easier to make font and space sizes on the fly, using just a function and a number that expresses the number of steps on your design system. For example, --fluid-size(2) could be used to get the size for the second step in the scale and work both for fonts and for spacing.

      @function --fluid-scaler(--small-measure, --large-measure) {
  result: calc(
    --small-measure +
    (
      --large-measure -
      --small-measure
    ) *
    var(--screen-normalizer)
  );
}

--fluid-base-size: --fluid-scaler(
  var(--base-font-size-small),
  var(--base-font-size-large)
);

--fluid-step: --fluid-scaler(
  var(--lower-ratio),
  var(--upper-ratio)
);

@function --fluid-size(--step) {
  result: calc(
    var(--fluid-base-size) *
    var(--fluid-step) ^
    var(--step)
  );
}

.font-size-base {
  font-size: --fluid-size(1);
}

.font-size-md {
  font-size: --fluid-size(2);
}
    

Meanwhile, pressing the button below will open a menu that will let you play with all the typographic measures of this website, squizzing and expanding it as much as you like!

联系我们 contact @ memedata.com