如何使用 CSS 媒体查询检测 Android 设备的默认字体大小?

How to detect Android device's default font size with CSS media queries?

在 Android 中,设置 > 辅助功能 > 字体大小用户可以在 "Small"、"Default"、"Large"、"Largest" 之间设置字体大小。除其他事项外,此设置会影响 WebView 中 HTML 内容的默认字体大小。

我已经开发出适合默认字体大小的布局。将字体大小设置为 "Largest" 会导致文本在某些地方被截断,水平滚动条出现在其他地方等。在这些情况下,我可以使用替代布局(例如,垂直而不是水平堆叠东西),但我我不确定如何检测要使用的布局。

理想情况下,我会使用 CSS 媒体查询。类似于:

#foo {
    display: flex;
}

@media (min-width: 360px) {
    #foo {
        /* If at least 360px available, use a horizontal layout */
        flex-direction: row;
    }
}

问题是,360px 断点不受设备上字体大小设置的影响(这是有道理的)。我也尝试过其他测量单位:rem、ch、cm – 但其中 none 似乎考虑了设备的字体大小。

我考虑过在页面加载时做这样的事情:

但这种方法会增加页面加载的复杂性、延迟、重绘和闪烁。

有没有办法在 CSS(媒体查询或其他)中考虑设备字体大小?

您可以使用 VH(视口高度)或 VW(视口宽度)字体大小度量,字体将根据设备视口的百分比调整大小,例如:

1vh = 视口高度的 1% 2vw = 视口宽度的 2% 等

如果您正在做媒体选择器,您也可以使用 rem 或 px 作为字体大小。

您仍然需要为不同的设备添加@media 选择器,请记住视口是设备屏幕的实际尺寸,例如 10 英寸屏幕将有一个最大 1280px 或以下的@media 选择器。

/* please use caniuse.com  for  browser compatibility table*/ 
h1 {
  font-size: 2.5vw;
}

h2 {
  font-size: 2vw;
}

p {
  font-size: 12px;
}

@media only screen and (max-width:768px) {
  h1 {
    font-size: 5vw;
  }
  h2 {
    font-size: 4vw;
  }
  p {
    font-size: 18px;
  }
}
<h1>text</h1>

<h2>text</h2>

<p>some normal font controled by media query</p>

Is there a way to take device font size in account in CSS (media queries or otherwise)?

媒体查询用于根据设备宽度设置字体大小,而不是相反。

您可能使用的单位将始终基于设备宽度,而不是字体大小(因为此时无法定义)。

您可以做的是,您可以根据基本字体大小设置它们,而不是根据百分比或使用 px 单位定义列宽。

例如,而不是

.flex-col {
  flex: 0 1 30%;
}

你可以使用

.flex-col {
  flex: 0 1 20rem;
}

真正的问题不是你的媒体查询,而是你的容器没有以响应方式定义(例如固定宽度和高度)导致截断和滚动条。

简答

不,您不能仅使用 CSS 来完成此操作。但是,您可以使用类似于您在问题中提到的方法(测量字体大小并相应地调整布局)来最大程度地减少影响。

长答案

您不能仅使用 CSS 来做到这一点,但是可以拥有一个高性能的网站而无需重绘和 fall-back 您的默认样式 no JS.

此方法有一个缺点,您最终会将样式 sheet 注入页面,这会影响第一个内容绘制时间。但是请记住,这与具有匹配的媒体查询本质上是相同的(因此实际上,这与媒体查询之间没有区别,除了它依赖于 JavaScript)。

您可以通过内联相关样式来缓解这种情况,但显然这会带来页面权重成本。你将不得不决定哪个是更大的罪过!

解决方法很简单。

(1) 使用与您描述的方法类似的方法计算出用户的字体大小。

(2) 加载条件 CSS 以根据需要覆盖按键布局选项。

(2a) 或者将 class 添加到 body 并根据现有样式 sheet 中的样式更改布局,或者如果在折叠上方则内嵌在文档中.

1。算出用户的字体大小

您可以在页面的 header 内使用 vanilla JS 作为内联脚本执行此操作,因此它不会延迟任何内容(除了解析脚本)并且它仍然是高性能的。

尝试下面的示例,首先将字体大小设置为“中”,然后将 font-size 设置为“超大”,然后再次 运行 脚本。您的字体大小应分别显示为 16px 和 24px。

var el = document.getElementById('foo');
var style = window.getComputedStyle(el, null).getPropertyValue('font-size');
var fontSize = style;
console.log(style)
<div id="foo">a</div>

我们现在有一个与用户缩放比例相关的字体大小。

我们可以进一步改进这一点,只需将生成的字体大小除以 16(默认大小)即可获得百分比比例。

var el = document.getElementById('foo');
var style = window.getComputedStyle(el, null).getPropertyValue('font-size');
var fontSize = style;
var fontSizePercentage = parseFloat(style) / 16 * 100;


console.log(style, fontSizePercentage + "%");
<div id="foo">a</div>

2。加载条件 CSS

既然我们知道用户是否缩放了字体大小,我们只需有条件地加载 CSS。

为此,我们需要一个简单的 JavaScript 检查

//set to whatever criteria you need, if your site still works on "large" font size and only needs adjustment at "extra large" then use 124 etc.
if(fontSizePercentage > 100){
    //add the CSS
}

在下面的示例中,我将 3 列变成了 3 行,以演示字体大小如何决定要应用的样式。

请注意,为了模拟动态添加的 CSS 文件,我添加了一些内联 CSS 代码,这些代码被写入样式 sheet,您显然只需添加一个样式 [=158] =](我已经包含了一个函数来执行此操作,只是注释掉了调用该函数的位置)。

var el = document.getElementById('foo');
var style = window.getComputedStyle(el, null).getPropertyValue('font-size');
var fontSize = style;
var fontSizePercentage = parseFloat(style) / 16 * 100;
el.remove();

console.log(fontSizePercentage);



//this is just to simulate adding CSS, you would obviously import a style sheet properly here. I have put the proper function further down.
var normal = `
    .col3{
        float: left;
        width: 32%;
        margin-right: 1%;
    }
`
var bigger = `
    .col3{
        float: left;
        width: 100%;
    }
`

var styleSheet = document.createElement("style");
styleSheet.type = "text/css";
if(fontSizePercentage > 100){
    styleSheet.innerText = bigger;
}else{
    styleSheet.innerText = normal;
}
document.head.appendChild(styleSheet);

////actual style sheet code/////
function addCss(fileName) {

  var head = document.head;
  var link = document.createElement("link");

  link.type = "text/css";
  link.rel = "stylesheet";
  link.href = fileName;

  head.appendChild(link);
}
if(fontSizePercentage > 100){
    //addCss('url-to-large-font-size-layout');
}else{
    //addCss('url-to-normal-font-size-layout');
}
<div id="foo">a</div>

<div class="col3">column</div>
<div class="col3">column</div>
<div class="col3">column</div>

您将从示例中看到我们动态添加样式sheet,在示例中的两个样式sheet 之间进行选择。实际上,您可能只需要检查使用大字体样式 sheet 的要求,因为您的标准字体大小将被您的主要 CSS.

覆盖

优点 此方法实际上与 'font size media query' 相同,并带有微小的 JavaScript 开销。

缺点 如果您对重绘感到困扰,那么性能显然对您很重要,此方法会添加一个额外的请求,并且可以延迟“首屏内容”的首次内容绘制/初始页面呈现。

因此我提出第二个建议:

2a。在 body.

中添加一个 class

使用与上面完全相同的方法,但不是插入样式 sheet 而是简单地使用检查字体大小在页面加载时将 class 添加到 body。

只需将样式包含在当前样式 sheet 中,但将额外的 body class 作为限定符。

var el = document.getElementById('foo');
var style = window.getComputedStyle(el, null).getPropertyValue('font-size');
var fontSize = style;
var fontSizePercentage = parseFloat(style) / 16 * 100;
el.remove();

var bod = document.getElementById('simulated-body');

if(fontSizePercentage > 100){
   bod.classList.add('large-font-layout');
}




console.log(fontSizePercentage);
.col3{
        float: left;
        width: 32%;
        margin-right: 1%;
    }
    
.large-font-layout .col3{
        float: left;
        width: 100%;
    }
<div id="simulated-body">
<div id="foo">a</div>
<div class="col3">column</div>
<div class="col3">column</div>
<div class="col3">column</div>
</div>

pros 这不会添加任何额外的请求,应该不会影响您的页面绘制。一般来说,此选项比第一个选项更可取,因为您只需要覆盖少数 CSS classes,因此增加的权重可以忽略不计。

cons - 为您的 CSS.

添加额外的权重

结论

一些body应该添加一个“用户字体大小”媒体查询:-P

说真的,我会选择我给你的 (2a) 选项和 inline your critical CSS。如果您在 CSS 中更改超过 100 classes(因此 CSS 重量成为问题)那么您的设计有问题,因此速度差异可以忽略不计。再加上 JS 小于 1kb,不会影响你的绘画,这是一个简单但有效的解决问题的方法。

选项 2 的奖金信息

作为一个额外的想法,您可以将选项 2 与检查屏幕宽度结合起来,以真正达到 mi估计沿线路发送的数据量。然而,这随后开始增加相当大的复杂性,这是您所说的要避免的事情。为了完整起见,我将其包含在此处。

function getFontSizePercentage(){    
    
    var el = document.getElementById('foo');
    var style = window.getComputedStyle(el, null).getPropertyValue('font-size');
    var fontSize = style;
    var fontSizePercentage = parseFloat(style) / 16 * 100;
    el.remove();
    return fontSizePercentage;
}

function getPageWidth(){
  return Math.max(
    document.body.scrollWidth,
    document.documentElement.scrollWidth,
    document.body.offsetWidth,
    document.documentElement.offsetWidth,
    document.documentElement.clientWidth
  );
}

function addCSS(fileName) {

  var head = document.head;
  var link = document.createElement("link");

  link.type = "text/css";
  link.rel = "stylesheet";
  link.href = fileName;

  head.appendChild(link);
}

var fontSizePercentage = getFontSizePercentage();
var pageWidth = getPageWidth();
var cssSize = "1920";


switch(true) {
  case (pageWidth < 1366):
    cssSize = "1366";
    break;
  case (pageWidth < 728):
    var cssSize = "728";
    break;
  default:
    cssSize = "1920";
}


var cssPath = "styles/screen-width-" + cssSize + "-font-size-adjust";

if(fontSizePercentage > 100){
    console.log("adding CSS for width: " + cssSize, cssPath);
    addCSS(cssPath);
}else{
   console.log("not adding CSS", cssPath);
}
<div id="foo">a</div>