CSS 问题

本章节是前端开发者面试问题 - CSS 部分的参考答案。 欢迎提出 PR 进行建议和指正!

目录

CSS 选择器的优先级是如何计算的?

浏览器通过优先级规则,判断元素展示哪些样式。优先级通过 4 个维度指标确定,我们假定以a、b、c、d命名,分别代表以下含义:

  1. a表示是否使用内联样式(inline style)。如果使用,a为 1,否则为 0。
  2. b表示 ID 选择器的数量。
  3. c表示类选择器、属性选择器和伪类选择器数量之和。
  4. d表示标签(类型)选择器和伪元素选择器之和。

优先级的结果并非通过以上四个值生成一个得分,而是每个值分开比较。a、b、c、d权重从左到右,依次减小。判断优先级时,从左到右,一一比较,直到比较出最大值,即可停止。所以,如果b的值不同,那么cd不管多大,都不会对结果产生影响。比如0,1,0,0的优先级高于0,0,10,10

当出现优先级相等的情况时,最晚出现的样式规则会被采纳。如果你在样式表里写了相同的规则(无论是在该文件内部还是其它样式文件中),那么最后出现的(在文件底部的)样式优先级更高,因此会被采纳。

在写样式时,我会使用较低的优先级,这样这些样式可以轻易地覆盖掉。尤其对写 UI 组件的时候更为重要,这样使用者就不需要通过非常复杂的优先级规则或使用!important的方式,去覆盖组件的样式了。

参考

[↑] 回到顶部

重置(resetting)CSS 和 标准化(normalizing)CSS 的区别是什么?你会选择哪种方式,为什么?

  • 重置(Resetting): 重置意味着除去所有的浏览器默认样式。对于页面所有的元素,像marginpaddingfont-size这些样式全部置成一样。你将必须重新定义各种元素的样式。
  • 标准化(Normalizing): 标准化没有去掉所有的默认样式,而是保留了有用的一部分,同时还纠正了一些常见错误。

当需要实现非常个性化的网页设计时,我会选择重置的方式,因为我要写很多自定义的样式以满足设计需求,这时候就不再需要标准化的默认样式了。

参考

[↑] 回到顶部

请阐述Float定位的工作原理。

浮动(float)是 CSS 定位属性。浮动元素从网页的正常流动中移出,但是保持了部分的流动性,会影响其他元素的定位(比如文字会围绕着浮动元素)。这一点与绝对定位不同,绝对定位的元素完全从文档流中脱离。

CSS 的clear属性通过使用leftrightboth,让该元素向下移动(清除浮动)到浮动元素下面。

如果父元素只包含浮动元素,那么该父元素的高度将塌缩为 0。我们可以通过清除(clear)从浮动元素后到父元素关闭前之间的浮动来修复这个问题。

有一种 hack 的方法,是自定义一个.clearfix类,利用伪元素选择器::after清除浮动。另外还有一些方法,比如添加空的<div></div>和设置浮动元素父元素的overflow属性。与这些方法不同的是,clearfix方法,只需要给父元素添加一个类,定义如下:

.clearfix::after {
content: '';
display: block;
clear: both;
}

值得一提的是,把父元素属性设置为overflow: autooverflow: hidden,会使其内部的子元素形成块格式化上下文(Block Formatting Context),并且父元素会扩张自己,使其能够包围它的子元素。

参考

[↑] 回到顶部

请阐述z-index属性,并说明如何形成层叠上下文(stacking context)。

CSS 中的z-index属性控制重叠元素的垂直叠加顺序。z-index只能影响position值不是static的元素。

没有定义z-index的值时,元素按照它们出现在 DOM 中的顺序堆叠(层级越低,出现位置越靠上)。非静态定位的元素(及其子元素)将始终覆盖静态定位(static)的元素,而不管 HTML 层次结构如何。

层叠上下文是包含一组图层的元素。 在一组层叠上下文中,其子元素的z-index值是相对于该父元素而不是 document root 设置的。每个层叠上下文完全独立于它的兄弟元素。如果元素 B 位于元素 A 之上,则即使元素 A 的子元素 C 具有比元素 B 更高的z-index值,元素 C 也永远不会在元素 B 之上.

每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父层叠上下文中按顺序进行层叠。少数 CSS 属性会触发一个新的层叠上下文,例如opacity小于 1,filter不是nonetransform不是none

参考

[↑] 回到顶部

请阐述块格式化上下文(Block Formatting Context)及其工作原理。

块格式上下文(BFC)是 Web 页面的可视化 CSS 渲染的部分,是块级盒布局发生的区域,也是浮动元素与其他元素交互的区域。

一个 HTML 盒(Box)满足以下任意一条,会创建块格式化上下文:

  • float的值不是none.
  • position的值不是staticrelative.
  • display的值是table-celltable-captioninline-blockflex、或inline-flex
  • overflow的值不是visible

在 BFC 中,每个盒的左外边缘都与其包含的块的左边缘相接。

两个相邻的块级盒在垂直方向上的边距会发生合并(collapse)。更多内容请参考边距合并(margin collapsing)

参考

[↑] 回到顶部

有哪些清除浮动的技术,都适用哪些情况?

  • div方法:<div style="clear:both;"></div>
  • Clearfix 方法:上文使用.clearfix类已经提到。
  • overflow: autooverflow: hidden方法:上文已经提到。

在大型项目中,我会使用 Clearfix 方法,在需要的地方使用.clearfix。设置overflow: hidden的方法可能使其子元素显示不完整,当子元素的高度大于父元素时。

[↑] 回到顶部

请解释什么是精灵图(css sprites),以及如何实现?

精灵图,也称雪碧图。因常见碳酸饮料雪碧的英文名也是 Sprite,因此也有人会使用雪碧图的非正式译名。

精灵图是把多张图片整合到一张上的图片。它被运用在众多使用了很多小图标的网站上(Gmail 在使用)。实现方法:

  1. 使用生成器将多张图片打包成一张精灵图,并为其生成合适的 CSS。
  2. 每张图片都有相应的 CSS 类,该类定义了background-imagebackground-positionbackground-size属性。
  3. 使用图片时,将相应的类添加到你的元素中。

好处:

  • 减少加载多张图片的 HTTP 请求数(一张精灵图只需要一个请求)。但是对于 HTTP2 而言,加载多张图片不再是问题。
  • 提前加载资源,防止在需要时才在开始下载引发的问题,比如只出现在:hover伪类中的图片,不会出现闪烁。
参考

[↑] 回到顶部

如何解决不同浏览器的样式兼容性问题?

  • 在确定问题原因和有问题的浏览器后,使用单独的样式表,仅供出现问题的浏览器加载。这种方法需要使用服务器端渲染。
  • 使用已经处理好此类问题的库,比如 Bootstrap。
  • 使用 autoprefixer 自动生成 CSS 属性前缀。
  • 使用 Reset CSS 或 Normalize.css。

[↑] 回到顶部

如何为功能受限的浏览器提供页面? 使用什么样的技术和流程?

  • 优雅的降级:为现代浏览器构建应用,同时确保它在旧版浏览器中正常运行。
  • 渐进式增强:构建基于用户体验的应用,但在浏览器支持时添加新增功能。
  • 利用 caniuse.com 检查特性支持。
  • 使用 autoprefixer 自动生成 CSS 属性前缀。
  • 使用 Modernizr进行特性检测。

[↑] 回到顶部

有什么不同的方式可以隐藏内容(使其仅适用于屏幕阅读器)?

这些方法与可访问性(a11y)有关。

  • width: 0; height: 0:使元素不占用屏幕上的任何空间,导致不显示它。
  • position: absolute; left: -99999px: 将它置于屏幕之外。
  • text-indent: -9999px:这只适用于block元素中的文本。
  • Metadata: 例如通过使用 Schema.org,RDF 和 JSON-LD。
  • WAI-ARIA:如何增加网页可访问性的 W3C 技术规范。

即使 WAI-ARIA 是理想的解决方案,我也会采用绝对定位方法,因为它具有最少的注意事项,适用于大多数元素,而且使用起来非常简单。

参考

[↑] 回到顶部

你使用过栅格系统吗?偏爱哪一个?

我使用 float-based 栅格系统,因为它相比 flex、grid 系统,拥有更多浏览器的支持。它已经在 Bootstrap 中使用多年,并且已经被证明是可行的。

[↑] 回到顶部

你是否使用过媒体查询或移动优先的布局?

是的,一个例子就是根据窗口的尺寸改变导航的样式。

[↑] 回到顶部

你熟悉制作 SVG 吗?

是的,你可以使用内联 CSS、嵌入式 CSS 部分或外部 CSS 文件对形状进行着色(包括指定对象上的属性)。在网上大部分 SVG 使用的是内联 CSS,不过每个类型都有优点和缺点。

通过设置fillstroke属性,可以完成基本着色操作。fill可以设置内部的颜色,stroke可以设置周围绘制的线条的颜色。你可以使用与HTML中使用的 CSS 颜色命名方案相同的 CSS 颜色命名方案:颜色名称(即red)、RGB 值(即rgb(255,0,0))、十六进制值、RGBA 值等等。

<rect
x="10"
y="10"
width="100"
height="100"
stroke="blue"
fill="purple"
fill-opacity="0.5"
stroke-opacity="0.8"
/>
参考

[↑] 回到顶部

除了screen,你还能说出一个 @media 属性的例子吗?

  • all 适用于所有设备。
  • print 为了加载合适的文档到当前使用的可视窗口. 需要提前咨询 paged media(媒体屏幕尺寸), 以满足个别设备网页尺寸不匹配等问题。
  • screen 主要适用于彩色的电脑屏幕
  • speech 解析 speech 这个合成器. 注意: CSS2 已经有一个相似的媒体类型叫 aural.
参考

[↑] 回到顶部

编写高效的 CSS 应该注意什么?

首先,浏览器从最右边的选择器,即关键选择器(key selector),向左依次匹配。根据关键选择器,浏览器从 DOM 中筛选出元素,然后向上遍历被选元素的父元素,判断是否匹配。选择器匹配语句链越短,浏览器的匹配速度越快。避免使用标签和通用选择器作为关键选择器,因为它们会匹配大量的元素,浏览器必须要进行大量的工作,去判断这些元素的父元素们是否匹配。

BEM (Block Element Modifier)原则上建议为独立的 CSS 类命名,并且在需要层级关系时,将关系也体现在命名中,这自然会使选择器高效且易于覆盖。

搞清楚哪些 CSS 属性会触发重新布局(reflow)、重绘(repaint)和合成(compositing)。在写样式时,避免触发重新布局的可能。

参考

[↑] 回到顶部

使用 CSS 预处理的优缺点分别是什么?

优点:

  • 提高 CSS 可维护性。
  • 易于编写嵌套选择器。
  • 引入变量,增添主题功能。可以在不同的项目中共享主题文件。
  • 通过混合(Mixins)生成重复的 CSS。
  • 将代码分割成多个文件。不进行预处理的 CSS,虽然也可以分割成多个文件,但需要建立多个 HTTP 请求加载这些文件。

缺点:

  • 需要预处理工具。
  • 重新编译的时间可能会很慢。

[↑] 回到顶部

对于你使用过的 CSS 预处理,说说喜欢和不喜欢的地方?

喜欢:

  • 绝大部分优点上题以及提过。
  • Less 用 JavaScript 实现,与 NodeJS 高度结合。

Dislikes:

  • 我通过node-sass使用 Sass,它用 C ++ 编写的 LibSass 绑定。在 Node 版本切换时,我必须经常重新编译。
  • Less 中,变量名称以@作为前缀,容易与 CSS 关键字混淆,如@media@import@font-face

[↑] 回到顶部

如何实现一个使用非标准字体的网页设计?

使用@font-face并为不同的font-weight定义font-family

[↑] 回到顶部

解释浏览器如何确定哪些元素与 CSS 选择器匹配。

这部分与上面关于编写高效的 CSS 有关。浏览器从最右边的选择器(关键选择器)根据关键选择器,浏览器从 DOM 中筛选出元素,然后向上遍历被选元素的父元素,判断是否匹配。选择器匹配语句链越短,浏览器的匹配速度越快。

例如,对于形如p span的选择器,浏览器首先找到所有<span>元素,并遍历它的父元素直到根元素以找到<p>元素。对于特定的<span>,只要找到一个<p>,就知道<span>已经匹配并停止继续匹配。

参考

[↑] 回到顶部

描述伪元素及其用途。

CSS 伪元素是添加到选择器的关键字,去选择元素的特定部分。它们可以用于装饰(:first-line:first-letter)或将元素添加到标记中(与 content:...组合),而不必修改标记(:before:after)。

  • :first-line:first-letter可以用来修饰文字。
  • 上面提到的.clearfix方法中,使用clear: both来添加不占空间的元素。
  • 使用:beforeafter展示提示中的三角箭头。鼓励关注点分离,因为三角被视为样式的一部分,而不是真正的 DOM。如果不使用额外的 HTML 元素,只用 CSS 样式绘制三角形是不太可能的。
参考

[↑] 回到顶部

说说你对盒模型的理解,以及如何告知浏览器使用不同的盒模型渲染布局。

CSS 盒模型描述了以文档树中的元素而生成的矩形框,并根据排版模式进行布局。每个盒子都有一个内容区域(例如文本,图像等)以及周围可选的paddingbordermargin区域。

CSS 盒模型负责计算:

  • 块级元素占用多少空间。
  • 边框是否重叠,边距是否合并。
  • 盒子的尺寸。

盒模型有以下规则:

  • 块级元素的大小由widthheightpaddingbordermargin决定。
  • 如果没有指定height,则块级元素的高度等于其包含子元素的内容高度加上padding(除非有浮动元素,请参阅下文)。
  • 如果没有指定width,则非浮动块级元素的宽度等于其父元素的宽度减去父元素的padding
  • 元素的height是由内容的height来计算的。
  • 元素的width是由内容的width来计算的。
  • 默认情况下,paddingborder不是元素widthheight的组成部分。
参考

[↑] 回到顶部

* { box-sizing: border-box; }会产生怎样的效果?

  • 元素默认应用了box-sizing: content-box,元素的宽高只会决定内容(content)的大小。
  • box-sizing: border-box改变计算元素widthheight的方式,borderpadding的大小也将计算在内。
  • 元素的height = 内容(content)的高度 + 垂直方向的padding + 垂直方向border的宽度
  • 元素的width = 内容(content)的宽度 + 水平方向的padding + 水平方向border的宽度

[↑] 回到顶部

display的属性值都有哪些?

  • none, block, inline, inline-block, table, table-row, table-cell, list-item.

TODO

[↑] 回到顶部

inlineinline-block有什么区别?

我把block也加入其中,为了获得更好的比较。

blockinline-blockinline
大小填充其父容器的宽度。取决于内容。取决于内容。
定位从新的一行开始,并且不允许旁边有 HTML 元素(除非是float与其他内容一起流动,并允许旁边有其他元素。与其他内容一起流动,并允许旁边有其他元素。
能否设置widthheight不能。 设置会被忽略。
可以使用vertical-align对齐不可以可以可以
边距(margin)和填充(padding)各个方向都存在各个方向都存在只有水平方向存在。垂直方向会被忽略。 尽管borderpaddingcontent周围,但垂直方向上的空间取决于'line-height'
浮动(float)--就像一个block元素,可以设置垂直边距和填充。

[↑] 回到顶部

relativefixedabsolutestatic四种定位有什么区别?

经过定位的元素,其position属性值必然是relativeabsolutefixedsticky

  • static:默认定位属性值。该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。
  • relative:该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。
  • absolute:不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。
  • fixed:不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。
  • sticky:盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 table 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。position: stickytable 元素的效果与 position: relative 相同。
参考

[↑] 回到顶部

你使用过哪些现有的 CSS 框架?你是如何改进它们的?

  • Bootstrap: 更新周期缓慢。Bootstrap 4 已经处于 alpha 版本将近两年了。添加了在页面中广泛使用的微调按钮组件。
  • Semantic UI:源代码结构使得自定义主题很难理解。非常规主题系统的使用体验很差。外部库的路径需要硬编码(hard code)配置。变量重新赋值没有 Bootstrap 设计得好。
  • Bulma: 需要很多非语义的类和标记,显得很多余。不向后兼容,以至于升级版本后,会破坏应用的正常运行。

[↑] 回到顶部

你了解 CSS Flexbox 和 Grid 吗?

了解。Flexbox 主要用于一维布局,而 Grid 则用于二维布局。

Flexbox 解决了 CSS 中的许多常见问题,例如容器中元素的垂直居中,粘性定位(sticky)的页脚等。Bootstrap 和 Bulma 基于 Flexbox,这是创建布局的推荐方式。我之前曾使用过 Flexbox,但在使用flex-grow时遇到了一些浏览器不兼容问题(Safari),我必须使用inline-blocks和手动计算百分比宽度,来重写我的代码,这种体验不是很好。

Grid 创建基于栅格的布局,是迄今为止最直观的方法(最好是!),但目前浏览器支持并不广泛。

参考

[↑] 回到顶部

请解释在编写网站时,响应式与移动优先的区别。

TODO

[↑] 回到顶部

响应式设计与自适应设计有何不同?

响应式设计和自适应设计都以提高不同设备间的用户体验为目标,根据视窗大小、分辨率、使用环境和控制方式等参数进行优化调整。

响应式设计的适应性原则:网站应该凭借一份代码,在各种设备上都有良好的显示和使用效果。响应式网站通过使用媒体查询,自适应栅格和响应式图片,基于多种因素进行变化,创造出优良的用户体验。就像一个球通过膨胀和收缩,来适应不同大小的篮圈。

自适应设计更像是渐进式增强的现代解释。与响应式设计单一地去适配不同,自适应设计通过检测设备和其他特征,从早已定义好的一系列视窗大小和其他特性中,选出最恰当的功能和布局。与使用一个球去穿过各种的篮筐不同,自适应设计允许使用多个球,然后根据不同的篮筐大小,去选择最合适的一个。

参考

[↑] 回到顶部

你有没有使用过视网膜分辨率的图形?当中使用什么技术?

我倾向于使用更高分辨率的图形(显示尺寸的两倍)来处理视网膜显示。更好的方法是使用媒体查询,像@media only screen and (min-device-pixel-ratio: 2) { ... },然后改变background-image

对于图标类的图形,我会尽可能使用 svg 和图标字体,因为它们在任何分辨率下,都能被渲染得十分清晰。

还有一种方法是,在检查了window.devicePixelRatio的值后,利用 JavaScript 将<img>src属性修改,用更高分辨率的版本进行替换。

参考

[↑] 回到顶部

什么情况下,用translate()而不用绝对定位?什么时候,情况相反。

translate()transform的一个值。改变transformopacity不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。而改变绝对定位会触发重新布局,进而触发重绘和复合。transform使浏览器为元素创建一个 GPU 图层,但改变绝对定位会使用到 CPU。 因此translate()更高效,可以缩短平滑动画的绘制时间。

当使用translate()时,元素仍然占据其原始空间(有点像position:relative),这与改变绝对定位不同。

参考

[↑] 回到顶部

其他答案

Last updated on by Yangshun Tay