Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scrolling in the iframe is not working in iOS #3921

Closed
Sandstedt opened this issue Jul 26, 2018 · 13 comments
Closed

Scrolling in the iframe is not working in iOS #3921

Sandstedt opened this issue Jul 26, 2018 · 13 comments
Assignees
Labels

Comments

@Sandstedt
Copy link

Bug or support request summary

This is a re-opened issue of Issue: 1227

It's not possible to scroll the iframe where the components is show on an iOS device.

Steps to reproduce

  • Open the storybook on an iOS device
  • Navigate to a component that takes more space then the screens viewport height (so it should be able to scroll.
  • Scroll it

Please specify which version of Storybook and optionally any affected addons that you're running

  • @storybook/addon-info": "^3.4.8",
  • @storybook/addon-knobs": "^3.4.8",
  • @storybook/addon-options": "^3.4.8",
  • @storybook/react": "^3.4.8",

Affected platforms

  • iPad iOS 11

Screenshots / Screencast / Code Snippets (Optional)

To fix this, add this to the container around the iframe:

overflow: auto;
-webkit-overflow-scrolling: touch;
@Sandstedt
Copy link
Author

A dirty workaround:
Create a file called manager-head.html in the .storybook folder and put this dirty css in it:

<style>
  /* Make the iframe scroll on iOS */

  .Pane.horizontal.Pane1>div>div+div {
    overflow: auto;
    -webkit-overflow-scrolling: touch;
  }
</style>

@danielduan
Copy link
Member

would you mind opening a PR to fix this? thanks!

@jtomaszewski
Copy link

jtomaszewski commented Nov 26, 2018

@Sandstedt 's fix is not enough.

My case: I am using newest stable 4.0.x.

I had added <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> tag to both manager-head.html and preview-head.html.

I tried debugging it remotely with Safari Debugger and adding various width, max-width, min-width, overflow: auto;, -webkit-overflow-scrolling: touch; wherever it's possible, and it just didn't work. Still the scroll on iOS was broken.

The reason is you can't force the iframe's document to have a certain width on iOS (1, 2). The only way is to force it from the document inside. For example, in preview-head.html you can add:

<style>
body {
  max-width: 100vw;
}
</style>

Then only you will prevent iframe from being wider than how it should be, and thus scroll will be working better.

But this will still break position: fixed in the iframe. And the scroll still works very weirdly for me. If I browse the story directly by /iframe.html link, then all is okay. So I know it's the storybook / iOS / iFrame fault.

I think there should be a way to let the stories be opened in a separate tab (directly, without the <iframe> thing). For example, any click in the storybook sidebar could just act like that. This could be enabled only when some configuration flag is enabled and the device is running on iOS.

@Sandstedt
Copy link
Author

@jtomaszewski I will see if I can come upp with a working solution during the weekend and make a pull request. But I don't think it's a good solution to open it in a new tab. Then you loose access to the navigation and the bottom panel. In our projects we use that panel for ex Knobs to trigger actions and change values, so we still need that panel in the iOS version.

It should be an easy fix. Just need to have time for it :)

@jtomaszewski
Copy link

jtomaszewski commented Nov 30, 2018

P.S. As a workaround if anybody's interested, we created a simple preview panel addon, which shows a 'Preview in a new window' button. It always opens the tab in the same new window so you can easily go back and forth between the tabs on your mobile ;)

Looks like that:

image

Code (storybook ~4.0.0):

import React from 'react';
import addons from '@storybook/addons';

class PreviewPanel extends React.PureComponent {
  state = {
    url: undefined,
  };

  componentDidMount() {
    const { api } = this.props;
    api.onStory(this.handleStory);
  }

  componentWillUnmount() {}

  handleStory = () => {
    const { api } = this.props;
    this.setState({
      url: `${window.location.origin +
        window.location.pathname.replace('index.html', '')}iframe.html${
        api.getUrlState().url
      }`,
    });
  };

  render() {
    const { active } = this.props;
    const { url } = this.state;
    if (!active) {
      return null;
    }

    if (!url) {
      return 'Waiting for a story to be initialized...';
    }

    return (
      <div
        style={{
          width: '100%',
          padding: '15px',
          fontFamily:
            '-apple-system, ".SFNSText-Regular", "San Francisco", BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", "Lucida Grande", Arial, sans-serif',
          WebkitFontSmoothing: 'antialiased',
        }}
      >
        <a
          href={url}
          target="storybook-preview"
          style={{
            color: '#333',
            display: 'block',
            textAlign: 'center',
            borderRadius: '3px',
            backgroundColor: 'rgb(247, 247, 247)',
            textDecoration: 'none',
            fontSize: '16px',
            lineHeight: '3',
          }}
        >
          Preview in new window
        </a>
      </div>
    );
  }
}

addons.register('preview', api => {
  const channel = addons.getChannel();

  addons.addPanel('preview/panel', {
    title: 'Preview',
    render: ({ active }) => (
      <PreviewPanel active={active} channel={channel} api={api} />
    ),
  });
});

@ndelangen
Copy link
Member

You'll be glad to hear that will be a standard feature in Storybook 5, see #4086

@ndelangen ndelangen added this to the v5.0.0 milestone Nov 30, 2018
@tmeasday
Copy link
Member

@ndelangen did this end up getting implemented?

@ndelangen
Copy link
Member

The 'eject' button IS implemented, yes.

I'm unsure of the scrolling in iOS bug described.

@tmeasday
Copy link
Member

OK, I think let's leave this open and someone can get back to us as to whether it is fixed. It isn't a particular focus of v5 so I will remove from the milestone.

@tmeasday tmeasday removed this from the v5.0.0 milestone Jan 19, 2019
@larsenwork
Copy link

Just tried V5 Beta2 and confirm it's not fixed, so still a 🐛

@ndelangen
Copy link
Member

@larsenwork thanks for checking, sad to hear the issue is still present. I'll try to take a look asap.

Can I reproduce this in the iOS simulator?

@ndelangen
Copy link
Member

I did some digging, I'm able to scroll in iOS simulator a little bit, but it's buggy.

But the cause is this bug: https://bugs.webkit.org/show_bug.cgi?id=149264

WebKit is "frame flattening" which is causing the iframe to be sized differently than expected. (it auto-sizes, overriding any styles we throw at it).

This causes very annoying bugs, like:
If you component has 100vh paddingTop..
Then the iframe will be initially be sized to fit the styles storybook supplies.
Then the iframe will be resized to encompass all content inside..
Then this causes the vh to change.
Then the component gets redrawn because of the css rule

Now if WebKit would keep updating the size of the iframe element, it would just keep on growing. So it doesn't.
It seems WebKit, just "flattens" sometimes, It seems in some cases it resizes/reflows correctly.

As you can imagine this causes a TON of bugs.

Unfortunately there nothing we can do about this. Iframes cannot be scrolled on iOS, and the "flattening" is buggy because otherwise the iframe's size would potentially explode.


TLDR:
So as long as your component/element doesn't respond to the height of the iframe it seems to mostly works OK.

@larsenwork
Copy link

larsenwork commented Mar 18, 2019

@ndelangen great digging! And yes, it's a webkit thing and not storybook specific.

Just some further details should anyone be interested:

My main issue has also been when the layout I'm testing is 100% height e.g.

html, body, #root {
  height: 100%;
}

and then some element inside it should scroll

.sidebar {
  overflow-y: scroll;
}

even though is shouldn't be scrollable the body "catches" the scroll-swipe-gesture and insists on doing the webkit scroll bounce.

Doing something like:

html, body, #root {
  position: fixed; 
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

helps a bit but it's still buggy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants