对于某些字体,当元素的line-height
小于阈值时,scrollHeight
大于clientHeight
。
因此,字体属性中有某些原因会导致这种情况,但这又是什么?如何最好避免使用CSS甚至自定义字体的字体编辑器来避免这种情况?
例如,在此摘录中,scrollHeight
的{{1}}大于Tahoma
,虽然clientHeight
在sans-serif
为1时似乎还可以。当页面在Chrome(ctrl +)中缩放时,这种差异会增加,甚至在无衬线情况下也会发生。当行高低于1或字体大小变大时,差异会增加。
对于某些其他字体,它在行高1处上升到5px ,并通过将行高增加到2而减小,这导致计算不正确。
line-height
var a = document.getElementById('a');
console.log('tahoma - a.clientHeight: ' + a.clientHeight);
console.log('tahoma - a.scrollHeight: ' + a.scrollHeight);
var b = document.getElementById('b');
console.log('sans - b.clientHeight: ' + b.clientHeight);
console.log('sans - b.scrollHeight: ' + b.scrollHeight);
var c = document.getElementById('c');
console.log('sans - lineHeight:0.5 - c.clientHeight: ' + c.clientHeight);
console.log('sans - lineHeight:0.5 - c.scrollHeight: ' + c.scrollHeight);
var d = document.getElementById('d');
console.log('sans - font-size:200px - d.clientHeight: ' + d.clientHeight);
console.log('sans - font-size:200px - d.scrollHeight: ' + d.scrollHeight);
div[id] {
overflow:auto;
max-width:80%;
}
很明显,这种差异是由于溢出问题引起的,但是这里涉及哪些字体指标,以及我们如何识别<div id='a' style='font-family:tahoma; line-height:1;'>Hello</div>
<div id='b' style='font-family:sans-serif; line-height:1;'>Hello</div>
<div id='c' style='font-family:sans-serif; line-height:0.5;'>Hello</div>
<div id='d' style='font-family:sans-serif; line-height: 1; font-size:500px;'>Hello</div>
和scrollHeight
之间的差异?
在Chrome和Firefox中都发生;我没有测试其他浏览器。
答案 0 :(得分:1)
我发现scrollHeight
是元素内容的高度的量度,其中包括由于溢出而在屏幕上不可见的内容,而clientHeight
是度量值元素高度的值。
当减小line-height时,div元素的高度变小-因此clientHeight会变小,但是内容的高度不会改变,因此scrollHeight会保持不变,因此这就是您进行2次测量的原因不同。
如果要两次不同的测量得出相同的结果,则必须修改容器元素的高度。例如,添加到div min-height: 1.2em
var a = document.getElementById('a');
console.log('tahoma - a.clientHeight: ' + a.clientHeight);
console.log('tahoma - a.scrollHeight: ' + a.scrollHeight);
var c = document.getElementById('c');
console.log('sans - lineHeight:0.5 - c.clientHeight: ' + c.clientHeight);
console.log('sans - lineHeight:0.5 - c.scrollHeight: ' + c.scrollHeight);
.div {
font-size: 40px;
margin: 10px;
border: 1px solid black;
min-height: 1.2em;
}
<div class='div' id='a' style='font-family:tahoma; line-height:1;'>Hello</div>
<div class='div' id='c' style='font-family:sans-serif; line-height:0.5;'>Hello</div>
显然,这会更改布局。在不更改布局的情况下,您将无法测量两种不同的东西,并且期望获得相同的结果。
如果要计算实际字符大小-可以使用this solution
console.log("tahoma size: " + measureTextHeight("40px tahoma"));
console.log("sans-serif size: " + measureTextHeight("40px sans-serif"));
console.log("Bookman Old Style size: " + measureTextHeight("40px Bookman Old Style"));
console.log("Palatino Linotype size: " + measureTextHeight("40px Palatino Linotype"));
function measureTextHeight(fontSizeFace) {
// create a temp canvas
var width=1000;
var height=60;
var canvas=document.createElement("canvas");
canvas.width=width;
canvas.height=height;
var ctx=canvas.getContext("2d");
// Draw the entire a-z/A-Z alphabet in the canvas
var text="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
ctx.save();
ctx.font=fontSizeFace;
ctx.clearRect(0,0,width,height);
ctx.fillText(text, 0, 40);
ctx.restore();
// Get the pixel data from the canvas
var data = ctx.getImageData(0,0,width,height).data,
first = false,
last = false,
r = height,
c = 0;
// Find the last line with a non-transparent pixel
while(!last && r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
last = r;
break;
}
}
}
// Find the first line with a non-transparent pixel
while(r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
first = r;
break;
}
}
// If we've got it then return the height
if(first != r) return last - first;
}
// error condition if we get here
return 0;
}
div{
font-size: 40px;
}
<div style="font-family:tahoma;">Hello</div>
<div style="font-family:sans-serif;">Hello</div>
<div style="font-family:Bookman Old Style;">Hello</div>
<div style="font-family:Palatino Linotype;">Hello</div>
答案 1 :(得分:1)
为使问题更明显,我们在span
内引入div
并添加一些边框/背景。让我们开始使用一个大的line-height
:
body {
font-family:sans-serif;
}
div {
border:1px solid;
margin:10px;
}
span {
background:red;
}
<div style='line-height:3;'><span>Hello</span></div>
红色部分定义内容区域,边框所包围的空间是线框,它是我们div元素的高度(请查看此更多信息:Why is there space between line boxes, not due to half leading?)。
在这种情况下,我们没有任何溢出,因此scrollHeight
和clientHeight
的值相同:
var a = document.getElementById('a');
console.log('clientHeight: ' + a.clientHeight);
console.log('scrollHeight: ' + a.scrollHeight);
body {
font-family:sans-serif;
}
div {
border:1px solid;
margin:10px;
}
span {
background:red;
}
<div id="a" style='line-height:3;'><span>Hello</span></div>
我们还可以得出结论,两者都等于3 * 16px
,即line-height * font-size
ref (默认情况下,font-size
是{{1 }}。
现在,如果我们开始降低16px
的音量,我们将在逻辑上减小div的高度,并且内容区域将保持不变:
line-height
body {
font-family:sans-serif;
}
div {
border:1px solid;
margin:10px;
}
span {
background:red;
}
现在很明显,我们已经溢出了,<div style='line-height:3;'><span>Hello</span></div>
<div style='line-height:1;'><span>Hello</span></div>
<div style='line-height:0.5;'><span>Hello</span></div>
<div style='line-height:0.2;'><span>Hello</span></div>
现在小于clientHeight
,但是scrollHeight
将保持clientHeight
,而line-height * font-size
将保留是红色部分的高度:
scrollHeight
var a = document.querySelectorAll('.show');
var b = document.querySelectorAll('.show span');
for(var i=0;i<a.length;i++) {
console.log('cH: ' + a[i].clientHeight + ' sH: ' + a[i].scrollHeight);
}
body {
font-family:sans-serif;
font-size:100px;
padding-bottom:100px;
}
div.show {
border:1px solid;
margin:100px;
}
span {
background:red;
}
但是为什么在内容区域保持不变的情况下<div class="show" style='line-height:3;'><span>Hello</span></div>
<div class="show" style='line-height:1;'><span>Hello</span></div>
<div class="show" style='line-height:0.5;'><span>Hello</span></div>
<div class="show" style='line-height:0.2;'><span>Hello</span></div>
<div class="show" style='line-height:0.1;'><span>Hello</span></div>
<div class="show" style='line-height:0;'><span>Hello</span></div>
的值却减小了?这是由于以下事实:我们在顶部和底部都有溢出(因为对齐方式是基线),并且scrollHeight
仅包括底部溢出,因为顶部无法访问。要使scrollHeight
等于内容区域,我们只需要更改对齐方式:
scrollHeight
var a = document.querySelectorAll('.show');
var b = document.querySelectorAll('.show span');
for(var i=0;i<a.length;i++) {
console.log('cH: ' + a[i].clientHeight + ' sH: ' + a[i].scrollHeight);
}
body {
font-family:sans-serif;
font-size:100px;
padding-bottom:100px;
}
div.show {
border:1px solid;
margin:100px;
}
span {
background:red;
vertical-align:text-bottom;
}
现在很明显,如果<div class="show" style='line-height:3;'><span>Hello</span></div>
<div class="show" style='line-height:1;'><span>Hello</span></div>
<div class="show" style='line-height:0.5;'><span>Hello</span></div>
<div class="show" style='line-height:0.2;'><span>Hello</span></div>
<div class="show" style='line-height:0.1;'><span>Hello</span></div>
<div class="show" style='line-height:0;'><span>Hello</span></div>
足够大,并且line-height
减小,line-height
的最小值等于内容区域。
如果我们选中the specification,我们可以阅读以下内容:
“ height”属性不适用。 内容区域的高度 应基于字体,但此规范未指定 如何。 UA可能会使用em-box或最大上升器, 字体的降序形式。 (后者将确保带有部分字形 在Em-box上方或下方仍位于内容区域内,但 导致用于不同字体的大小不同的框;前者会 确保作者可以控制相对于 “行高”,但导致字形在其内容之外绘画 区域。
注意:CSS的第3级可能会包含一个属性来选择 字体的度量用于内容的高度。
因此我们无法知道用于定义此区域的确切度量,这就是为什么每种字体的行为都不同的原因。我们只能知道它取决于scrollHeight
和font-family
。我们可能会通过一些测试手动找到计算结果。对于上面的示例,内容区域的高度似乎为font-size
对于1.12 * font-size
,似乎是tahoma
(在Chrome上)和1.206 * font-size
(对于Firefox)(见下文):
1.21 * font-size
var a = document.querySelectorAll('.show');
var b = document.querySelectorAll('.show span');
for(var i=0;i<a.length;i++) {
console.log('cH: ' + a[i].clientHeight + ' sH: ' + a[i].scrollHeight);
}
body {
font-family:tahoma;
font-size:1000px;
padding-bottom:100px;
}
div.show {
border:1px solid;
margin:100px;
}
span {
background:red;
vertical-align:text-bottom;
}
因此<div class="show" style='line-height:3;'><span>Hello</span></div>
<div class="show" style='line-height:1;'><span>Hello</span></div>
<div class="show" style='line-height:0.5;'><span>Hello</span></div>
<div class="show" style='line-height:0.2;'><span>Hello</span></div>
<div class="show" style='line-height:0.1;'><span>Hello</span></div>
<div class="show" style='line-height:0;'><span>Hello</span></div>
等于scrollHeight
,其中p * font-size
取决于字体,我们可以通过手动测试找到它,而p
等于clientHeight
。当然,如果我们保持对齐基线,line-height * font-size
会因为顶部溢出而有所不同。