Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a fluid line break on mobile browsers even when zooming?

Tags:

html

css

How can I get a fluid line break on mobile browsers even when zooming?

I have a very simple web page with only one column of text. Here are the relevant parts of the CSS:

/* ✂---------------- */

body {
    /* To avoid problems with some older browsers, that do not calculate
    * relative values correctly without this statement. */
    font-size: 100%;
    /* ✂---------------- */
    /* Center the content and leave a margin at the left and at the right. */
    margin-left: auto;
    margin-right: auto;
    /* ✂---------------- */
}

/* ✂---------------- */

@media not print {
    body {
        /* ✂---------------- */
        /* Do not put too many words in a single line: */
        width: 41em;
        /* Avoid horizontal scrolling, and leave a small margi
        * at the left and at the right. */
        max-width: 90%;
    }

    /* ✂---------------- */

}

/* ✂---------------- */

The aim is:

  1. Not use fixed font sizes but respect the default font size that the user has chosen in the settings of his browser

  2. If the width of the browser window is very big, then do not make the lines too wide (too many characters). Instead, leave space at the left and at the right.

  3. If the width of the browser window is small (=not enough space to show 41em of text in the current font size at the current zoom level), then use a line break for exactly the whole width of the browser window (with a small margin of (100% − 90%) ÷ 2 = 5% at the left and at the right), avoiding horizontal scrolling.

  4. If the user zooms in or zooms out, the line break gets adapted correctly. So even when the user zooms in really much, there is no horizontal scrolling necessary because the length of the line is not wider than the browser window.

This works fine on desktop browsers. But mobile browsers lie about the viewport. They claim to have a viewport of about eight hundred pixels instead of the real browser window width (this is the “layout viewport” – different from the real “visual viewport” – see http://www.quirksmode.org/mobile/viewports2.html for details). So, for mobile browsers, I’ve added <"viewport" content="width=device-width, initial-scale=1"/> in the HTML and

@viewport {
    /* 100% of viewport’s width */
    width: 100vw;
    zoom: 1.0;
}

in the CSS. Now, aim #1, 2 and 3 work also on Firefox Mobile. But aim #4 doesn’t. The line break does not change on recent Firefox Mobile when zooming in or zooming out. (Fun fact: On my old Android 2.3.6 standard browser, it works.) I suppose that the layout viewport width on mobile browsers is determined once the <meta> tag has been read and this layout viewport’s CSS pixel width does not change any more when the user zooms in or zooms out (opposed to desktop browsers, that adopt their viewport when zooming). As the max-width: 90%; is relative to the viewport (as this is the surrounding container), the line break does not change any more when zooming in or zooming out. Try http://ryanve.com/lab/dimensions/ that displays some DOM values using JavaScript. When you run this site on a desktop browser, you see that window.innerWidth changes when you zoom in or when you zoom out. If you do the same thing on mobile browsers, the value of window.innerWidth does not change when zooming in or out. As far as I see, this behaviour seems also to be the standard behaviour on modern mobile browsers and mobile web pages in general. This seems to be a deliberate choise of the developers of the mobile browers (they want to be able to show also old, desktop-optimized non-responsive web pages), but the downside is that you can work only with the virtual “layout viewport”.

And as far as I know, there are no measurement units in CSS that are relative to the real “visual viewport” size instead of the virtual “layout viewport”.

So my questions are:

  1. I wonder if there is any clean and standard-conform possibility at all for a web page to get this (zoom + fluid line break) working on mobile browsers just like on the desktop version?

  2. If there is such a possibility, how exactly could that work (preferred without JavaScript)? Is the only possibility a dirty hack that estimates the zoom factor (which itself is as far as I know not cross-browser accessible in JS) on mobile browsers by calculating “visual viewport width” ÷ “screen width” and adopts the viewport accordingly?

like image 368
Lukas Sommer Avatar asked Nov 09 '22 23:11

Lukas Sommer


1 Answers

Short answer: It’s not possible. (But there is a workaround.)

Long answer:

Apparently it is not possible to have dynamic resizing of the layout viewport on mobile browsers.

Quirksmode gives an introduction to the different viewports (layout viewport vs. visual viewport): http://www.quirksmode.org/mobile/viewports.html http://www.quirksmode.org/mobile/viewports2.html

It seems to be a deliberate choice of the mobile browsers not to adapt the layout viewport size on zoom.

There are some efforts to bring zoom and viewport handling to CSS (substituting the ugly Meta-Viewport-tag in HTML):

https://drafts.csswg.org/css-device-adapt/#zoom-desc http://www.quirksmode.org/blog/archives/2015/09/a_new_device_ad.html

But even when this would be implemented by the browsers, it would still not give control about what happens to the layout viewport size during zoom.

Workaround: Make two buttons or links named “bigger” and “smaller” on the webpage. Use them to call a JavaScript (ECMAScript) and change the text size. Most simple case: The size of all your content is relative to the font size of the <body> element; if so, you just have to change this font size. Code:

<!-- The CSS is assumed to apply “display=none” to the elements
with class="no-print" when used for printing. -->
<p class="no-print">
  <!-- Some text size tools.
  The CSS is assumed to apply “display=none” to the elements
  with id="textSizeTools". So the text size tools are
  by default invisible and do not take any space in the default
  rendering. -->
  <span id="textSizeTools">
    <span class="linkStyle zoomInCursor" onclick="javascript:resizeText(true)">
      [größer]
    </span>
    –
    <span class="linkStyle zoomOutCursor" onclick="javascript:resizeText(false)">
      [kleiner]
    </span>
  </span>
</p>
<script>
  /* document.body.style.fontSize is empty – though “font-size=100%” is set in
   * the CSS. We initialize it here with the value "100%", that
   * corresponds to our CSS entry . From
   * now on, the value is available in ECMAScript. */
  document.body.style.fontSize = "100%";
  var resizeText = (function () {
      'use strict';
      var step = 0;
      return function (bigger) {
          if (bigger !== true) {
              step -= 1;
          } else {
              step += 1;
          }
          document.body.style.fontSize = 100 * Math.pow(1.2, step) + "%";
      };
  }());
  /* If the browser is scripting-enabled, than this script will be executed
   * and the text size tools will become visible. If the browser is not scripting-enabled,
   * than this script will not be executed and the text size tools will stay hidden.
   * This is intentional, because without scripting, the text size tools would not
   * work, and it is not good if the user can see buttons and links that
   * do not work. The same is if this script does not work because some
   * of the commands do not work in the current browser: The script cannot
   * be executed until here, so the text size tools will not be made
   * visible. */
  document.getElementById("textSizeTools").style.display = 'initial';
</script>
like image 169
Lukas Sommer Avatar answered Nov 15 '22 07:11

Lukas Sommer