div之间横竖方向的5px间距

  1. 问题描述
  2. 解释
    1. 横向的5px 来源
      1. 等宽字体
      2. 全角和半角
    2. 纵向的间距来源
      1. vertical-align
    3. 其他办法
  3. 写在最后

问题描述

我们想在一个400*400的容器内放下4个200*200的div,实现代码如下:

style
------
.father {
width: 400px;
height: 400px;
outline: 1px solid blue;
}

.item {
width: 200px;
height: 200px;
display: inline-block;
background-color: red;
}

body
------
<div class="father">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>

就会发现,元素并没有按照想象的进行布局:

此时我们不断调整父容器的宽度,直到调整到405的时候:

虽然大致实现了目标,但是中间那些空白是什么情况!也许你以为是默认margin,但是你马上就会发现去除margin后,问题依然还在,本文就为了探究这个问题,从引起这个问题的根本原因:从一个空格 开始。

当然,之所以会有这篇文章,是因为博主也遇到了这个问题,而在我最终在这篇博客的评论区找到了线索:

两个div之间有一段空隙(距离)怎么回事?_microcosmv的博客-CSDN博客_div之间空白间距

解释

横向的5px 来源

相信从基础学起的同学们都知道

像这样进行书写,子div之间其实是存在一个空格的,浏览器在解析html的时候,任何地方任意数量空格和换行符都会被替换为一个空格,效果相当于这句代码document.replace(/[ \n]{2,}/,' '),当然像<pre>这种标签是不受影响的,更确切点是white-space 这个CSS属性控制着元素内的空格、换行符如何被解释。

关键就是这个空格,空格也是一个字符,和别的字一样都是要占用宽度的。默认没有设置字体属性的时候,它占用了5px宽度,我们把字体大小设置为100px试试:

style
------
.father{
width: 600px;
height: 405px;
outline: 1px solid red;
font-size: 100px;
}
.son{
width: 200px;
height: 200px;
display: inline-block;
outline: 1px solid red;
}


body
------
<div class="father">
    <div class="son"></div>
    <div class="son"></div>1 2
    <div class="son"></div>
    <div class="son"></div>
</div>

可以看到,空隙确实变大了,但是为什么是25px而不是100px呢?我们很容易联想到日常看英文的时候,经常发现不同字母所占用的实际宽度是不同的: wm这类占的宽度比ji通常要宽,这种效果在本网页中内也是如此。为什么会有这样呢,下面介绍对应的概念:比例字体和等宽字体。

等宽字体

和等宽字体对应的称为比例字体,他们通常都体现在英文中:一个字符根据自己的宽度调整实际占用的宽度,这就是比例字体,比如下图中肉眼可见的 jm 占用的宽度不同

比例字体字母J占宽 比例字体字母m占宽
image-20211112085656537 image-20211112091747764

而等宽字体则无论什么字符,占用的宽度都是相等的。

image-20211112092657516 image-20211112092714221
image-20211112092722537 image-20211112092730259

那比例字体的宽高又是如何确定的呢? 字体大小和实际上的字体宽高有什么关系呢? 很容易发现,绝大部分情况下,设置的font-size 字体大小和实际宽高都是对应不上的,而且不好找到规律。实际上这个是在设计字体的时候自己设置的,字体设计的时候有几个参数: 顶线、x线、基线、底线等,甚至可以设置字体的宽度,这些都是固定在字体内部的,CSS无法修改。更详细的可以看下面这篇文章:

字号与行高 – 人人FED (rrfed.com)

现在,我们把demo的字体改为等宽字体试试:

由于windows中默认只有Courier New这一个等宽字体

Microsoft-Supplied Monospaced TrueType Fonts

Microsoft-Supplied Monospaced TrueType Fonts
Summary
The only monospaced TrueType fonts shipped by Microsoft are Courier New, which shipped with Windows 3.1, and Lucida Sans Typewriter, which was included in the TrueType Font Pack. All other TrueType fonts included with Windows 3.1 and the TrueType Font Pack are proportional fonts.

style add
------
*{
font-family: "Courier New";
}

可以发现间距又变宽了

但是这个60是如何计算出来的呢? 如果大家看过了上面引用的那篇和字号有关的文章之后应该会比较清楚了,我们再实践一下那篇博客中的方法,自己尝试一下精确每个数值。用fontForge打开COUR.TTF,顺便再测试一个英文字母

空格 e
宽度
高度 \
em size 2048
计算 w=1229/2048*100=60 h=(1705+615)/2048*100=113
测量 \

可以看到全部都是一像素不差,完全吻合的。

细心的读者会发现字母e的那个结果中最后一个块为什么陷下去了,如果不懂可以参考这篇文章:

关于 vertical-align 你应该知道的一切 - 政采云前端团队 (zoo.team)

全角和半角

输入法可以切换全角和半角,由于中文输入都是全角的,所以区别只能在英文输入或显示中发现:

所谓半角就是一个正常英文字符所占的宽度,全角就是两个。所以没有别的参数干扰的话,一个中文的宽度等于同字体下两个任意等宽英文字母的宽度。

为了印证这个,我专门找了一个带中文的等宽字体。接下来就来看看sarasa这款字体(font-family: '等距更纱黑体 SC';)的配置和实际展现:

英文 中文 全角
文字宽度 全角中英文甚至字符、空格宽度都是一致的
em size \
高度 \
计算 通过计算可以得出,在font-size=100px的情况下,h = (977+273)/1000*100 = 125w = 500/1000*100 = 50 高度和英文一样,宽度两倍 \
结果

至此,对于文字的解析就告一段落了。那么回到主题,是时候揭示一下纵向的间距是怎么来的了。

纵向的间距来源

细心的朋友们其实已经能从上面发现一些端倪了:

在这张图中其实我们能发现选中中间的空格,它纵向占据了中间的间距,这就表示,空格这个字体,它的底线就在那个位置。是不是很反直觉,一个字的最底部和兄弟元素的底部不是对齐的,而是会略微长出一些。那究竟是什么规则呢?这里就要讲到一个CSS属性:vertical-align

vertical-align

vertical-align用于控制行内元素盒子相对于其行框盒子的垂直位置。

该CSS属性只对inlineinline-block(或table-cell)元素生效。

vertical-align默认值为baselinebaseline也就是字母x底部的位置:

可以看到,盒子和字母X的底部也就是基线是默认对齐,我们尝试把这些方框元素(inline-block)的baseline改为bottom,也就是相互底线对齐:

可以看到X被抬升了,现在X的底线和块底线对齐了,块垂直方向的间距已经消失了!(这里其实有个问题, 我们设置的是这些块的vertical-align,为什么动的却是兄弟元素,不过这个x算不算兄弟元素呢?他是裸露在外面的,这样的元素又有什么特性呢?这些就以后再探究了)

所以回到问题, 纵向的间距来源是代码写法中的标签之间的换行,换行被当成了一个空格字符,而字符默认和行内块是基线对齐的,而行内块里面如果没有内容, 则其基线位置为margin-bottom 的位置,而因为一个字符在设计的时候,通常基线底下都是还有内容的,而空格也是因为这个因素,基线底下留空,这个空白内容对应到块元素中就是底部下面,从而导致块元素出现了纵向的间距。

如果关于这块听不懂的话可以去看看这篇博客,写的比我好。

关于 vertical-align 你应该知道的一切 - 政采云前端团队 (zoo.team)

其他办法

vertical-align可以当作这种问题的一种正统的解决方式。其余还有很多解决办法,比如

  • 把空格所在父元素的font-size 设置为0 这样相当于空格被隐藏了
  • line-height:0
  • 标签之间去除空格

写在最后

本次探索再次让我感受到了,计算机是很严谨的,只要我们了解透之后,一个像素的偏差都不会出现。不知道大家有没有感受到。

这几天看了一起诚为简的视频,那期视频讲述了他探索如何才能让一片纸片的下降时间达到最久。虽然我的探索远不及他的深入,但是我确实能体会那种由目标驱动自己去了解一项事物,并引发强烈的成就感。

不过激动归激动,不久之前我就在想,我真的是在往正确的方向发展吗?即使我坚定我会在前端的道路上走下去,但是当下是不是应该花更多时间去学习框架,而非这些小细节呢? 或者,我学习这些小细节也是效率十分低下。 不得不承认,看博客真的是一件很低效的事,大多数博客只是官方文档的翻译官,其中还有一部分没翻译好,而那些真正高价值的博客,在我这个阶段还根本看不到,看到了也看不懂。其实反思一下,我当下最应该去做的是学好英语,起码要学到能够去顺读官方文档的地步,这是提高效率的第一步。而脱离了这一步其他都无从说起了。

加油!


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 yionr99@gmail.com