My hobby recently has been making website scale better on phones, but I ran into a problem on several of them: The viewport meta tag assumes that a website either has a fixed width or that it scales to any possible width. I investigated several solutions and eventually settled on an (apparently) novel one: Check the screen size, and if it's too small, add a new meta tag with a fixed viewport. I also wrote a JavaScript polyfill that lets me just set a min-width in the viewport tag.

Why I needed a different solution

Assume I have a website that scales nicely down to 500px. I want it to use any available screen real estate, but never try to render below that size.

My solution

Changing the viewport meta tag was a good idea, and the only change I made is realizing that Firefox will use a viewport tag added in JavaScript. This means the trivial solution is to just add your tag with JavaScript:

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

But, having JavaScript in the header to deal with this isn't ideal, so I experimented and found that as long as I remove the previous viewport, I can add another. With that in mind, I decided to just add the missing min-width attribute with a polyfill:

var viewport = document.querySelector("meta[name=viewport]");
if (viewport) {
    var content = viewport.getAttribute("content");
    var parts = content.split(",");
    for (var i = 0; i < parts.length; ++i) {
        var part = parts[i].trim();
        var pair = part.split("=");
        if (pair[0] === "min-width") {
            var minWidth = parseInt(pair[1]);
            if (screen.width < minWidth) {
                document.head.removeChild(viewport);

                var newViewport = document.createElement("meta");
                newViewport.setAttribute("name", "viewport");
                newViewport.setAttribute("content", "width=" + minWidth);
                document.head.appendChild(newViewport);
                break;
            }
        }
    }
}

This just finds your viewport meta tag, checks if it contains min-width. If the min-width is less than the screen width, it replaces the meta tag with a fixed one.

If you want to use this in your own code, just get the JavaScript file from the GitHub repo and do this:

<meta name="viewport" content="width=device-width, initial-scale=1, min-width=500"/>
<script type="text/javascript" src="viewport-min-width.js"></script>

At some point I'll probably make this polyfill support max-width, and also leave other attributes alone (although you really shouldn't use any of the others, since preventing user scaling is annoying). If you want to implement any of this, feel free to send me a pull request.