0

I have a Dash app made up of three sections: top, middle and bottom. I want it to look like this when displayed on mobile (viewport size xs):

  +--------+  # mobile
  |  top   |
  |--------|
  |        |
  | middle |
  |        |
  |--------|
  | bottom |
  +--------+

And like this when displayed on desktop (viewport sizes sm-xxl):

  +--------+ +--------+  # desktop
  |  top   | |        |
  |--------| | middle |
  | bottom | |        |
  +--------+ +--------+

These two layouts are fairly straightforward to create separately:

dbc.Col([         # mobile
    dbc.Col(top),
    dbc.Col(middle),
    dbc.Col(bottom)
])

dbc.Row([                   # desktop
    dbc.Col([top, bottom]),
    dbc.Col(middle)
])

The problem is I don't know how to create a single layout which switches between the two based on screen width. The dash-bootstrap-components documentation describes how the order, offset and size parameters of a dbc.Col can be used to define different layouts for different responsive tiers of the Bootstrap grid system (e.g. xs vs sm). But after a good amount of tinkering, I still can't figure out how to achieve the switching behavior described above.

Here is a minimal code sample, along with a screenshot of the unintended result:

from dash import Dash, html
import dash_bootstrap_components as dbc

top = dbc.Col(
    html.H1('top'),
    style={'height': '10em', 'background-color': '#636EFA'}
)
middle = dbc.Col(
    html.H1('middle'),
    style={'height': '20em', 'background-color': '#EF553B'}
)
bottom = dbc.Col(
    html.H1('bottom'),
    style={'height': '8em', 'background-color': '#00CC96'}
)

layout = dbc.Row([
    dbc.Col(
        top,
        xs=dict(order=1, size=12),
        sm=dict(order=1, size=6)
    ),
    dbc.Col(
        middle,
        xs=dict(order=2, size=12),
        sm=dict(order=2, size=6)
    ),
    dbc.Col(
        bottom,
        xs=dict(order=3, size=12),
        sm=dict(order=3, size=6)
    )
])

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(layout)
app.run_server(debug=True)

enter image description here

lukearend
  • 170
  • 2
  • 7

1 Answers1

0

This documentation page describes CSS styling parameters that can be added to flexbox containers to make contents wrap vertically rather than horizontally.

Because Bootstrap uses flexbox under the hood, it turns out the top-level dbc.Container for my app could be styled using the attributes described at that page. I created a stylesheet alongside the app with a special class for the root Container that changes its wrapping from horizontal to vertical based on a media query.

The code below produces the layout I wanted.

app.py:

from dash import Dash
import dash_bootstrap_components as dbc

top = dbc.Col('top', style={'height': '10em', 'background-color': '#636EFA'})
middle = dbc.Col('middle', style={'height': '20em', 'background-color': '#EF553B'})
bottom = dbc.Col('bottom', style={'height': '8em', 'background-color': '#00CC96'})

layout = [
    dbc.Col(
        top,
        xs=dict(order=1, size=12),
        sm=dict(order=1, size=6)
    ),
    dbc.Col(
        middle,
        xs=dict(order=2, size=12),
        sm=dict(order=3, size=6)
    ),
    dbc.Col(
        bottom,
        xs=dict(order=3, size=12),
        sm=dict(order=2, size=6)
    )
]

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(layout, className='root-container')
app.run_server(debug=True)

assets/custom.css:

@media screen and (min-width: 576px) {
    .root-container {
        display: flex;
        flex-wrap: wrap;
        flex-direction: column;
        height: 300px;
    }
}
lukearend
  • 170
  • 2
  • 7