学了这么久前端 你知道 ”可替换元素“ 吗?

492 阅读4分钟

今天刷面试题的时候,偶然看到一道题,问可替换元素与非可替换元素的差异是什么?

看到题突然发现自己其实差远了,学了这么久前端,压根没听说过这个名词。

特地搜索学习,将相关知识总结分享出来。

可替换元素 (replaced element)

可替换元素,表示在 CSS 中,这些元素的展现效果不是由 CSS 来控制的。它们是一种外部对象,外观的渲染是独立于 CSS 的。

简单来说,它们的内容不受当前文档的样式的影响。CSS 可以影响可替换元素的位置,但不会影响到可替换元素自身的内容。某些可替换元素,例如 <iframe> 元素,可能具有自己的样式表,但它们不会继承父文档的样式。

CSS 能对可替换元素产生的唯一影响在于,部分属性支持控制元素内容在其框中的位置或定位方式。

典型的可替换元素有:

  • <iframe> 内联框架元素
  • <video> 播放播放器元素
  • <embed> 外部内容嵌入元素
  • <img> 图片元素

有些元素仅在特定情况下被作为可替换元素处理,例如:

  • <option> 菜单项元素
  • <audio> 音频播放器元素
  • <canvas> 画布元素
  • <object> 嵌入对象元素

类型为"image" 的 <input> 元素就像 <img> 一样会被替换,也属于可替换元素。但是其他类型的 <input> 元素,并不是可替换元素。

用 CSS content 属性插入的伪元素(例如 ::before::after)也是匿名的可替换元素。它们并不存在于 HTML 标记中,因此是“匿名的”。

非替换元素 (non-replaced elements)

和可替换元素对应,不是可替换元素的元素就是非可替换元素。

HTML 中的大多数元素都是不可替换元素,例如 <p> <h1> <div> 等等

差异

最主要的差异在上文中已经说过了,就是可替换元素的展现效果不是由 CSS 来控制的。

我们可以用一种更通俗易懂的方式来理解,所有可替换元素,其实都是两层 div,外层 div 表示它们在页面布局中的展示,内层 div 是可替换元素的内容(如视频、图片、网页等等)。我们的 CSS 属性,只可以修改外层的 div 的布局效果,而无法作用于内层 div

举个例子,在我们使用 canvas 元素时,当我们要修改画布的宽高,一般会这样写

<canvas width="600" height="400" id="canvas"></canvas>

或者使用js

<script>
  const canvas = document.querySelector('#canvas')
  canvas.width = 600
  canvas.height = 400
</script>

而不是修改 CSS

<style>
#canvas {
  width: 600px;
  height: 400px;
}
</style>

或这样

<script>
  const canvas = document.querySelector('#canvas')
  canvas.style.width = '600px'
  canvas.style.height = '400px'
</script>

弄清楚这两种方案的异同,有助于我们理解可替换元素CSS之间的关系。

为方便演示,我们在画布中绘制一些内容,并以使用 js 的实现方式来讲解,代码如下

<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>

<script>
  const canvas1 = document.querySelector('#canvas1')
  const ctx1 = canvas1.getContext('2d')
  const canvas2 = document.querySelector('#canvas2')
  const ctx2 = canvas2.getContext('2d')

  canvas1.width = 600
  canvas1.height = 400
  canvas2.style.width = '600px'
  canvas2.style.height = '400px'

  const draw = (ctx, str) => {
    ctx.fillStyle = 'pink'
    ctx.fillRect(0, 0, canvas1.width, canvas1.height)

    ctx.beginPath()
    for (let i = 0; i < 10; i++) {
      ctx.moveTo(i * 40, 0)
      ctx.lineTo(i * 40, 400)
    }
    ctx.closePath()
    ctx.stroke()

    ctx.fillStyle = 'black'
    ctx.font = '48px serif'
    ctx.fillText(str, 50, 100)
  }
  draw(ctx1, '方案一')
  draw(ctx2, '方案二')
</script>

image.png 从两种方案的效果图中可以明显看出区别,后者的线宽比前者粗,没有完整显示出 10 条线。

这两种方案,都修改了画布元素在布局上的宽高。但是,前者是修改 canvas 元素的属性,后者是修改容器的 CSS 属性,后者将画布的内容放大了 (浏览器中画布元素的默认宽高是 300 X 150)。

所以,设置可替换元素的 CSS 属性,只能影响其布局,而无法影响其内容。

一般想要修改可替换元素的属性时,会去修改可替换元素中包含的内容对象(内层 div)

独有属性

可替换元素还独有的2个 CSS 属性,用于指定 内层 div 在外层 div 中的位置或定位方式。

object-fit

此属性用于指定可替换元素的内容对象在元素盒区域中的填充方式。(类似于 background-size

此属性默认为 fill,用法如下

<style>
  canvas {
    object-fit: contain;
  }
</style>

image.png

object-position

此属性用于指定可替换元素的内容对象在元素盒区域中的位置。(类似于 background-position

此属性默认为 50% 50%,用法如下

<style>
  canvas {
    object-position: 20px 40px;
    outline: 1px solid black;
  }
</style>

image.png

垂直对齐方式

CSS 中的vertical-align 属性,用于指定行内元素的垂直对齐方式。可替换元素 都是行内块元素,在浏览器中此属性的默认值与其余行内元素不同,这也是导致文字与图片对不齐问题的原因。

<style>
  span {
    outline: 1px solid red;
  }
</style>
<span>文字更靠下一点</span>
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>

image.png

结语

如果文中有错误或不严谨的地方,请务必给予指正,十分感谢。

如果喜欢或者有所启发,欢迎点赞关注,鼓励一下新人作者。

内容参考

MDN
HTML标准