13

I'm working on a single-page web app, that will most typically be used on mobile devices. One of its features is a map mode, which temporarily takes over the entire browser window; a distance scale and some controls are attached to the four corners of the map. Here's a little screenshot of the map so you can tell what I'm talking about:

Screenshot of map overlay

The map is implemented as a <div> with position: fixed and all four coordinates zero; I also temporarily set the <body> to overflow: hidden while the map is visible to handle the case of the underlying app display being scrolled away from the origin. That's sufficient to make the map work exactly how I want on desktop browsers. Mobile browsers also required that I give a meta viewport tag with something like "width=device-width,user-scalable=no" in order to make the visible area of the window exactly correspond with the viewport.

This all worked beautifully a few years back when I originally wrote this app, but somewhere along the line iOS Safari stopped honoring any of the meta viewport options involving scaling - apparently too many sites were misapplying the tag, resulting in text that was unreadably small, yet unzoomable. Currently, if you enable the map on this browser, you're likely to get a slightly zoomed-in view, that cuts off those buttons on the right and bottom - and you can't do anything about it, because all touches are interpreted as zoom/pan gestures for the map, rather than browser scrolling. The map isn't terribly useful without the features accessed through those buttons - and without the top-right button, you can't even close the map. The only way out is to reload the page, which may result in loss of unsaved data.

I'm definitely going to be adding the use of history.pushState/onpopstate so that the map overlay behaves like a separate page. You'd be able to get out of the map mode using the browser's Back button - but that doesn't address the rest of the loss of the functionality due to missing buttons.

I've considered using .requestFullscreen() to implement the map overlay, but it's not supported everywhere that the app would otherwise be usable. In particular, it apparently doesn't work at all on iPhones, and on iPads you get a status bar and a huge 'X' button overlaying your content - my distance scale would likely not be readable any more. It's not semantically what I really want, anyway - I need the full window, not the full screen.

How do I get a full-window display working on modern browsers? All the information I can find on the subject talks about using the meta viewport tag, but as I mentioned that no longer works.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • Have you considered responsive design or a CSS grid-layout which is responsive by nature? I am still a newbie so let me know if there is a particular reason why you are not making use of these... – Joehat Dec 04 '19 at 18:54
  • 1
    @Joehat, the bulk of the app *is* responsive; that's not the problem. It's just this map overlay feature that has an issue: touch gestures are used to zoom/pan the map (it's a SVG, generated by d3.js), leaving no way to adjust the browser's zoom and scrolling. It worked just fine back when the browser allowed me to control the viewport. – jasonharper Dec 04 '19 at 19:25
  • 1
    Some basic questions: Are you using a CSS reset? Are there any weird margins or paddings on anything? Is the body set to 100vw x 100vh? Is the body positioned relative for your map div to work with? – itsallgoodie Dec 04 '19 at 20:37
  • @itsallgoodie: no reset; nothing weird that I'm aware of; body has `min-height: 100vh`, no explicit width; I have the `position: relative` on html rather than body. – jasonharper Dec 04 '19 at 20:55
  • 1
    can you please share sample code for this.. i will check and let you know – Ranjith v Dec 05 '19 at 06:48
  • 1
    show your code!! – Nikhil S Dec 05 '19 at 17:46
  • this is a single page, your buttons have fixed positions, so you can use `grid` to determine where the positions of the buttons would be. So create a `div` for the actual map that fits window size (use` css` for that eg 100vw,100vh). Create a grid on a child `div` where the map buttons would be and make it appear on top of map `div`. –  Dec 08 '19 at 14:27
  • In addition for more than suggestions please add some code or create an example fiddle. You will get better answers if you share some code (you should hide/alter some parts that are not for all eyes). –  Dec 08 '19 at 14:29
  • @PeterDarmis, I agree that example code would be a good idea here, but I don't see any way to do so - all of the online HTML sharing tools seem to put your results in an ` – jasonharper Dec 08 '19 at 19:22
  • @jasonharper i understand but your issue is to keep the buttons inside the viewport. That is why i proposed two `div`, one for the layer of the map and one on top for the controls. By using `100vw` and `100vh` as `width` and `height` on the controls `div` you would always keep it inside the page. –  Dec 08 '19 at 20:16
  • @jasonharper if you add `grid` logic on the controls layer you could specify a grid area for the top buttons and bottom buttons and left and right accordingly. Personally i like this guide for `grid` https://css-tricks.com/snippets/css/complete-guide-grid/ if you take a look you may have a nice outcome with the two layer logic. –  Dec 08 '19 at 20:23
  • @PeterDarmis How is 100vw/100vh supposed to help? Even if that made the `
    ` exactly the same size as the visible window (it doesn't, when the browser is in a zoomed state), that wouldn't do anything to make it aligned with the visible window, so I'd still likely have content chopped off on two edges.
    – jasonharper Dec 08 '19 at 23:17
  • 1
    A screenshot or some example of the content that's getting put into this window would really help determine what's going on. – Bryce Howitson Dec 09 '19 at 21:39
  • @jasonharper post some code, that way we could provide solid answers. Regarding `vw` and `vh`, https://css-tricks.com/fun-viewport-units/. Please add some code to give you answers, it is useless to chat about it. –  Dec 10 '19 at 21:33
  • @jasonharper This has been already asked, but it is critical that you share your webpage so that an answer can be provided. I have been in similar situations, and having a working web page with you, makes all the difference. Please see if you can host the page somewhere with limited functionalities and share the link. – Furqan Rahamath Dec 11 '19 at 15:27

9 Answers9

3

if your using position: fixed just use the standard CSS method that has been around for many years.

.divFixedClass{
    position: fixed;
    top:0;
    left:0;
    right:0;
    bottom:0;
}

This will just make the div auto-size to the full size of the viewport, and using possition fixed it's locked in place no matter how much they scroll, you could disable body scroll if you needed to with

html.noScroll, html.noScroll > body{
    overflow:none;
}

so if you just add the noScroll class to the html tag it will disable scrolling. then when you want to allow scrolling again you can.

Barkermn01
  • 6,781
  • 33
  • 83
1

Have you tried these?

width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
Maurici Abad
  • 1,012
  • 9
  • 20
Rajilesh Panoli
  • 770
  • 10
  • 17
  • (I assume you meant `vw` on the width, not `vh`...) What element are you suggesting that I add this to? I tried it in several places (``, ``, and the map `
    `), but saw no differences.
    – jasonharper Dec 05 '19 at 04:43
  • It is for the div. Is there any transform scale or zoom property applied to any element.? – Rajilesh Panoli Dec 05 '19 at 04:50
  • There are no transforms at the HTML level, my map zooming/panning is done by applying translations to the SVG elements composing it. – jasonharper Dec 05 '19 at 04:53
1

You need to set the height of both body and html to 100%

   html, body {
       width: 100%;
       height: 100%;
       margin: 0;
    }
iicaptain
  • 1,065
  • 1
  • 13
  • 37
1

Solution

Set the fullscreen div's height to window.innerHeight with JavaScript and then update it on window resizes.

Same problem here:

https://stackoverflow.com/a/37113430/8662476

More info:

Maurici Abad
  • 1,012
  • 9
  • 20
0

try this:

<meta name="viewport" content="width=device-width, height=device-height , 
initial-scale=1.0,user-scalable=no, shrink-to-fit=yes" />
Nikhil S
  • 3,786
  • 4
  • 18
  • 32
  • This didn't change anything, and I see no reason to expect it to: `shrink-to-fit=yes` is the default, and Safari no longer pays any attention to the scaling options. – jasonharper Dec 04 '19 at 20:11
0

Since I can't comment, I would like to add that you should check if your body tag is the height of the browser. You might also want to check this: Chrome / Safari not filling 100% height of flex parent

trigangle
  • 193
  • 1
  • 9
0

This is an old solution, and addresses a problem that is closely linked, but not exactly the same, so I'm not sure if it applies: https://github.com/gajus/brim

It is supposed to be a solution that is similar to minimal-ui.

Here is another question that references this answer: iOS 8 removed "minimal-ui" viewport property, are there other "soft fullscreen" solutions?

Let me know if this helps at all.

Sam Sabin
  • 553
  • 1
  • 6
  • 19
0

Try following code for div

.class{height:100vh;}
0

You could implement this using two layer structure for your map controls and your map layer. Meaning that you actually don't need any javascript to implement what you want (although no coding example was given in the question). You can manipulate viewport with CSS and that is the actual meaning of vw and vh in order to answer your comment How is 100vw/100vh supposed to help?, it can help since v stands for viewport.

See the snippet for example.

A better example (being more accurate on specific parameters that might be missed) could be provided if some coding was present in the question.

PS: the map layer is simulated by an image that gets zoomed on scroll.

function zoom(event) {
  event.preventDefault();

  scale += event.deltaY * -0.01;

  // Restrict scale
  scale = Math.min(Math.max(.125, scale), 4);
  if (scale < 1) {
    scale = 1;
  }
  // Apply scale transform
  el.style.transform = `scale(${scale})`;
}
let scale = 1;
const el = document.getElementById('map');
el.onwheel = zoom;
.container {
  position: absolute;
   display: flex;
  align-items: center;
  justify-content: center;
  top: 0;
  left: 0;
  overflow: hidden;
  width: 100vw;
  height: 100vh;
  background-color: transparent;
}

#map {
  width: 100vw;
  height: 100vh;
    background-repeat: no-repeat;
  background-position: center center;
  background-image: url(https://picsum.photos/800/500.webp);
  z-index: 1;
}


#main {
  display: grid;
  position: absolute;
  background-color: transparent;
  top: 0;
  left: 0;
  grid-template-columns: 6rem auto 6rem;
  grid-template-rows: 3rem auto 3rem;
  width: 0;
  height: 0;
 z-index: 2;
}

.t-l {
background: #fc0;
  position: fixed;
  z-index: 2;
  color: #000;
  top; 0;
  left: 0;
  width: 6rem;
  height: 3rem;
  display: block;
  grid-column-start: 1;
  grid-column-end: column1-end;
  grid-row-start: 1;
  grid-row-end: row1-end;
}
.t-r {
background: #0cf;
  position: fixed;
  z-index: 2;
  color: #000;
  top; 0;
  left: calc(100vw-6rem);
  right: 0;
  width: 6rem;
  height: 3rem;
  display: block;
  grid-column-start: 3;
  grid-column-end: column3-end;
  grid-row-start: 1;
  grid-row-end: row1-end;
}
.b-l {
background: #c0f;
  position: fixed;
  z-index: 2;
  color: #000;
  bottom: 0;
  top: calc(100vh-3rem);
  left: 0;
  width: 6rem;
  height: 3rem;
  display: block;
  grid-column-start: 1;
  grid-column-end: column1-end;
  grid-row-start: 3;
  grid-row-end: row3-end;
}
.b-r {
background: #cf0;
  position: fixed;
  z-index: 2;
  color: #000;
  top: calc(100vh-3rem);
  left: 100vw;
  margin-left: -6rem;
  bottom: 0;
  width: 6rem;
  height: 3rem;
  display: block;
  grid-column-start: 3;
  grid-column-end: column3-end;
  grid-row-start: 3;
  grid-row-end: row3-end;
}
<div class="container">

  <div id="main">
    <button class="t-l">top left control</button>
    <button class="t-r">top right control</button>
    <button class="b-l">bottom left control</button>
    <button class="b-r">bottom right control</button>
  </div>
<div id="map"></div>
</div>