holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.71k stars 513 forks source link

Disabling scrolling in parents not working as expected #6102

Open hyamanieu opened 10 months ago

hyamanieu commented 10 months ago

ALL software version info

Python 3.10.12 Panel: 1.3.4 Bokeh: 3.3.2 Param: 2.0.1

Description of expected behavior and the observed behavior

However, if I disable scroll too all the parents but enable it to the target column, one of the parent is actually enabling scroll, not the target column which has an overflowing height!

I have tried various combination, so my examples are not as exhaustive as everything I've tried out (combining scroll, max_height, height_policy, sizing_mode, height, on both client side and here).

Complete, minimal, self-contained example code that reproduces the issue

Non working example that I though shall work

import panel as pn
from bokeh.palettes import Category10_10

color = Category10_10

child_column = pn.Column(*[
    pn.pane.HTML(f"*Number {i}*", 
                 height=50, 
                 styles={'background':color[(i % len(color))-1]})
    for i in range(40)
],
scroll = True)

child_right_side = pn.pane.Markdown("""
# Some side text

## some paragraph

La Buse variable (Buteo buteo) est une espèce de rapaces diurnes de taille moyenne, appartenant à la famille des Accipitridae, très répandue dans le Paléarctique, où elle niche depuis les îles de l'océan Atlantique jusqu'au nord-ouest de la Chine et de la Mongolie, en passant par l'Europe et la Russie européenne. Sa zone d'hivernage inclut le Paléarctique occidental, l'Afrique de l'Est et australe, ainsi que le sous-continent indien.                    

""")

top_row = pn.Row(child_column, child_right_side, scroll=False)

template = pn.template.MaterialTemplate(
    title="Non-working minimal example",
    collapsed_sidebar=True,
)
template.main.scroll=False
template.main.append(top_row)

try:
    s.stop()
except:
    pass
s = template.show(port = 5006)

Working example using custom JS (beware as I haven't rewritten the children):


MESSAGES_COLUMN_CSS = "messages-column"
MESSAGES_MAIN_VIEW_CSS = "messages-view-row"

RESIZE_MESSAGE_COLUMN = """

<script type="text/javascript">
const updateColumnHeight = () => {{
    const bkRow = document.querySelector('.{message_main_view_css}');
    const shadowRootContainer = bkRow.shadowRoot; // Adjust as per your actual DOM structure
    const bkColumn = shadowRootContainer.querySelector('.{message_column_css}');
    console.log("resizing column")
    if (bkColumn) {{
        const bkRowHeight = bkRow.offsetHeight;
        bkColumn.style.height = `${{bkRowHeight}}px`;
        bkColumn.style.overflowY = 'auto';
        }}
    }}

console.log("initializing callback...")

window.addEventListener('resize', updateColumnHeight);
setTimeout(updateColumnHeight, 1000);

</script>
""".strip().format(
    message_main_view_css=MESSAGES_MAIN_VIEW_CSS,
    message_column_css=MESSAGES_COLUMN_CSS
)

child_column.css_classes = [MESSAGES_COLUMN_CSS]
top_row = pn.Row(child_column, 
                 child_right_side, 
                 scroll=False,
                 css_classes=[MESSAGES_MAIN_VIEW_CSS],                 
                styles = {
                    "max-height": "100%",
                    },
                    )

template = pn.template.MaterialTemplate(
    title="Working minimal example",
    collapsed_sidebar=True,
)
template.header.append(pn.pane.HTML(RESIZE_MESSAGE_COLUMN))
template.main.scroll=False
template.main.append(top_row)
try:
    s.stop()
except:
    pass
s = template.show(port = 5006, open=False)

Stack traceback and/or browser JavaScript console output

Screenshots or screencasts of the bug in action

https://github.com/holoviz/panel/assets/15906523/aae51c3a-37e9-44da-866b-eab9e7dc4c42

https://github.com/holoviz/panel/assets/15906523/596bac16-15da-41bd-9eff-4d115b610c8a

ahuang11 commented 10 months ago

If I understand this issue correctly, I think you may need to pass height to child_column. Let me know if that's it, or something else?

child_column = pn.Column(*[
    pn.pane.HTML(f"*Number {i}*", 
                 height=50, 
                 styles={'background':color[(i % len(color))-1]})
    for i in range(40)
],
scroll = True, height=600)
image
hyamanieu commented 10 months ago

As I have said:

I want everything to be responsive, not absolute.

So yes, it works to fix to 600 px, but it's not responsive anymore.

ahuang11 commented 10 months ago

Does this work?

child_column = pn.Column(*[
    pn.pane.HTML(f"*Number {i}*", 
                 height=50, 
                 styles={'background':color[(i % len(color))-1]})
    for i in range(40)
],
scroll = True, min_height=600, sizing_mode="stretch_height")
hyamanieu commented 10 months ago

Does this work?

child_column = pn.Column(*[
    pn.pane.HTML(f"*Number {i}*", 
                 height=50, 
                 styles={'background':color[(i % len(color))-1]})
    for i in range(40)
],
scroll = True, min_height=600, sizing_mode="stretch_height")

I'm having two scroll bar in this case: one for the child column (its content is as expected overflowing its height), but also one for the main content (not the row) as the child column has a height bigger than the viewport, and main-content has a height which is some value below 100hv.

As I said, I've tried several combinations.

pierrotsmnrd commented 9 months ago

I have had a look and you'll find below a solution that I think works as you expect. I mostly rely on CSS to achieve this.

Here are my findings and a few remarks :

  1. the template itself needs to have some padding removed
  2. You don't need to use scroll=True/False, so I commented all occurrences
  3. There's a weird div with class scroll-button that was messing the layout, I hid it with CSS. I think that comes from the template used.
  4. The main container of the app is a Row, with first a column and then a Markdown. I have put a fixed width (in pixels) to the column, and used this fixed with to size the markdown properly (with the CSS function calc) . You can change this fixed with to whatever you want, even a relative width like 10% to have everything responsive, you simply need to change at both places. If you put the markdown inside a column to add more content, move the width CSS property from the Markdown to the column.

Part of my development process when styling a CSS app is to add background-color:...; on key components so I can visualize them easily and understand what's going on. I've left them on purpose in the code below.

This is the result :

https://github.com/holoviz/panel/assets/756464/85ceb401-e2e8-431d-b4b4-0fb7fa9eb063

Suggested solution :


import panel as pn
from bokeh.palettes import Category10_10

color = Category10_10

child_column = pn.Column(*[
    pn.pane.HTML(f"*Number {i}*", 
                 height=50, 
                 styles={'background':color[(i % len(color))-1]})
    for i in range(40)
],

stylesheets=[''' :host {
                    overflow-y: scroll;
                    height:100%;
                    width: 100px;  /* 4 : fixed width on the column*/ 
             } ''']
)

child_right_side = pn.pane.Markdown("""
# Some side text

## some paragraph

La Buse variable (Buteo buteo) est une espèce de rapaces diurnes de taille moyenne, appartenant à la famille des Accipitridae, très répandue dans le Paléarctique, où elle niche depuis les îles de l'océan Atlantique jusqu'au nord-ouest de la Chine et de la Mongolie, en passant par l'Europe et la Russie européenne. Sa zone d'hivernage inclut le Paléarctique occidental, l'Afrique de l'Est et australe, ainsi que le sous-continent indien.                    

""",
stylesheets=[''':host { 
                    background-color:lightblue;
                    margin: 0px;
                    width: calc(100% - 100px); /* 4 : use the fixed width here to size the markdown properly */ 
             } ''']
)

top_row = pn.Row(child_column, 
                 child_right_side, 
                 #scroll=False
                 sizing_mode="stretch_both",
                 stylesheets=[''' :host { 
                                    background-color: gold;
                                } 

                                /* 3 : Hide the scroll-button that messes the layout */
                                .scroll-button {
                                    display:none;
                                }
                            ''']
                 )

template = pn.template.MaterialTemplate(
    title="Non-working minimal example",
    collapsed_sidebar=True,
    raw_css=[''' #main {
                    background-color:red;
                    padding: 0px !important;  /*  1 : removing padding on the template*/
                }  
            ''']
)
#template.main.scroll=False
template.main.append(top_row)

s = template.show(port = 5006)
hyamanieu commented 9 months ago

Thanks @pierrotsmnrd ! It works even without your point number 3 (I'm using Firefox)

/* 3 : Hide the scroll-button that messes the layout */
          .scroll-button {
              display:none;
          }

I've tried with vanilla, material template, as well as no template (simply serving top_row).

Concerning the padding (number 3), without it it indeed hides part of the last message block after scrolling all the way down. Of course this problem is not there upon only serving top_row.

I don't know what kind of resolution this issue deserves: documentation or a fix? I still believe it should have been easier to have the layout containing an overflowing content to have its scroll bar enabled, rather than having on of the layout parent enable the scrolling in its place.

ahuang11 commented 9 months ago

I think a fix would be ideal.