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

Behavior of setViewport() inconsistent in Headful #1910

Open
alixaxel opened this issue Jan 28, 2018 · 19 comments
Open

Behavior of setViewport() inconsistent in Headful #1910

alixaxel opened this issue Jan 28, 2018 · 19 comments
Labels
bug chromium Issues with Puppeteer-Chromium confirmed P3 upstream

Comments

@alixaxel
Copy link
Contributor

alixaxel commented Jan 28, 2018

Environment:

  • Puppeteer: 1.0.0
  • Platform / OS: Ubuntu 16.04 LTS (1920x1080@1x)
  • Node.js: 8.9.3
  • Chromium: 65.0.3312.0 (Developer Build) (64-bit)

What steps will reproduce the problem?

Running the following code several times.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: [
      '--start-maximized',
    ],
    headless: false,
  });

  const page = await browser.newPage();

  /**
   * This should make Chromium infer current screen resolution (only in headless = false).
   */
  await page.setViewport({
    width: 0,
    height: 0,
  });

  await page.goto('http://matanich.com/test/viewport-width', {
    waitUntil: [
      'domcontentloaded',
      'load',
    ],
  });

  let result = await page.evaluate(
    () => {
      return window.innerWidth;
    }
  );

  console.log(`Detected window.innerWidth to be ${result}.`);

  await browser.close();
})();

What is the expected result?

I should get the save window.innerWidth all the time.

What happens instead?

Seems that sometimes setViewport() fails silently and fallbacks to the default viewport size of 800x600.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 800.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 1855.

$ node setViewportTest.js
Detected window.innerWidth to be 800.
@alixaxel
Copy link
Contributor Author

Also experimented adding a await page.waitFor(500); after setViewport() and goto().

Same results. 😕

@aizuyan
Copy link

aizuyan commented Jan 28, 2018

➜  testChromium node t.js
Detected window.innerWidth to be 800.
➜  testChromium node t.js
Detected window.innerWidth to be 800.
➜  testChromium node t.js
Detected window.innerWidth to be 800.
➜  testChromium node t.js
Detected window.innerWidth to be 800.
➜  testChromium node t.js
Detected window.innerWidth to be 800.
➜  testChromium node t.js
Detected window.innerWidth to be 800.
  • Puppeteer: 1.0.0
  • Platform / OS: Darwin localhost 17.2.0 Darwin Kernel Version 17.2.0
  • Node.js: v9.3.0
  • Chromuim: 66.0.3334.0

@aslushnikov
Copy link
Contributor

@alixaxel @aizuyan interesting. Can you guys share your user scenario?

@aizuyan
Copy link

aizuyan commented Jan 29, 2018

@aslushnikov THX, I want to create a page demo, show the full page to someone else, but now only show part of viewport.

@alixaxel
Copy link
Contributor Author

@aslushnikov Actually I would just like to use this while developing.

I almost always use Chrome maximized, and while developing with PPTR, one of several things happen:

  • I leave viewport/window size untouched and I often end up with mobile media queries
  • I set a fixed viewport size but window size is smaller, causing horizontal scroll
  • I set a fixed viewport size and full screen window, causing large part of the screen to be blank

It is helpful to have PPTR match the behavior of my Chrome, no matter which computer/resolution I'm at.

Granted, it's not a huge issue, but I find the inconsistency intriguing.

@aizuyan
Copy link

aizuyan commented Jan 30, 2018

when i delete some code, that be ok:

file lib/Page.js

line 56~58

code

// Initialize default page size.
if (!appMode)
    await page.setViewport({width: 800, height: 600});

I think maybe the setViewport don't go into effect when i call it in my code.

@alixaxel
Copy link
Contributor Author

alixaxel commented Jan 30, 2018

@aizuyan You don't need to delete it, can just pass appMode: true to Browser options:

https://github.com/GoogleChrome/puppeteer/blob/f2b6016354670ed8300285e0ae25894e3bc5c8e9/lib/Launcher.js#L68-L69

However, I have no idea what this option is for, it's not documented anywhere.


BTW, care to clarify what you mean by "that be ok"?

@aizuyan
Copy link

aizuyan commented Jan 30, 2018

@alixaxel
Thanks very much.
I mean I can create a page demo that show 100% viewport.

my english is poor 😶🙃🙂

@aslushnikov
Copy link
Contributor

I can't reproduce this as of puppeteer v1.7.0. @alixaxel is this still relevant to you?

P.S. There's now a defaultViewport: null option that you can pass to puppeteer.launch to disable viewport overrides.

@aslushnikov aslushnikov added the chromium Issues with Puppeteer-Chromium label Dec 6, 2018
@o0101
Copy link

o0101 commented Feb 4, 2020

I work around this by setting the Browser.setWindowBounds

to {width: width, height: height + 64}

where I guess 64 to approximate the window chrome above the tab viewport in regular headful chrome.

@o0101
Copy link

o0101 commented Feb 4, 2020

This helps prevent the irregularity of Emulation.setVisibleSize sometimes reverts back to the window bounds when in headful mode. I have not seen this happen in headless mode.

@zmorris
Copy link

zmorris commented Nov 17, 2020

I was struggling with a similar issue (trying to resize the viewport in headless), but thanks to aslushnikov's answer on another thread I was able to use this workaround function for both headful and headless modes:

async function setWindowSize(page, width, height) {
  if(headless) {
    const session = await page.target().createCDPSession();
    const {windowId} = await session.send('Browser.getWindowForTarget');
    await session.send('Browser.setWindowBounds', {windowId, bounds: {width: width, height: height}});
    await session.detach();
  } else {
    await page.setViewport({width: width, height: height});
  }
}

Apologies that it isn't the most idiomatic async Javascript code..

I would use Browser.setWindowBounds() everywhere, but unfortunately it has inconsistent behavior in headful. It doesn't seem to account for the dimensions of UI elements like the address bar and navigation controls. Which would make sense since those probably don't exist in headless mode.

Maybe someone can put together a workaround that measures the width/height differences between the two methods upon the first call in headful, then accounts for those differences during subsequent calls. That way Browser.setWindowBounds() could be used everywhere until the Puppeteer devs get time to fix this.

Note that the width also seems to be inconsistent, but that could be due to css rules in my project. Also the sizes are different between headless and headful, so to avoid a bunch of false positives, you'll need to run your tests completely in one mode or the other for now. In my case that's fine, since I was just trying to make window resizing work headless.

If any of the devs read this, please please remove all runtime differences due to implementation details between headful and headless. We shouldn't have to worry about the window bounds not working just because we're running headless. I realize that this is probably a goal of yours, and that you probably have your hands tied by the Chrome devs not realizing the we still need to resize windows during development:

https://bugs.chromium.org/p/chromium/issues/detail?id=2091

@LeviPesin
Copy link
Contributor

LeviPesin commented Jun 9, 2022

Maybe someone can put together a workaround that measures the width/height differences between the two methods upon the first call in headful, then accounts for those differences during subsequent calls. That way Browser.setWindowBounds() could be used everywhere until the Puppeteer devs get time to fix this.

The only workaround I found to be working is manually adding 16 to the width and 133 to the height (these numbers are different on different platforms...). Does anyone find a more automatic workaround?

I tried setting bounds and then measuring client width and height (by Page.getLayoutMetrics, by document.documentElement, by screenshoting the page) and setting bounds again, but for some reason client width and height are the same as the values set.

@LeviPesin
Copy link
Contributor

by screenshoting the page

I guess I forgot to disable defaultViewport option. Will try to compile a workaround with it...

@LeviPesin
Copy link
Contributor

LeviPesin commented Jun 10, 2022

So, I have found a workaround, but it requires capturing screenshot in the fromSurface: false mode which is not supported by Puppeteer until #8496:

const { windowId } = await session.send( 'Browser.getWindowForTarget' );
await session.send( 'Browser.setWindowBounds', { windowId, bounds: { width, height } } );
const { width: clientWidth, height: clientHeight } = ( await jimp.read( await captureFromSurfaceFalse( session ) ) ).bitmap;
await session.send( 'Browser.setWindowBounds', { windowId, bounds: { width: 2 * width - clientWidth, height: 2 * height - clientHeight } } );

It works with defaultViewport, because fromSurface ignores it.

@LeviPesin
Copy link
Contributor

LeviPesin commented Jun 10, 2022

If desired, I can make a PR with this workaround after #8496 will be merged. /ping @jrandolf @OrKoN

@LeviPesin
Copy link
Contributor

LeviPesin commented Jun 10, 2022

Seems like the fromSurface: false adds a Windows applications "shadow" to the top of the image (but it does not break the workaround, I think)... Also, it seems to screenshot scrollbars... (--hide-scrollbars options can be used)

@stale
Copy link

stale bot commented Aug 15, 2022

We're marking this issue as unconfirmed because it has not had recent activity and we weren't able to confirm it yet. It will be closed if no further activity occurs within the next 30 days.

@yanghoxom
Copy link

You can think about '--window-size=375,667', if you want set width height in initialize state

@OrKoN OrKoN added the P3 label May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug chromium Issues with Puppeteer-Chromium confirmed P3 upstream
Projects
None yet
Development

No branches or pull requests

9 participants