{"id":13451748,"url":"https://github.com/WICG/visual-viewport","last_synced_at":"2025-03-23T19:32:37.824Z","repository":{"id":5904891,"uuid":"54214664","full_name":"WICG/visual-viewport","owner":"WICG","description":"A proposal to add explicit APIs to the Web for querying and setting the visual viewport","archived":false,"fork":false,"pushed_at":"2024-03-18T15:26:02.000Z","size":195,"stargazers_count":176,"open_issues_count":20,"forks_count":28,"subscribers_count":17,"default_branch":"gh-pages","last_synced_at":"2024-07-02T14:47:04.915Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://wicg.github.io/visual-viewport/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WICG.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-03-18T16:09:47.000Z","updated_at":"2024-05-20T08:43:05.000Z","dependencies_parsed_at":"2024-01-16T03:46:01.162Z","dependency_job_id":"3eee6aef-2ca5-4296-ad2c-6f01c7cc4e6d","html_url":"https://github.com/WICG/visual-viewport","commit_stats":{"total_commits":126,"total_committers":15,"mean_commits":8.4,"dds":"0.32539682539682535","last_synced_commit":"44deaba64b1c2c474bf5a4ece07eefa93b2fb028"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WICG%2Fvisual-viewport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WICG%2Fvisual-viewport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WICG%2Fvisual-viewport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WICG%2Fvisual-viewport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WICG","download_url":"https://codeload.github.com/WICG/visual-viewport/tar.gz/refs/heads/gh-pages","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213325083,"owners_count":15570231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T07:01:01.221Z","updated_at":"2024-07-31T07:04:05.586Z","avatar_url":"https://github.com/WICG.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# Visual Viewport API\n\n## tl;dr\n\nWe propose adding a `visualViewport` object on `window` that contains the\nproperties of the visual viewport.  We're incubating this idea via the WICG in\norder to try to make incremental progress on the long-standing problem of\nexposing features like pinch-zoom to web developers in a rational way.  We are\nworking with the CSSWG to eventually get [these\nideas](https://github.com/w3c/csswg-drafts/issues/206) into [the relevant\nspecs](https://github.com/w3c/csswg-drafts/issues/505) as first-class features\nof the web platform.\n\n_Update: The `window.visualViewport` API has shipped in Chrome M61 (Sept. 2017). Follow crbug\n[issue 635031](http://crbug.com/635031) for details._\n\n## Spec\n\n## Draft Spec\n\n~~[Draft Spec](https://wicg.github.io/visual-viewport/index.html)~~\n\nNow merged upstream to [CSSOM-View](https://drafts.csswg.org/cssom-view/#visualViewport)\n\n## Background\n\nThe mobile web contains two viewports, the Layout and Visual viewport. The\nLayout viewport is what a page lays out its elements into(*) and the Visual\nviewport is what is actually visible on the screen. When the user pinch-zooms\ninto the page, the visual viewport shrinks but the layout viewport is\nunchanged. UI like the on-screen keyboard (OSK) can also shrink the visual\nviewport without affecting the layout viewport. See this\n[demo](http://bokand.github.io/viewport/index.html) to visualize the two\nviewports. This isn't specified anywhere and implementations vary greatly\nbetween browsers.\n\nCurrently, several CSSOM scroll properties are relative to the visual viewport\n(see\n[this](https://docs.google.com/document/d/1ZzzvA_AuMDa_nlwIc9PdpzfIXsgrOZDixFvEFwrfXJM/edit#)\nfor list). Again, there is no spec governing this, but this is how browsers\n  have it implemented today. With this implementation, the dimensions of the\n  visual viewport can be easily determined (For example, window.innerHeight =\n  visual viewport height). However, all other coordinates are generally\n  relative to the layout viewport (e.g. getBoundingClientRects,\n  elementFromPoint, event coordinates, etc.). Having these APIs be mixed is\n  arbitrary and confusing.\n\nThis confusion has caused many desktop sites to break when pinch-zoomed or when\nshowing the OSK (see [this bug ](http://crbug.com/489206) for examples). This\nis because mobile browsers added new semantics to existing properties,\nexpecting they'd to be invisible to desktop browsers. This becomes a problem as\nthe lines between mobile and desktop blur and features like on-screen keyboard\nand pinch-zoom make their way to desktops, or when accessing desktop pages from\nmobile devices.\n\n(*) - This isn't strictly true. In Chrome, the layout viewport is actually the\n\"viewport at minimum scale\". While on most well behaving pages this is the box\nthat the page lays out into (i.e. the initial containing block), extra-wide\nelements or an explicit minimum-scale can change this. More specifically, the\nlayout viewport is what position: fixed elements attach to.\n\n## Proposed Plan\n\nWe believe the best way forward is to change those remaining CSSOM scroll\nproperties to be relative to the layout viewport. In fact, Chrome did this in\nM48 but, due to [developer feedback](http://crbug.com/571297), this change was\nreverted in M49. There was more reliance on this than anticipated.\n\nIn order to make this transition we propose adding a new explicit API for the\nvisual viewport. With an explicit API, we could once again change the CSSOM \nscroll properties to be relative to the layout viewport. This change would make\nsure existing desktop sites continue to function correctly as new UI features\nare added. At the same time, it would allow authors to use and customize those\nfeatures where needed.\n\nThe new API is also easy to feature detect and polyfilling this behavior should\nbe fairly straightforward.\n\n## Proposed API (v1)\n\n  * Add a `visualViewport` object on `window`.\n\n```\nvisualViewport = {\n    double offsetLeft; // Relative to the layout viewport\n    double offsetTop; // and read-only.\n\n    double pageLeft;  // Relative to the document\n    double pageTop;  // and read-only.\n\n    double width;  // Read-only and excludes the scrollbars\n    double height; // if present. These values give the number\n                   // of CSS pixels visible in the visual viewport.\n                   // i.e. they shrink as the user zooms in.\n\n    double scale;     // Read-only. The scaling factor applied to\n                      // the visual viewport relative to the `ideal\n                      // viewport` (size at width=device-width). This\n                      // is the same scale as used in the viewport\n                      // \u003cmeta\u003e tag.\n    \n    FrozenArray\u003cDOMRect\u003e segments; // Read-only. Returns an array of \n                                   // DOMRects that represent the dimensions \n                                   // of each existing viewport segment.\n\n}\n```\n\n  * Fire a `scroll` event against `window.visualViewport` whenever the `offsetLeft` or `offsetTop` attributes change.\n\n  * Fire a `resize` event against `window.visualViewport` whenever the `width` or `height` attributes change.\n  \n  * The viewport segments property is currently in development and experimental. Please view the [segments explainer](https://github.com/WICG/visual-viewport/tree/gh-pages/segments-explainer) for more details. \n\n## Example\n\nHere's how an author might use this API to simulate `position: device-fixed`, which fixes elements to the visual viewport.\n\n[Live example from below](https://wicg.github.io/visual-viewport/examples/fixed-to-viewport.html)\n\n```html\n\u003cmeta name=\"viewport\" content=\"width=device-width\"\u003e\n\u003cstyle\u003e\n    #layoutViewport {\n        position: fixed;\n        width: 100%;\n        height: 100%;\n        visibility: hidden;\n    }\n    #bottombar {\n        position: fixed;\n        left: 0px;\n        right: 0px;\n        bottom: 0px;\n        background-color: red;\n        transform-origin: left bottom;\n        transform: translate(0px, 0px) scale(1);\n    }\n    #forcescrolling {\n        width: 100px;\n        height: 2000px;\n        background-color: green;\n    }\n\u003c/style\u003e\n\n\u003cbody\u003e\n    \u003cdiv id=\"bottombar\"\u003eThis stays stuck to the visual viewport\u003c/div\u003e\n    \u003cdiv id=\"forcescrolling\"\u003e\u003c/div\u003e\n    \u003cdiv id=\"layoutViewport\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n\n\u003cscript\u003e\n    var bottomBar = document.getElementById('bottombar');\n    var viewport = window.visualViewport;\n    function viewportHandler() {\n        var layoutViewport = document.getElementById('layoutViewport');\n\n        // Since the bar is position: fixed we need to offset it by the visual\n        // viewport's offset from the layout viewport origin.\n        var offsetLeft = viewport.offsetLeft;\n        var offsetTop = viewport.height\n                    - layoutViewport.getBoundingClientRect().height\n                    + viewport.offsetTop;\n\n        // You could also do this by setting style.left and style.top if you\n        // use width: 100% instead.\n        bottomBar.style.transform = 'translate(' +\n                                    offsetLeft + 'px,' +\n                                    offsetTop + 'px) ' +\n                                    'scale(' + 1/viewport.scale + ')'\n    }\n    window.visualViewport.addEventListener('scroll', viewportHandler);\n    window.visualViewport.addEventListener('resize', viewportHandler);\n\u003c/script\u003e\n```\n## Other Examples\n\nHere's a few other examples you can try out on Chrome Canary today. Be sure to turn on the following flags:\n\n  * chrome://flags/#enable-experimental-web-platform-features (Enable window.visualViewport)\n  * chrome://flags/#inert-visual-viewport (Makes window.scrollX|innerWidth and others refer to layout viewport)\n  * chrome://flags/#enable-osk-overscroll (Makes keyboard resize visual viewport only)\n\n### Links\n\n  * [Hide on Zoom](https://wicg.github.io/visual-viewport/examples/hide-on-zoom.html): Overlays a position: fixed\n    box in the viewport (e.g. an ad) but hides to improve the UX when the user zooms in.\n  * [Fixed to keyboard](https://wicg.github.io/visual-viewport/examples/fixed-to-keyboard.html): Keeps a bar (e.g.\n    text formatting toolbar) fixed to the keyboard when it comes up.\n  * [Fixed to keyboard (No Zoom)](https://wicg.github.io/visual-viewport/examples/fixed-to-keyboard-no-zoom.html):\n    Same as above but makes the bar behave like position: fixed rather than position: device-fixed. That is, the\n    bar will stay above the keyboard, but if the user zooms in it will remain in its original position.\n  * [Fixed to viewport](https://wicg.github.io/visual-viewport/examples/fixed-to-viewport.html): Simulates position:\n    device-fixed by keeping a bar fixed to the visual viewport.\n  * [Fixed to viewport (absolute)](https://wicg.github.io/visual-viewport/examples/absolute-fixed-to-viewport.html):\n    Uses position: absolute to accomplish a position: sticky type effect that works with pinch-zoom.\n\n### Polyfill\n\n  TODO: Doesn't work on iOS Safari yet.\n  We've added a rudimentary polyfill that should work across browsers, albeit with worse\n  performance properties (requires polling and ugly hacks). The polyfill itself is\n  [visualViewport.js](https://github.com/WICG/visual-viewport/blob/gh-pages/polyfill/visualViewport.js)\n  and you can see two examples that use it in the same directory:\n\n  * [position: device-fixed with position: fixed](https://wicg.github.io/visual-viewport/polyfill/vvapi-fix.html)\n  * [position: device-fixed with position: absolute](https://wicg.github.io/visual-viewport/polyfill/vvapi-abs.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWICG%2Fvisual-viewport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FWICG%2Fvisual-viewport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWICG%2Fvisual-viewport/lists"}