How to get a responsive layout

I have the feeling I am just missing something, but how do you make a layout mobile responsive? I am using bootstrap’s css.

Here is the minimum example:

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash()

app.layout = (
  html.Div(
    html.Div(
      html.Div(
        html.Button('Some very long text so we can see centering and styling', className='btn btn-secondary'),
      className='col-md-6 col-xs-12'),
    className='row justify-content-center'),
  className='container')
)

app.css.append_css({
    "external_url": "https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
})

if __name__ == '__main__':
    app.run_server(debug=True)

I am using:

dash==0.35.2
dash-core-components==0.42.1
dash-html-components==0.13.5
results from pip freeze
certifi==2018.11.29
chardet==3.0.4
Click==7.0
dash==0.35.2
dash-core-components==0.42.1
dash-html-components==0.13.5
dash-renderer==0.16.2
decorator==4.3.0
Flask==1.0.2
Flask-Compress==1.4.0
gunicorn==19.9.0
idna==2.8
ipython-genutils==0.2.0
itsdangerous==1.1.0
Jinja2==2.10
jsonschema==2.6.0
jupyter-core==4.4.0
MarkupSafe==1.1.0
nbformat==4.4.0
plotly==3.5.0
pytz==2018.9
requests==2.21.0
retrying==1.3.3
six==1.12.0
traitlets==4.3.2
urllib3==1.24.1
Werkzeug==0.14.1

These are the screenshots from Firefox, full screen:

Resizing the browser manually:

And using dev tools, viewport control:

You can see how that is way off. Any help is greatly appreciated and thanks in advance!

1 Like

If you were doing this in html, you would probably have something like this in your header

<meta name="viewport" content="width=device-width, initial-scale=1.0">

The easiest way to achieve the same in a Dash app is to use the meta_tags argument when creating your app object

app = dash.Dash(
    meta_tags=[
        {"name": "viewport", "content": "width=device-width, initial-scale=1"}
    ]
)

If you prefer, Dash also lets you override the default html template into which your app gets injected, check out the docs.

Finally, since you’re using Bootstrap, you might be interested in checking out dash-bootstrap-components (full disclosure, I’m one of the developers working on it),

5 Likes

Thanks a lot. Simple but so essential!

I am using dash-bootstrap-components, but wanted to keep the example basic!

1 Like

I am running into the same issue. When I try to resize my browser, the css isn’t responsive. I am using a bootstrap styling sheet:

import dash_bootstrap_components as dbc

app = dash.Dash(
            meta_tags=[
                {"name": "viewport", "content": "width=device-width, initial-scale=1"}
            ],
            external_stylesheets=[dbc.themes.SLATE],
      )

Screenshot for reference:

How have you constructed the layout? Those meta tags will only ensure that the CSS responds to the real viewport size rather than a virtual one (mobile devices generally pretend their screen is larger than it is then scale content down so that non-responsive websites don’t look terrible). To make the layout reorganise itself appropriately on small screens you need to tell it how to do that.

I see. I am on desktop running the app on chrome web browser. The meta-tags are in app.py and my layout code is in index.py:


app.layout = html.Div([

    # header
    html.Div([

        html.H2("Stroom Product suite ®", style={"float":"center",
                                                                      "margin-left":"40%",
                                                                      "margin-top":"30px"}),

        html.Div(
            html.Img(src='https://logo-white.png',height="100%")
            ,style={"float":"right","width":"170px","height":"100px","margin-top":"-14px"})
        ],
        className="row header"
    ),

    # body
    #html.Div(className='background')

    # tabs
    html.Div([

        dcc.Tabs(

            id="tabs",
            vertical=True,
            className="mb-3",
            #style={"height":"60", "verticalAlign":"middle", "font-size":"0.9375rem"},
            children=[

                 dcc.Tab(label="Portfolio", value="portfolio_tab"),
                 dcc.Tab(label="Smart Leads", value="market_tab"),
                 dcc.Tab(label="Spaces", value="reporting_tab"),
                 dcc.Tab(label="Revenue", value="revenue_tab",
                         children=[dcc.Tabs(id="subtabs", value="subtabs", style={"margin-left":"50px"},
                         children=[dcc.Tab(label='Comps', value='subtab1'),
                                   dcc.Tab(label='Analysis', value='subtab2')

                 ])
            ]),
                 dcc.Tab(label="Deal", value="deal_tab")

            ],
            value="revenue_tab",
        )

        ],

        className="row tabs_div"
    ),

        # Tab content
        html.Div(id="tab_content", style={"margin": "-32% 11%","float":"left"})

])

1 Like

I would suggest using dbc.Row and dbc.Col to control the layout rather than setting float property in your style arguments. They can be configured to take up different widths on different screen sizes. More generally to achieve responsiveness you’ll need to use CSS (whether bootstrap or your own) rather than inline style arguments as generally you need to make use of media queries to achieve different behaviour on different screen sizes.

Take a look at the layout documentation for dash-bootstrap-components and perhaps something like this responsive sidebar example.

1 Like

@tcbegley I am embedding a Dash app in an iFrame in a React component. The react app has a minimal navbar and layout, and the Dash app should fill the entirety of the available space. The React app and the Dash app are served from the same server (same origin), so CORS is not an issue.

Do you have a best-practice for ensuring the iFrame fills the available viewport? I have used react-iframe-resizer-super and iframe-resizer-react to implement this but it has been tough to get the iframe to fill all available space.

Side question - do you know how to inject Dash app state from the React app? Something like the (proprietary in Dash Enterprise) dash-embedded-component package does with their <DashApp value={this.state.sharedData}/> interface?

I know it’s not exactly on-topic here, but you seem to be extremely knowledgeable on this topic. Thank you!

I haven’t used the iframe approach much, but when I did I just set style="width:100vw;height:100vh" on the <iframe /> to make it fill the available space. I’m not familiar with the iframe resizer libraries you mention I’m afraid.

If the enclosing react app is just being used to add a navbar and some layout, I would see if you can either replicate that in Dash, or alternatively modify the index string (the HTML template that the Dash app gets injected into). This latter approach is what I did on the dash-bootstrap-components documentation and it has worked very well for me.

do you know how to inject Dash app state from the React app?

When I looked at this in the past, I think I concluded it wasn’t really possible. I think you’re right that something is possible in this direction with Dash enterprise, but I haven’t really used it. If you need to communicate with components outside the app, probably the easiest thing is to first see if you definitely can’t move those components into the app and use callbacks etc. to share information.

1 Like