如何使用 CSS 媒体查询检测 Android 设备的默认字体大小?
Posted
技术标签:
【中文标题】如何使用 CSS 媒体查询检测 Android 设备的默认字体大小?【英文标题】:How to detect Android device's default font size with CSS media queries? 【发布时间】:2020-09-20 21:20:44 【问题描述】:在 android 中,设置 > 辅助功能 > 字体大小,用户可以在“小”、“默认”、“大”、“最大”之间设置字体大小。除其他外,此设置会影响 WebView 中 html 内容的默认字体大小。
我已经开发了我的布局,使其与默认字体大小相得益彰。将字体大小设置为“最大”会导致文本在某些地方被截断,水平滚动条出现在其他地方等。在这些情况下,我可以使用替代布局(例如,垂直堆叠而不是水平堆叠),但我不确定如何检测要使用的布局。
理想情况下,我会使用 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——但它们似乎都没有考虑到设备的字体大小。
我考虑过在页面加载时做这样的事情:
在屏幕上显示一行常量文本(例如“0000000000”) 在 JS 中测量 如果测量的宽度/设备宽度比高于某个设置的常数,则切换到替代布局但这种方法会增加复杂性、延迟、重绘和页面加载闪烁。
有没有办法在 CSS(媒体查询或其他)中考虑设备字体大小?
【问题讨论】:
可以使用orientation: "portrait"
orientation控制站点,看这里manifest.json您所要做的就是将信息发送到页面以垂直或水平显示。并根据这个参数提供相应的 manifest.json
@GrzegorzT。我不确定我是否遵循 - 在清单中指定方向如何帮助我检测可用宽度(就适合的文本字符而言)?
在手机端检查是否设置了缩放,您知道在此手机分辨率和文本缩放下页面会中断。您正在下载一个带有一些参数的页面,该参数将成为另一个具有不同 orientation:" portrait "
的 manifest.json 的基础。例如。 myWebView.loadUrl("https://www.example.com?orientation=landscape");
基于此参数,您可以在页面上提供各种 manifest.json
当然,这不仅仅是manifest.json
的替换,你可以改变字体大小或者隐藏页面上的元素。您在非电话方面进行更改。手机只会通知网站该文本不适合视图,仅此而已。
@GrzegorzT。啊,我想我现在明白了——决定在本机代码中使用哪种布局(通过检查用户的首选字体大小、屏幕大小等),然后根据它加载不同的 HTML 文档?
【参考方案1】:
简答
不,您不能仅使用 CSS 来做到这一点。但是,您可以使用类似于您在问题中提到的方法(测量字体大小并相应地调整布局)来最小化影响。
长答案
您不能仅使用 CSS 来做到这一点,但是可以拥有一个无需重绘的高性能网站,并且可以回退到 no JS 的默认样式。
这种方法有一个缺点,您最终会在页面中注入样式表,这会影响第一次内容绘制时间。但是请记住,这与匹配媒体查询本质上是相同的(因此实际上,这与媒体查询之间没有区别,只是它依赖于 javascript)。
您可以通过内联相关样式来缓解这种情况,但显然这会带来页面权重成本。你将不得不决定哪个是更大的罪!
解决方法很简单。
(1) 使用与您描述的方法类似的方法计算出用户的字体大小。
(2) 根据需要加载覆盖关键布局选项的条件 CSS。
(2a) 或者向正文添加一个类,并根据现有样式表中的样式更改布局,或者如果在折叠上方,则在文档中内联。
1。计算出用户的字体大小
您可以在原版 JS 中作为内联脚本直接在页面标题中执行此操作,这样它就不会延迟任何事情(除了解析脚本)并且仍然可以执行。
尝试下面的示例,首先将字体大小设置为“中”,然后将字体大小设置为“特大”并再次运行脚本。您的字体大小应分别显示为 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(默认大小)即可获得 %age scale。
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 代码,您显然只需添加一个样式表(我已经包含了一个函数来执行此操作,并且只是注释掉了该函数的位置被调用)。
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>
您将从示例中看到我们动态添加样式表,在示例中的两个样式表之间进行选择。实际上,您可能只需要检查使用大字体样式表的要求,因为您的标准字体大小将被您的主 CSS 覆盖。
优点 这种方法实际上与“字体大小媒体查询”相同,并带有很小的 JavaScript 开销。
缺点 如果您对重绘感到困扰,那么性能显然对您很重要,此方法会添加一个额外的请求,并且可能会延迟“首屏内容”的首次内容绘制/初始页面渲染。
因此我提出第二个建议:
2a。向正文添加一个类。
使用与上述完全相同的方法,但不插入样式表,只需使用检查字体大小在页面加载时将类添加到正文。
只需将样式包含在当前样式表中,但将附加的正文类作为限定符。
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>
专业人士这不会添加任何额外的请求,不会影响您的页面绘制。通常,此选项比第一个选项更可取,因为您应该只需要覆盖少数 CSS 类,因此增加的权重可以忽略不计。
缺点 - 给你的 CSS 增加额外的权重。
结论
有人应该添加“用户字体大小”媒体查询:-P
说真的,尽管我会选择我给你的 (2a) 选项和inline your critical CSS。如果您在 CSS 中更改了 100 多个类(因此 CSS 权重成为问题),那么您的设计有问题,因此速度差异可以忽略不计。再加上 JS 小于 1kb,它不会影响您的绘画,这是解决您问题的简单而有效的方法。
选项 2 的奖励信息
作为一个额外的想法,您可以将选项 2 与检查屏幕宽度结合起来,以真正最大限度地减少通过网络发送的数据量。然而,这开始增加相当大的复杂性,这是你说你想要避免的。为了完整起见,我将其包含在此处。
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>
【讨论】:
感谢您提供令人印象深刻的详细回答。关于结论中的“用户字体大小”媒体查询备注:直观地说,没有阅读规范,我希望像@media (min-width: 123ch)
这样的东西会起作用,因为基本字体的字符宽度会根据用户的设置而改变。但是,唉,它不是那样工作的。 JS将不得不这样做。再次感谢您!
没问题,是的,我尝试了所有我能想到的媒体查询,我想这与其他可访问性设置被公开的原因相同,他们不希望人们成为目标,因为他们需要更大的字体尺寸等。烦人,但希望以上内容对你来说足够不显眼!【参考方案2】:
有没有办法在 CSS(媒体查询或其他)中考虑设备字体大小?
媒体查询用于根据设备宽度设置字体大小,而不是相反。
您可能使用的单位将始终基于设备宽度,而不是字体大小(因为此时无法定义)。
您可以做的是,您可以根据基本字体大小设置它们,而不是根据百分比或使用 px 单位来定义列的宽度。
例如,而不是
.flex-col
flex: 0 1 30%;
你可以使用
.flex-col
flex: 0 1 20rem;
真正的问题不是您的媒体查询,而是您的容器没有以响应方式定义(例如固定宽度和高度)导致截断和滚动条。
【讨论】:
在一个具体示例中,我没有网格,也没有设置任何宽度。我有一个布局,其中三个按钮水平相邻显示(在 flex 容器内,flex-direction: row
)。如果按钮标签放不下,我想切换到垂直布局(flex-direction: column
)。
@PēterisCaune 这是默认行为,只要您在弹性容器上设置flex-wrap: wrap
IIUC,在三个按钮的示例中,flex-wrap: wrap
可能导致两个按钮出现在一行上,第三个按钮出现在第二行上。我想要实现的是两种不同的布局:水平的所有三个按钮(如果它们适合的话)或垂直的所有三个按钮。换行比截断内容要好 :-)【参考方案3】:
您可以使用 VH(视口高度)或 VW(视口宽度)字体大小度量,字体将根据设备视口的百分比调整大小,例如:
1vh = 视口高度的 1% 2vw = 视口宽度的 2% 等
如果你在做媒体选择器,你也可以使用 rem 或 px 作为字体大小。
您仍然需要为不同的设备添加@media 选择器,请记住视口是设备屏幕的实际大小,例如 10 英寸屏幕将有一个 @media 选择器,最大为 1280 像素或以下。
/* 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>
【讨论】:
谢谢,您建议设置相对于视口宽度的字体大小。这不是我所追求的。我想使用用户选择的任何字体大小,但如果字体大小与视口宽度的比率超过特定阈值,则使用替代布局。 大众单位似乎也受到 Android 系统字体设置的影响。即带有“大”的 1vw 实际上与带有“最大”的 1vw 不同。以上是关于如何使用 CSS 媒体查询检测 Android 设备的默认字体大小?的主要内容,如果未能解决你的问题,请参考以下文章
我需要一种使用 jquery 检测 CSS3 媒体查询支持的简单方法
CSS媒体查询不足以检测超大型移动/平板设备与桌面设备[重复]