Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Font size (responsive), relative to device resolution?

Tags:

html

css

Let's say we have the following test.htm:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <style type="text/css">
.testdiv, .testdivB, .testdivC {
  width: 50%;
  height: 30%;
  margin: 6px;
  border: 2px solid gray;
  font-size: 4em;
}
.testdivB {
  font-size: 12px;
}
.testdivC {
  font-size: 30pt;
}
  </style>
</head>

<body>

  <div class="testdiv">Test one writing</div>
  <div class="testdivB">Test another writing</div>
  <div class="testdivC">Test three writing</div>

</body>
</html>

I've tried testing this in Chromium, with the Developer Tools, which allows me to emulate different devices; here:

* Apple iPhone 4        : device resolution  320 x  480 , a/r 0.666667
* Google Nexus 10       : device resolution  800 x 1280 , a/r 0.625
* Amazon Kindle Fire HDX: device resolution 1600 x 2560 , a/r 0.625

the outcome is this:

chrome-test

In this example, all the devices are portrait, and have "nearly" the same aspect ratio (~ 0.6+), even if they have wildly differing resolutions.

So, in the two first cases, I'm getting approximately the same font sizes, as relative to the device screen size, which is what I want to achieve (even though, I'm confused how can testdivB also show as nearly the same size, when it should be smaller) - so that's all good.

But, in the third example, which is on a device with the largest resolution, testdivB unsurprisingly (as it is defined in px) is much smaller relative to the device screen size; testdivA is also not really surprising, since em is relative to the "computed font-size" of the browser - and that one, if I remember correctly, is also expressed in pixels.

However, I thought that pt would have taken the device screen resolution into account, but it looks like it doesn't:

http://www.w3.org/Style/Examples/007/units.en.html

In the past, CSS required that implementations display absolute units correctly even on computer screens. But as the number of incorrect implementations outnumbered correct ones and the situation didn't seem to improve, CSS abandoned that requirement in 2011. Currently, absolute units must work correctly only on printed output and on high-resolution devices.

Ok, so what options do I have, to achieve approximately the same font sizes (as relative to device screen sizes) in all three cases:

  • If I don't want to use JavaScript (only HTML + CSS)?
  • If I do want to use JavaScript (I'd guess there's a way to query for device screen - not viewport - resolution, but I'm not sure if there really is one)?
like image 456
sdbbs Avatar asked Dec 09 '16 13:12

sdbbs


People also ask

What is the best font size unit for responsive design?

Rem is an absolute unit relative to the root element of the HTML document and is commonly used for font sizes. It is a scalable unit in which the browser renders into pixel values. I recommend it for responsiveness. The default root element font size is 16px.

How do I set relative font size in CSS?

If the font-size you want is 12px , then you should specify 0.75em (because 12/16 = 0.75). Similarly, if you want a font size of 10px , then specify 0.625em (10/16 = 0.625); for 22px , specify 1.375em (22/16).

How does font size relate to pixels?

Font size specifications may come in points or pixels where: 1 pixel (px) is usually assumed to be 1/96th of an inch. 1 point (pt) is assumed to be 1/72nd of an inch. Therefore 16px = 12pt.


2 Answers

I've written a small tutorial / example on how to achieve this with pure HTML/CSS a while ago:

Responsive units (vmin/vmax)

#small {
    font-size: calc(1em + 1vmin);
}

#medium {
    font-size: calc(1em + 2vmin);
}

#large {
    font-size: calc(1em + 3vmin);
}
<div id="small">Small text</div>
<div id="medium">Medium text</div>
<div id="large">Large text</div>

The rule vmin is quite useful in your context. It takes vmin: 1/100th of the smallest side of your screen. Regardless of orientation. Combining it with the basic 1em in a calc() gives us a great way of applying a small custom responsive aspect on the font-size.

Alternative approach (vw/vh)

#small {
    font-size: calc(1em + 1vw);
}

#medium {
    font-size: calc(1em + 2vw);
}

#large {
    font-size: calc(1em + 3vw);
}
<div id="small">Small text</div>
<div id="medium">Medium text</div>
<div id="large">Large text</div>

If you wish to apply more control regarding the actual aspect ratio, I'd advise going with vw over vmin. Viewport width (vw) takes 1/100th of the width of your viewport.

Responsive units based on viewport aspect ratio (both vmin and vmax):

#test1 {
    font-size: calc((.4em + 1vmin) + (.4em + 1vmax));
}

#test2 {
    font-size: calc((.4em + 2vmin) + (.4em + 2vmax));
}

#test3 {
    font-size: calc((.4em + 3vmin) + (.4em + 3vmax));
}
<div id="test1">Small text</div>
<div id="test2">Medium text</div>
<div id="test3">Large text</div>

I'm quite happy with this solution, this way allows us to take both the viewports width, and it's length into account. We divide the base font size in two (.4em in this case) and multiply it with both 1vmin and 1vmax, after that- we add both values to establish the font size.

like image 155
roberrrt-s Avatar answered Sep 18 '22 19:09

roberrrt-s


Ok, I think I came to a solution which I can use, which uses JavaScript. With the code pasted below, I now get this when testing in different devices in Chromium Developer Tools:

devtools-test-2

As one can see, the relative size for the first div, .testdiv with a specification in em now is preserved across device sizes (which is what I wanted); px in the second div, as expected doesn't preserve relative size -- and neither does the third case with pt specification.

The first problem I had, was how to get the device resolution. Note that vw, vh - and thus vmin and vmax - are in respect to the viewport size, that is, the window size. This is not so much of a problem in mobile, as the browsers on mobile typically start in "fullscreen" (I'm not even sure it is possible to resize the browser/app window on mobile, iOS or Android) - but it might be a problem if using a browser on the desktop, where the browser might end up not being in full screen.

Thankfully, one can get the device resolution using JavaScript, ( How to detect the screen resolution with JavaScript? ), and in this case, I get the device width and height in pixels - and from them, I calculate devicemin as the smaller of the two (similar to vmin). Then I set a "base font size", font size of the <html> element, to 2.67% of devicemin (this was my own arbitrary choice) in pixels. That would, hopefully, make sure that I have the same font size, relative to device resolution, across devices with different resolution.

Second issue, somewhat unexpected for me, was that you must have a <meta name="viewport" content="width=device-width, initial-scale=1.0"/> entry/directive in the head! Otherwise, without it, iOS browser will just apply their own font-sizes/scaling, and thus we'd get an unexpected result like:

devtools-ios-no-viewport

I was in fact so surprised at this result in Chromium Developer Tools, that I had to try the test in an Xcode iOS simulator - and surprisingly enough, the Chromium Developer Tools, actually did simulate this behavior the same as the iOS simulator did (left image is the code below in Developer Tools, right one is OP code in iOS simulator). For more on this, see Some font-size's rendered larger on Safari (iPhone) ...

Anyways, now that I have the "base" font size like this, I can proceed and implement responsive design based on say width <20em, <40em etc - and be sure that these sizes will refer to approximately the same relative area on any screen device...

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <!-- MUST have, so iPhone doesn't autozoom and change the fontsize! -->
  <script type="text/javascript">
  // https://stackoverflow.com/questions/2242086/how-to-detect-the-screen-resolution-with-javascript
  var devicewidth = window.screen.width;
  var deviceheight = window.screen.height;
  var devicemin = Math.min(devicewidth, deviceheight);
  // say we want base font size: 16px @ 600px (min of 800x600); 16/600 = 0.0266667
  var basefontsize = Math.round(0.0267*devicemin);
  // apply:
  var rootElement = document.documentElement;
  rootElement.style.fontSize = basefontsize;
  // report:
  console.log(navigator.userAgent);
  var report = "device res: " + devicewidth + " x " + deviceheight + " ; base font size: " + basefontsize + "/" + rootElement.style.fontSize;
  console.log(report);
  function reporter() {
    document.getElementById("dreport").innerHTML = report + "/" + document.documentElement.style.fontSize + " ... " + navigator.userAgent;
  }
  window.onload = reporter;
  </script>
  <style type="text/css">
body {
  /* https://stackoverflow.com/questions/3226001 ; no real need/effect in this case, though */
  -webkit-text-size-adjust: none;
}
.testdiv, .testdivB, .testdivC {
  width: 50%;
  height: 30%;
  margin: 6px;
  border: 2px solid gray;
  font-size: 4em;
}
.testdivB {
  font-size: 12px;
}
.testdivC {
  font-size: 30pt;
}
#dreport {
  font-size: 0.76em;
}
  </style>
</head>

<body>
  <div id="dreport"></div>
  <div class="testdiv">Test one writing</div>
  <div class="testdivB">Test another writing</div>
  <div class="testdivC">Test three writing</div>

</body>
</html>
like image 36
sdbbs Avatar answered Sep 21 '22 19:09

sdbbs