All Bits Equal
All Bits Equal

Reputation: 793

Setting the fontSize of <html> in React for using REM in responsive design

I'm currently working on a pet web project with react and I'm using a container that's 16:9 and scaling with the current viewport. The idea is based on a pen, I've created with vanilla JS (https://codepen.io/AllBitsEqual/pen/PgMrgm) and that's already working like a charm.

function adjustScreen() {...}
adjustScreen()

[...]

const resizeHandler = function () { adjustScreen() }

window.addEventListener('resize', helpers.debounce(resizeHandler, 250, this))

I've now written a script that's sitting in my App.jsx, (un)binds itself via useEffect and calculates the current size of the viewport to adjust the container, whenever the viewport changes (throttled for performance). I'm also using media queries to adjust the size and font size of elements in the container, which is working ok but isn't much fun to work with.

I want to expand on this idea and change the font size of the HTML Element in the same function that calculated the current container size so that I can use REM to scale font-size and other elements based on my calculated root font size.

Is there a valid and future-proofed way of changing the font-size style of my Tag via ReactJS either via the style tag or style attribute?

Upvotes: 1

Views: 2865

Answers (1)

All Bits Equal
All Bits Equal

Reputation: 793

For now I've resorted to using "document.documentElement" and "style.fontSize" to achieve what I wanted but I'm not 100% sure this is the best solution. I'll see if I can find or get a better solution before I accept my own answer as the best...

I'm using useState for the game dimensions and within the useEffect, I'm attaching the listener to resize events, which I throttle a bit for performance reasons.

const App = () => {
    const game_outerDOMNode = useRef(null)
    const rootElement = document.documentElement

    function getWindowDimensions() {
        const { innerWidth: width, innerHeight: height } = window
        return {
            width,
            height,
        }
    }

    const [gameDimensions, setGameDimensions] = useState({ width: 0, height: 0})

    useEffect(() => {
        function adjustScreen() {
            const game_outer = game_outerDOMNode.current
            const ratioHeight = 1 / 1.78
            const ratioWidth = 1.78
            const { width: vw, height: vh } = getWindowDimensions()

            const width = (vw > vh)
                ? (vh * ratioWidth <= vw)
                    ? (vh * ratioWidth)
                    : (vw)
                : (vh * ratioHeight <= vw)
                    ? (vh * ratioHeight)
                    : (vw)

            const height = (vw > vh)
                ? (vw * ratioHeight <= vh)
                    ? (vw * ratioHeight)
                    : (vh)
                : (vw * ratioWidth <= vh)
                    ? (vw * ratioWidth)
                    : (vh)

            const longestSide = height > width ? height : width
            const fontSize = longestSide/37.5  // my calculated global base size

            setGameDimensions({ width, height })
            rootElement.style.fontSize = `${fontSize}px`
        }
        const debouncedResizeHandler = debounce(200, () => {
            adjustScreen()
        })
        adjustScreen()
        window.addEventListener('resize', debouncedResizeHandler)
        return () => window.removeEventListener('resize', debouncedResizeHandler)
    }, [rootElement.style.fontSize])

    const { width: gameWidth, height: gameHeight } = gameDimensions

    return (
        <div 
            className="game__outer" 
            ref={game_outerDOMNode} 
            style={{ width: gameWidth, height: gameHeight }}
        >
            <div className="game__inner">
                {my actual game code}
            </div>
        </div>
    )
}

Upvotes: 1

Related Questions