Server-side rendering + responsive design + inline styles -> which breakpoint to use?
G

2

18

I have a responsive web application built with ReactJS for which I want one day to support server-side rendering.

According to the viewport size, the application layout/behavior changes. But all these changes can not only be done with plain CSS mediaquery: the JS behavior, and the underlying HTML structure also has to be changed according to the width.

For example I could have:

Under 800px width:

<div class="app">
  <div class="menu-mobile">...</div>
  <div class="content">...</div>
  <div class="mobile-left-menu">...</div>
  <div class="footer-mobile">...</div>
</div>

Above 800px width:

<div class="app">
  <div class="menu">...</div>
  <div class="main">
    <div class="left-menu">...</div>
    <div class="content">...</div>
    <div class="right-menu">...</div>
  </div>
  <div class="footer">...</div>
</div>

Now, I want to use server-side rendering for that application. But on the server I don't have the width, so I don't know which HTML structure to return to the client.

Note that I'm not looking for a solution that use a static default server-side breakpoint, and that on the client correct the app. I am looking for a solution that would return to the client the proper html structure according to its device. So it should work fine if he disables javascript on his browser.


One could argue that I could render the html needed for both, and hide/show the required parts with plain CSS mediaqueries and display: none, but it would complicates the app and make it render a lot of unused html elements because generally it's unlikely that the user move above/under the breakpoint (I mean if he has a mobile device, the html elements for desktop will never be used)

Also, if I want to use inline-style, it becomes complicated because I have to render these inline styles for the correct width on the server.

I've seen some people are thinking about sniffing the browser UA to make an estimated guess of their viewport size. But even with some unsecure screen dimension detection, I'm not sure we can know the device screen orientation on the server-side.

Can I do anything to solve this problem?

Gerhart answered 12/2, 2016 at 11:8 Comment(5)
I'm pretty sure this won't be good enough for you, but you really should just render both displays. As you mentioned, you can't realy be sure of the screen size on the client, so you won't be able to know if you should render the full/mobile version. Here's what I did in my app, though I'm not sure it's great idea: I wrapped my app with a component that set up a resize listener that would share the view size via context. Every responsive component would read the view size and render accordingly.Firecrest
What are your limitations in terms of specifying the viewport size, orientation, etc., in the initial request from the client app?Display
@LuisCrespo not sure to understand your question. I'm not doing SSR atm and don't have a concrete problem to solve, but I'd like to explore SSR in the near future and know how to handle this kind of problem. For now it seems suggestion of Gershon Papi is the only way unfortunatlyGerhart
@SebastienLorber Oh I see, thought you had an app already using SSR. I don't know too much about SSR yet, with my question I was wondering if you could somehow specify viewport info when performing the first request to the server. But please disregard my question if that's not something feasible when using server side rendering.Display
I think server-side rendering is often taken to mean that everything is rendered on the server, which does not have to be the case. If something is dependent on client-side data (i.e. the device width), then you can simply delegate the rendering of those components to the componentDidMount lifecycle method, at which point all the device information will be available.Bunch
G
4

I think Artsy found the best solution to this problem.

They render everything on the server, and then only render the layout needed on the frontend.

If on the server they are sure the device has certain boundaries, they eventually optimize the SSR by rendering only the required layout.

https://artsy.github.io/blog/2019/05/24/server-rendering-responsively/

Gerhart answered 5/7, 2019 at 9:53 Comment(3)
Artsy is a great solution, but when js is disabled it has all layouts in dom for all breakpoints.Lockage
when js is enabled, it's loads all js chunks for all screen size, even though code splitting is done.Lockage
@Lockage This must mean you didn’t load the CSS, as it would hide those breakpoints with pure CSS methods. See createMediaStyle in the docs github.com/artsy/fresnel#ssr-exampleRummy
S
1

I think this is what you want, but this is not a prefect solution

1.what matters

you want mobile user get mobile page directly and without html in PC version, and verse versa, that assures no need of css ( inline style instead ), and less network

2.how I solve it

use browser user agent to detect mobile or tablet, and you can have a predict and render on your server, when client got all loaded, recheck screen solution and render again if you had a false predict.

you can bind callback to window resize and orientation change, change your redux and render automaticly

3.shot comings

less network, the less means very very little

false predict may happen, when it happens the page may refresh when loaded

//server side detect and show different, if got force param, use force solution
const detected = bowser._detect(req.get('User-Agent'))
const initState = req.query.force ? {
  [req.query.force]: true,
} : {
  bowser: {
    mobile: detected.mobile,
    tablet: detected.tablet,
  }
}
const redux = initStore(initState)
serverRender(redux)

//component X, show different content
const X = ({
  mobile
}) => (<div>
  {!!mobile?(<div>mobile</div>):(<div>pc</div>)}
</div>)

export default connect((state) => {
  return {
    mobile: detected.mobile,
    tablet: detected.tablet,
  }
})(X)

//top level component 
componentDidMount() {
  const reflow = () => {
    switch ($(window).width()) {
      case >800:
        this.props.dispatch(setSolution('pc'))
      default:
        this.props.dispatch(setSolution('mobile'))
    }
  }
  if (typeof window != 'undefined') {
    reflow()
  }
  $(window).resize(() => {
    reflow()
  })
  $(window).on("orientationchange", () => {
    reflow()
  })
}
Shockproof answered 5/9, 2017 at 6:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.