71

I would like my webpage's viewport width to equal device-width as long as device-width > 450px, or 450px otherwise (my layout dynamically scales, but doesn't look good below 450px wide).

The following two meta tags work well on tablets, where the device-width > 450px:

<!-- uses device width -->
<meta name="viewport" content="width=device-width" />

<!-- use of initial-scale means width param is treated as min-width -->
<meta name="viewport" content="width=450, initial-scale=1.0" />

however, on phones (where e.g. device-width=320px) the former is too thin for the content; and the latter causes the browser to zoom in, so the user has to manually zoom out to see the content.

Alternatively, this meta tag works well on phones

<meta name="viewport" content="width=450" />

but doesn't take advantage of the extra width available on tablets.

Any help/ideas would be really appreciated (and if it makes a difference, I'm using GWT).

Tom G
  • 2,025
  • 3
  • 21
  • 32

7 Answers7

39

So you want to change the viewport tag's width dynamicaly .

Here you go :

<meta id="myViewport" name="viewport" content="width = 380">
<script>
window.onload = function () {
    var mvp = document.getElementById('myViewport');
    mvp.setAttribute('content','width=580');
}
</script> 

See:http://www.quirksmode.org/mobile/tableViewport.html

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • 9
    This worked perfectly: . The page [here](http://www.quirksmode.org/blog/archives/2011/06/dynamically_cha.html) gives more details, and the page [here](http://www.quirksmode.org/mobile/viewports.html) is a brilliant explanation of viewports. Thanks to everyone for all the help and pointing me in the right direction. – Tom G Feb 24 '13 at 14:22
  • 1
    How is this solving the problem? Setting the viewport-width to a fixed size is not interpreted as minimum size! f.e. on iPad doesn't give the site more space. Further the suggested code in the answer is not complete. – Andy Aug 13 '14 at 09:09
  • @Andy No one provide complete project code. Pseudo code is enough for programmers to grab the concept. If you want, let me know. I'l give you the full code. – Suresh Atta Sep 02 '14 at 07:01
  • 1
    @sᴜʀᴇsʜᴀᴛᴛᴀ this is not pseudo-code, it's JavaScript code. And it's just incomplete, therefore not a solution – Andy Sep 18 '14 at 09:12
  • 1
    See my answer for the full code. I don't really see the point in hiding 5 lines of code. Also, there's no need to wait until onload before changing the viewport. – CpnCrunch Nov 10 '15 at 20:49
  • Also note that you have to use screen.width, as window.innerWidth gives incorrect value on iphone. screen.width seems to work properly on all devices as far as I can see. – CpnCrunch Nov 10 '15 at 21:00
25

Try this:

<meta id="vp" name="viewport" content="width=device-width, initial-scale=1">
<script>
window.onload = function() {
    if (screen.width < 450) {
        var mvp = document.getElementById('vp');
        mvp.setAttribute('content','user-scalable=no,width=450');
    }
}
</script>

Note that I have swapped the initial-scale=1, as I think you had it the wrong way round. You want initial-scale to be set to 1 when width=device-width, so that the page fits exactly in the window. When you set a specific viewport width, you don't want to set initial-scale to 1 (otherwise the page will start off zoomed in).

Timo Tijhof
  • 10,032
  • 6
  • 34
  • 48
CpnCrunch
  • 4,831
  • 1
  • 33
  • 31
  • Your 'Note' at the bottom is $$, ty – gmustudent May 01 '17 at 15:28
  • Also, it looks like recent versions of iOS require user-scalable=no, otherwise it sometimes ignores or overrides the width you set. I've updated the answer. – CpnCrunch Dec 01 '17 at 17:57
  • Don't use `user-scalable=no` as it's not accessible (though most browsers in fact ignore it and let you zoom in anyways) use `minimum-scale=1` instead – Tofandel Feb 22 '23 at 17:20
5

use a @media tag and css. It works wonders. Although it does not supply a minimal width to the view port, this is the preferred way to go.

Here is what I do for the viewport:

<meta name="viewport" content="initial-scale=1.0, width=device-width, user-scalable=yes, minimum-scale=1.0, maximum-scale=2.0">

Then I adjust the size for the panel attached to the viewPort:

@media all and (max-width: 1024px) {
    /*styles for narrow desktop browsers and iPad landscape */
       .myContentPanel{
         width: 450;
    }    
}


@media all and (max-width: 320px) {
   /*styles for iPhone/Android portrait*/
      .myContentPanel {
         width: 320;
    }

}

Obviously you can have intermediate sizes too...

here's more in another example

msoft
  • 579
  • 5
  • 21
user1258245
  • 3,639
  • 2
  • 18
  • 23
  • hi, thanks for the quick reply. I understand that media queries can be used to alter CSS and change the size of the content div. I just don't really understand how this affects the viewport? i.e. I've tried what you suggested (and removed the viewport meta tag), but when I look at it on my phone (Android) it just makes the content smaller, with lots of empty space around it. – Tom G Feb 23 '13 at 16:56
  • Hi Tom, see the revised answer. It was late last night ... anyway ... I use CSS to set the size of the panel on the viewport (not the viewport itself which is set to screen size). So for smaller screens, the panel will scroll to show the content if it doesn't fit. It works nicely when rotating the screen too. – user1258245 Feb 24 '13 at 01:02
  • the javascript approach in the accepted answer is what I was looking for (changes the viewport rather than the layout). Thanks though, I didn't know about media queries before. – Tom G Feb 24 '13 at 14:46
  • But your accepted answer does not work in firefox mobile, and who knows where else.... – jacmkno Jul 23 '14 at 15:00
  • @jacmkno Did you notice that the with pixels don't have a "px" suffix? Maybe that's why. – galva Aug 22 '19 at 09:49
5

The JavaScript code given in the other answers doesn't work in Firefox, but it will work if you remove the meta tag and insert a new one.

<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
if (screen.width < 450){
    var viewport = document.querySelector("meta[name=viewport]");
    viewport.parentNode.removeChild(viewport);

    var newViewport = document.createElement("meta");
    newViewport.setAttribute("name", "viewport");
    newViewport.setAttribute("content", "width=450");
    document.head.appendChild(newViewport);
}
</script>

Or just always insert it in JavaScript:

<script>
var viewport = document.createElement("meta");
viewport.setAttribute("name", "viewport");
if (screen.width < 450) {
    viewport.setAttribute("content", "width=450");
} else {
    viewport.setAttribute("content", "width=device-width, initial-scale=1");
}
document.head.appendChild(viewport);
</script>

For my sanity, I wrote a polyfill to just add a min-width attribute to the viewport meta tag:

Set min-width in viewport metatag

With this, you could just do:

<meta name="viewport" content="width=device-width, initial-scale=1.0, min-width=450" />
<script type="text/javascript" src="viewport-min-width.js"></script>
Community
  • 1
  • 1
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
  • 1
    You should always have the viewport meta in your page (as example 1), as Google doesn't like when it is missing (example 2). – Rauli Rajande Aug 22 '17 at 09:33
1

In short, there is no need to set min-width on viewport because you can set it on body or html element instead, to make them and their content wider than viewport. User will be able to scroll or zoom out content.

body {
  min-width: 450px;
}

I did some tests in Chrome for Android and it scales fonts of some elements up if viewport width is set to anything other than device-width. Also shrink-to-fit=yes is useful to have a page zoomed out initially.

Lastly, this approach supports desktop browsers that can have strange window sizes or current zoom settings (both of which affect reported viewport dimensions), but don't honor the viewport meta tag.

Andrew Svietlichnyy
  • 743
  • 1
  • 6
  • 13
1

Extending @Brendan and other's answer. The viewport size doesn't adjust again on orientation (portrait, landscape) change. To cater this, add an event listener on orientation change and resize again.

<script>
      const resize = () => {
        if (screen.width < 450) {
          var viewport = document.querySelector("meta[name=viewport]");
          viewport.parentNode.removeChild(viewport);
    
          var newViewport = document.createElement("meta");
          newViewport.setAttribute("name", "viewport");
          newViewport.setAttribute(
            "content",
            "width=450, maximum-scale=1.0, user-scalable=no"
          );
          document.head.appendChild(newViewport);
        }
      };
      resize();
      window.addEventListener("orientationchange", resize);
</script>
artsnr
  • 952
  • 1
  • 10
  • 27
-1

I just removed initial-scale=1 and perfectly working on Android Chrome and built-in browsers. No unexpected zoom anymore! :)

<meta name='viewport' content='width=device-width'>
Mikey
  • 1
  • 2