重学css(6)内联元素的掌管者line-height和vertical-align

2024-04-03 06:32

本文主要是介绍重学css(6)内联元素的掌管者line-height和vertical-align,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.字母x与CSS世界的基线

要了解内联元素,就不得不提到字母x,正是有了x,内联元素才确定了自己的基线(baseline),有了baseline之后,才有了line-height和vertical-align。因此在学习后面的内容之前,必须要了解一个概念:

字母x的下边缘线就是内联元素的基线(baseline)!

既然x那么重要,因此CSS还给了它一个特殊的称呼叫x-height。顾名思义,x-height指的就是小写字母x的高度,那么这个x-height有没有用呢?答案是肯定的,如vertical-align:middle的定义就是baseline往上1/2*x-height的位置,因此我们看到的vertical-align:middle在font-size较大的时候会显得不是特别“垂直居中”,因为不是每个字/字母的高度都和字母x相同,或者说,大部分都是不相同的。

由于vertical-align:middle需要基于x-height进行运算,那么CSS干脆给这个x-height一个名份,进一步衍生出了相对尺寸单位ex,1ex = x-height,因此这个单位会随着font属性的变化而变化,非常的不稳定,所以不太适合用来限定元素的尺寸,但某些情况下,ex的表现相当出色。如:我们需要如下效果

需要在文字后面加一个倒三角符号,这时候我们要让文字和图标对齐可能会借助vertical-align:middle,让文字和图片都基于中线对齐,事实上由于文字本身是基于baseline排版的,这时候我们只要让icon也基于baseline布局不就行了吗?那怎么让图标也基于基线布局呢?加个height:1ex不就完事了吗?如下所示:

<style>
.icon-arrow {display: inline-block;width: 20px;height: 1ex;background: url(/images/5/arrow.png) no-repeat center;
}
</style>

2.内联元素中真实存在的“行框盒子”

由于之前没有好好解析内联盒子的基础知识,这里要补充一个关于内联盒子的基础内容,这对于学习后面的知识有一定的帮助。首先我们需要明确两个非官方概念:什么是行框盒子以及行框盒子有什么用?

什么是行框盒子?事实上我并不敢说这是官方给出的一个盒模型,作者也没有提到,但他似乎真实存在于文字的每一行,而且是以行作为计算单位的,也就是每一行文字(不管他们是不是一个内联标签或匿名标签生成的),都在外面自动生成一个“行框盒子”。注意,这里仅代表我从书本上获取的观点,在后面的幽灵节点中会继续探讨官方是否给出了这个盒子。这么说可能不够直观,来看一个例子吧。

这是我用span标签生成的一段话,他被浏览器自动分割成了两行,你可以理解每行文字的外包裹就是一个行框盒子。那么什么时候会生成行框盒子呢?这里我仅凭个人测试提出两种生成行框盒子的情况,第一种,就是非空内联元素,注意这个非空,很关键,作者似乎总是忽略空元素的测试,我本人则对空元素比较在意。第二种,就是inline-block元素内部自动生成,注意这里可以为空了,具体为什么我也不知道,测试结果如此。

第二个问题是,行框盒子有什么用?作者为什么要提出行框盒子?因为这有助于我们理解很多问题。首先来看下面这个测试代码以及他们生成的结果。

<div style="background: yellow;"><span style="line-height: 40px">我行高40px</span><span style="line-height: 60px">我行高60px</span><span style="line-height: 30px">我行高30px</span><span style="line-height: 90px">我行高90px</span>
</div>

此时div的角色就像是“行框盒子”,因为div包裹了一行“行框盒子”(这里只有一行,两行情况又不同了),这样做是为了让你更直观的看到最终这些内联元素最终生成的“行框盒子”,生成的高度是90px,也就是说,同一行!内联元素生成的行框盒子的高度,取决于line-height最高的那个元素。为了加深你对这个结果的印象,我再放一张图,还是刚才那几个元素,这次我把父容器div的宽度压缩了。

image.png

最终结果跟上面测试的结论相同,第一行行高最高的是60px,第二行行高最高的是90px,两个“行框盒子”一相加,得到最终的150px,对于行框盒子的印象应该够深了吧!

3.内联元素的基石line-height

明白了行框盒子的概念之后,再来看line-height,就会容易的多了。作为内联元素的基石,line-height完全掌控了内联盒子的高度,注意,我说的是完全掌控,跟font-size没有半毛钱关系。

来思考一下下面这个问题,一个空的div的高度是0,在里面写上几个字,他的高度就被撑开了,那么这个高度是由何而来呢?首先可以确定的是,是由新增的文字撑开的,在内联元素中,还有一类叫做“匿名内联元素”的近亲,他们外面没有包裹任何内联元素标签,但事实上他们的表现跟内联元素相同,只是不能单独定义自己的样式(当然可以从父级去继承一些过来,虽然继承的权重最低,但总比没有强)。好了,我们知道这几个字是匿名内联元素了,因此高度是由这个内联元素的高度撑开的,那么这个内联元素的高度又取决于什么呢?下面我们来做两个测试。

image.png

如结果所示,最终撑开高度的是line-height,而不是font-size。注意这里说的是非替换元素的纯内联元素,替换元素的概念可以看一下之前的文章。之前说过padding和border可以影响元素的高度,那么在内联元素中,是否也可以呢?答案是:不行!但有些情况下,视觉上还是有一些偏差。如下测试

<div style="background: yellow"><span style="line-height: 40px;padding: 20px;border: 1px solid">我有padding和border</span>
</div>

由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)

我有padding和border

因此对于纯内联元素,他的高度计算只跟line-height相关。 line-height === 纯内联元素height !!!

关于line-height的计算方式,作者“啰哩吧嗦”算了半天,我只总结成一个公式,line-height = font-size + 上半行距 + 下半行距 。对于CSS来讲,font-size是已知的,因此他只需要计算半行距即可,至于它是怎么算的,就没必要深究了。我只讲这个计算方式会导致一种情况,第一行文字和最后一行文字的上方和下方都只有半行距的距离,中间部分则是一个行距,如对样式有较高要求的可以考虑一下这个因素,用其他方式去弥补这里的高度差。

4.line-height在块级元素和内联替换元素中的疲软性

说完了line-height在内联元素中的表现,再来说说line-height在块级元素和内联替换元素中承担什么样的角色吧。

首先我们先来看简单的,line-height在块级元素中承担一个什么样的角色呢?答案是:屁用没有。当然,本章第三点的第一个例子就是在块级元素上直接写line-height属性,所以,还是有那么丁点作用的,这个作用是line-height无处不在的继承属性决定的,正好块级元素内的匿名内联元素自己写不了样式,那就只能继承父级的line-height了,所以line-height最终还是作用于内联元素,而不是块级元素。然后由内联元素生成的行框盒子相加,撑开了块级元素的高度。

既然line-height在块级元素中没用,那他在内联替换元素中又有哪些表现呢?这个等讲完vertical-align再总结。

5.深入line-height的各类属性值

本节的标题让人觉得摸不着头脑,line-height还有别的属性?还真没有,line-height就一个值,只是可以有不同的类型。

line-height的默认值是normal,注意不是none,还支持数值,百分比值和具体长度值。

首先要了解一下这个看上去就不一般的normal,normal本身是一个跟font-family有关的变量,而且在不同的浏览器中还有不同的计算值,因此对于还原设计稿的这种要求,我们不可能用默认的normal属性,同时由于line-height无处不在的继承属性,有时候不知不觉的你就把这个属性给改了,因此normal属性可以不讨论(我们一切以实用性出发)。

实际上,我们平时会设置line-height为具体的数值,如line-height:xx像素。这种做法完全适用于现在高要求的精致网站,对于需要高保真还原设计稿的需求,完全可以用用具体数值。当然也有一种情况你可以用数字或百分比,就是现在有很多网站有自己的设计标准,如微信小程序,ant-design之类的,他们会要求文章内部的行高是字号的1.3-1.4倍,文章标题的的行高是字号的多少多少倍,这种情况下你大可以根据设计要求,用比例计算方式来写行高。

这里我只推荐用长度值(1,2,3),而不是百分比值(100%,200%),你可能觉得1不是等于100%嘛,其实我也这么认为,一般都是按照喜好随便挑一个。事实上,这里面问题可大了去了。

长度值和百分比值的计算方式是完全相同的。都是font-size长度/百分比,向下取整,141.4 = 19.6 = 19px,注意不是四舍五入,是向下取整的。

那么长度和百分比哪里不同呢?答案是:继承方式,就是line-height中无处不在的继承方式不同。这里我们来看一个实例:

<div class="box box-1"><h3>标题</h3><p>内容</p>
</div>
<div class="box box-2"><h3>标题</h3><p>内容</p>
</div>
<style>
.box   { font-size: 14px; }
.box-1 { line-height: 1.5; }
.box-2 { line-height: 150%; }
</style>

结果如下图所示:

最终表现得结果不一样,问题就在于这个继承方式。

使用数值,line-height = 本身的font-size*数值

使用百分比,line-height = 继承来的line-height*数值

你会发现,一个是基于自身的font-size,一个是基于继承的line-height,完全不同,而且数值在大多数情况下的表现更优,也更符合实际情况。所以我个人推荐不要用line-height的百分比值,就当没听过。

6.内联元素line-height的“大值特性”

其实这个问题并不能单纯的理解为,内联元素line-height取最大那么简单,其中还包含之前所说的“行框盒子”的内容,以及行框盒子产生的幽灵节点。在探索大值特性之前,我们得先了解一下,幽灵节点是什么。来看具体的实例:


<!DOCTYPE HTML>
<html>
<head>
<title></title>
</head>
<body>
<div style="background: yellow"><span style="display: inline-block;"></span></div>
</body>
</html>

注意这段代码必须要有声明。这段代码的结果是:

这里的span标签的高度确实是0,那么究竟是什么撑开了div的高度呢?就是上面提到的“幽灵空白节点”,你可以想象这个幽灵空白节点是一个没有宽度的空白节点,当然你不要去dom结构里找他,肯定是找不到的。在了解幽灵空白节点之前,先得知道,什么时候会出现这个幽灵空白节点,根据我的测试,结果跟作者的描述相同。

产生行框盒子的前面自动生成幽灵空白节点。由于之前提到了,inline-block元素内部可以生成幽灵空白节点,因此这里确实存一个一个看不见的内联元素,且他有自己的line-height。

幽灵空白节点的line-height = font-size(默认12px) * normal,因此这个幽灵空白节点就有自己的高度了,有自己的高度就撑开了inline-block的高度,inline-block又撑开了父容器的高度,那么现在就一切都说得通了。

做好了一切的准备工作,最后做个总结和检测,理解了下面这个案例,你就真正理解了内联元素的line-height。

<div class="box box1"><span>span: line-height:20px</span>
</div>
<div class="box box2"><span>span: line-height:96px</span>
</div>
<style>
.box {width: 280px;margin: 1em auto;outline: 1px solid #beceeb;background: #f0f3f9;
}
.box1 {line-height: 96px;
}
.box1 span {line-height: 20px;
}
.box2 {line-height: 20px;
}
.box2 span {line-height: 96px;
}
</style>

由于markdown编辑器支持标签语言,因此我们可以直接预览最终效果如下(小提示:你可以通过浏览器直接检查下面的元素看到CSS样式)

span: line-height:20px

span: line-height:96px

上面这两个box最终得到的高度是一样的,为什么会这样呢?

刚才说到,每个非空内联元素外面都会生出一层“行框盒子”,而每个行框盒子左边就有一个幽灵空白节点,box1>span的line-height是20px,但他隔壁住了个幽灵空白节点,继承了父元素的line-height:96px,我们已经知道行框盒子的高度是由最高的内联元素的行高决定的,因此box1的最终高度和box2的相同,都是96px。

本章内容过于多,vertical-align就放到下章讲,学了vertical-align之后我们再来看如何结合两者实现多行元素的垂直居中展示,有兴趣的可以关注后续文章,点个关注。

这篇关于重学css(6)内联元素的掌管者line-height和vertical-align的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/872147

相关文章

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

css中的 vertical-align与line-height作用详解

《css中的vertical-align与line-height作用详解》:本文主要介绍了CSS中的`vertical-align`和`line-height`属性,包括它们的作用、适用元素、属性值、常见使用场景、常见问题及解决方案,详细内容请阅读本文,希望能对你有所帮助... 目录vertical-ali

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js