🍄
内部要素のサイズに合わせてfont-sizeを調整するcomponentをhooksで作る
記事作成日: 2019/10/13
作ったものメモ。
ふとiOSでadjustsFontSizeToFitWidth
という横幅に合わせてフォントサイズが変わるのがあったな、というのを思い出したので再現してみた。
import React, { useState, useRef, useLayoutEffect, useEffect } from "react"
import stringWidth from "string-width"
import styled from "styled-components"
const Container = styled.div`
width: 100%;
`
const AutoSizedButton = ({ text }) => {
const ref = useRef()
const [width, setWidth] = useState(0)
const [fontSize, setFontSize] = useState("auto")
useEffect(() => {
const sizePx = (width / stringWidth(text)) * 2
setFontSize(`${sizePx}px`)
}, [width, text])
useLayoutEffect(() => {
// @ts-ignore
const obs = new ResizeObserver((e) => setWidth(e[0].contentRect.width))
obs.observe(ref.current)
return () => obs.disconnect()
}, [])
return (
<Container ref={ref} fontSize={fontSize}>
{text}
</Container>
)
}
ResizeObserver
を利用している。
まだこれも不安定なツールなので、そこまで実用的なものではない。
フォントサイズの計算として、string-width
を利用している。昔はencodeURIComponent
での計算方法などがあったが、今は3byteで判定されるので使えなくなっている。
カスタムhooksとして切り出すならこんな感じだろう
(が、refsを渡すのはいまいちなので切り出しに向いてない)
const useAutoFontSize = (targetRef, text) => {
const [width, setWidth] = useState(0)
const [fontSize, setFontSize] = useState("auto")
useEffect(() => {
const sizePx = (width / stringWidth(text)) * 2
setFontSize(`${sizePx}px`)
}, [width, text])
useLayoutEffect(() => {
// @ts-ignore
const obs = new ResizeObserver((e) => setWidth(e[0].contentRect.width))
obs.observe(targetRef.current)
return () => obs.disconnect()
}, [])
return fontSize
}
Discussion