CSS

CSS 选择器特异性是什么?它是如何工作的?

浏览器根据 CSS 规则的特异性来决定在元素上显示哪些样式。我们假设浏览器已经确定了与特定元素匹配的规则。在匹配的规则中,根据以下各项为每个规则计算特异性,即四个逗号分隔的值:a, b, c, d

  1. a 表示是否使用行内样式。如果属性声明是元素上的行内样式,则 a 为 1,否则为 0。
  2. b 是 ID 选择器的数量。
  3. c 是类、属性和伪类选择器的数量。
  4. d 是标签和伪元素选择器的数量。

结果特异性不是一个分数,而是一个值矩阵,可以按列进行比较。在比较选择器以确定哪个具有最高特异性时,从左到右查看,并比较每列中的最高值。因此,列 b 中的值将覆盖列 cd 中的值,无论它们可能是什么。因此,特异性 0,1,0,0 将大于 0,0,10,10

在特异性相等的情况下:以最新规则为准。如果您在样式表中(无论是内部还是外部)编写了两次相同的规则,那么样式表中靠下的规则更接近要设置样式的元素,它被认为更具特异性,因此将被应用。

我会编写低特异性的 CSS 规则,以便在必要时可以轻松覆盖它们。在编写 CSS UI 组件库代码时,它们具有低特异性很重要,这样库的用户就可以覆盖它们,而无需使用过于复杂的 CSS 规则来增加特异性或求助于 !important

“重置”和“标准化”CSS 有什么区别?您会选择哪一个,为什么?

  • 重置(Resetting) - 重置旨在清除元素上的所有浏览器默认样式。例如,所有元素的 marginpaddingfont-size 都被重置为相同。您必须重新声明常用排版元素的样式。
  • 标准化(Normalizing) - 标准化保留了有用的默认样式,而不是“取消样式”所有内容。它还纠正了常见浏览器依赖项的错误。

当我的网站设计非常个性化或非传统时,我会选择重置,这样我需要自己进行大量的样式设置,并且不需要保留任何默认样式。

描述 `float` 及其工作原理。

float 是一个 CSS 定位属性。浮动元素仍然是页面流的一部分,并且会影响其他元素的定位(例如,文本将围绕浮动元素流动),这与 position: absolute 元素不同,后者从页面流中移除。

CSS clear 属性可用于定位在 left/right/both 浮动元素下方。

如果父元素只包含浮动元素,其高度将折叠为零。这可以通过在容器中的浮动元素之后但在容器关闭之前清除浮动来修复。

.clearfix hack 使用了一个巧妙的 CSS 伪选择器 (::after) 来清除浮动。您不是在父元素上设置 overflow,而是为其应用一个附加类 clearfix。然后应用以下 CSS:

.clearfix::after { content: ' '; visibility: hidden; display: block; height: 0; clear: both; }

或者,给父元素添加 overflow: autooverflow: hidden 属性,这将建立一个位于子元素内部的新的块格式化上下文,并且它将扩展以包含其子元素。

描述 `z-index` 以及堆叠上下文是如何形成的。

CSS 中的 z-index 属性控制重叠元素的垂直堆叠顺序。z-index 仅影响 position 值不为 static 的元素。

在没有任何 z-index 值的情况下,元素按照它们在 DOM 中出现的顺序堆叠(在同一层级中,最下面的元素出现在顶部)。具有非静态定位的元素(及其子元素)将始终出现在具有默认静态定位的元素之上,无论 HTML 层次结构如何。

堆叠上下文是包含一组层的元素。在本地堆叠上下文中,其子元素的 z-index 值是相对于该元素设置的,而不是相对于文档根目录。该上下文之外的层——即本地堆叠上下文的兄弟元素——不能位于其内部层之间。如果元素 B 位于元素 A 的上方,则元素 A 的子元素 C 永远不会高于元素 B,即使元素 C 的 z-index 高于元素 B。

每个堆叠上下文都是自包含的——在元素内容堆叠之后,整个元素在父堆叠上下文的堆叠顺序中被考虑。一些 CSS 属性会触发新的堆叠上下文,例如 opacity 小于 1、filter 不为 nonetransform 不为 none

_注意:究竟是什么使元素能够创建堆叠上下文,可以在这组冗长的[规则]中找到。

描述块格式化上下文(BFC)及其工作原理。

块格式化上下文(BFC)是网页视觉 CSS 渲染的一部分,其中块级框被布局。浮动、绝对定位元素、inline-blockstable-cellstable-captionoverflow 值不是 visible 的元素(除非该值已传播到视口)都会建立新的块格式化上下文。

了解如何建立块格式化上下文很重要,因为如果不这样做,包含框将不会[包含浮动子元素]。这类似于折叠外边距,但更阴险,因为您会发现整个框以奇怪的方式折叠。

BFC 是满足以下至少一个条件的 HTML 框:

  • float 的值不是 none
  • position 的值既不是 static 也不是 relative
  • display 的值是 table-celltable-captioninline-blockflexinline-flexgridinline-grid
  • overflow 的值不是 visible

在 BFC 中,每个框的左外边缘都触及包含块的左边缘(对于从右到左的格式,右边缘触及)。

BFC 中相邻块级框之间的垂直外边距会折叠。阅读更多关于[折叠外边距]的信息。

有哪些不同的清除技术,哪种适合哪种情况?

  • div 方法 - <div style="clear:both;"></div>
  • Clearfix 方法 - 参见上面 .clearfix 类。
  • overflow: autooverflow: hidden 方法 - 父元素将建立新的块格式化上下文并扩展以包含其浮动子元素。

在大型项目中,我会编写一个实用程序 .clearfix 类,并在需要的地方使用它们。如果子元素比父元素高,overflow: hidden 可能会剪裁子元素,这不是很理想。

解释 CSS 精灵,以及您将如何在页面或站点上实现它们。

CSS 精灵将多个图像组合成一个更大的图像。它是图标的常用技术(Gmail 使用它)。如何实现它:

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

优点:

  • 减少对多个图像的 HTTP 请求数量(每个精灵表只需要一个请求)。但是随着 HTTP2 的出现,加载多个图像不再是问题。
  • 提前下载直到需要时才下载的资产,例如仅在 :hover 伪状态时才出现的图像。不会出现闪烁。

您将如何解决浏览器特定的样式问题?

  • 识别问题和有问题的浏览器后,使用单独的样式表,该样式表仅在该特定浏览器使用时加载。但是,此技术需要服务器端渲染。
  • 使用 Bootstrap 等库,它们已经为您处理了这些样式问题。
  • 使用 autoprefixer 自动为您的代码添加供应商前缀。
  • 使用 Reset CSS 或 Normalize.css。
  • 如果您使用 Postcss(或类似的转译库),可能存在插件,允许您选择使用现代 CSS 语法(甚至 W3C 提案),这些插件会将您的代码的这些部分转换为相应的安全代码,这些代码将在您使用的目标中工作。

您如何为功能受限的浏览器提供页面?您使用哪些技术/流程?

  • 优雅降级(Graceful degradation) - 为现代浏览器构建应用程序,同时确保它在旧浏览器中仍然功能正常。
  • 渐进增强(Progressive enhancement) - 为基本级别的用户体验构建应用程序,但在浏览器支持时添加功能增强。
  • 使用 [caniuse.com] 检查功能支持。
  • Autoprefixer 用于自动插入供应商前缀。
  • 使用 [Modernizr] 进行功能检测。
  • 使用 [CSS Feature queries @support]

有哪些不同的方法可以视觉上隐藏内容(并使其仅供屏幕阅读器使用)?

这些技术与可访问性(a11y)有关。

  • width: 0; height: 0。使元素完全不占用屏幕上的任何空间,从而不显示它。
  • position: absolute; left: -99999px。将其定位在屏幕外。
  • text-indent: -9999px。这仅适用于 block 元素中的文本。这是一种广泛使用且著名的技巧,但它有一些[缺点],例如导致性能问题,因此您可能需要考虑使用 text-indent: 100%
  • 元标签。例如,通过使用 Schema.org、RDF 和 JSON-LD。
  • WAI-ARIA。W3C 技术规范,规定了如何提高网页的可访问性。

即使 WAI-ARIA 是理想的解决方案,我也会选择 absolute 定位方法,因为它限制最少,适用于大多数元素,并且是一种简单的技术。

您使用过网格系统吗?如果使用过,您更喜欢哪一种?

在 Flex 流行之前(大约 2014 年),基于 float 的网格系统是最可靠的,因为它在现有替代系统(flex,grid)中仍然拥有最多的浏览器支持。Bootstrap 在 Bootstrap 4 之前一直使用 float 方法,之后切换到基于 flex 的方法。截至目前(2020 年),flex 是构建网格系统的推荐方法,并且具有[不错的浏览器支持]。

对于喜欢冒险的人,他们可以研究 [CSS Grid Layout],它使用了闪亮的新 grid 属性;它甚至比 flex 更适合构建网格布局,并且将来将成为事实上的方式。

您使用或实现了媒体查询或移动设备专用布局/CSS 吗?

是的。一个例子是在超出某个断点时,将堆叠的药丸导航转换为固定底部的选项卡导航。

您熟悉 SVG 样式设置吗?

是的,有几种方法可以为形状着色(包括在对象上指定属性),可以使用行内 CSS、嵌入式 CSS 部分或外部 CSS 文件。您在网络上找到的大多数 SVG 都使用行内 CSS,但每种类型都有其优点和缺点。

基本着色可以通过在节点上设置两个属性来完成:fillstrokefill 设置对象内部的颜色,stroke 设置对象周围绘制线的颜色。您可以使用与 HTML 中相同的 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" />

上面的 fill="purple" 是_表示属性_的一个例子。有趣的是,与行内样式(如 style="fill: purple",它也是一个属性)不同,表示属性可以被样式表中定义的 [CSS 样式覆盖]。因此,如果您执行 svg { fill: blue; } 之类的操作,它将覆盖我们定义的紫色填充。

除了 screen,您能举一个 @media 属性的例子吗?

是的,@media 属性有四种类型(包括 screen):

  • all - 适用于所有媒体类型设备
  • print - 适用于打印机
  • speech - 适用于“朗读”页面的屏幕阅读器
  • screen - 适用于电脑屏幕、平板电脑、智能手机等

这是 print 媒体类型使用示例:

@media print { body { color: black; } }

编写高效 CSS 的一些“陷阱”是什么?

首先,了解浏览器从最右侧(关键选择器)到左侧匹配选择器。浏览器根据关键选择器过滤 DOM 中的元素,并向上遍历其父元素以确定匹配项。选择器链的长度越短,浏览器确定该元素是否匹配选择器的速度就越快。因此,避免使用标签和通用选择器作为关键选择器。它们匹配大量元素,浏览器将需要做更多工作来确定父元素是否匹配。

[BEM(块元素修饰符)] 方法论建议所有内容都只有一个类,并且在需要层次结构的地方,这也融入到类名中,这自然使选择器高效且易于覆盖。

请注意哪些 CSS 属性会[触发]回流、重绘和合成。尽可能避免编写会改变布局(触发回流)的样式。

使用 CSS 预处理器有什么优点/缺点?

优点:

  • CSS 更易于维护。
  • 易于编写嵌套选择器。
  • 变量用于一致的主题设置。可以在不同项目之间共享主题文件。
  • Mixin 用于生成重复的 CSS。
  • Sass 功能,如循环、列表和映射,可以使配置更容易,更简洁。
  • 将代码拆分为多个文件。CSS 文件也可以拆分,但这样做需要通过 HTTP 请求下载每个 CSS 文件。

缺点:

  • 需要预处理工具。重新编译时间可能很慢。
  • 未编写当前和潜在可用的 CSS。例如,通过使用 [webpack] 的 [postcss-loader],您可以编写潜在的未来兼容 CSS,从而允许您使用 CSS 变量而不是 Sass 变量。因此,您正在学习新技能,这些技能在标准化后可能会带来回报。

描述您喜欢和不喜欢您使用过的 CSS 预处理器。

优点:

  • 主要是上面提到的优点。
  • 用 JavaScript 编写的代码更少,这与 Node 配合得很好。

缺点:

  • 我通过 node-sass 使用 Sass,它是 LibSass 的 C++ 绑定。在 Node 版本之间切换时,我必须频繁重新编译它。
  • 在 Less 中,变量名前缀为 @,这可能与 @media@import@font-face 规则等原生 CSS 关键字混淆。

您将如何实现使用非标准字体的网页设计稿?

使用 @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 hack 中使用,以添加一个零空间元素并使用 clear: both
  • 工具提示中的三角形箭头使用 :before:after。这鼓励了关注点分离,因为三角形被认为是样式的一部分,而不是 DOM 的一部分。

解释您对盒模型的理解以及如何在 CSS 中告诉浏览器以不同的盒模型渲染您的布局。

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

CSS 盒模型负责计算:

  • 块元素占用多少空间。
  • 边框和/或外边距是否重叠或折叠。
  • 框的尺寸。

盒模型有以下规则:

  • 块元素的尺寸由 widthheightpaddingbordermargin 计算得出。
  • 如果未指定 height,块元素的高度将与其包含的内容的高度加上 padding 相同(除非有浮动元素,具体请参见下文)。
  • 如果未指定 width,非浮动块元素将扩展以适应其父元素的宽度减去 padding
  • 元素的高度由内容的 height 计算。
  • 元素的宽度由内容的 width 计算。
  • 默认情况下,paddingborder 不属于元素的 widthheight

`* { box-sizing: border-box; }` 的作用是什么?它的优点是什么?

  • 默认情况下,元素应用了 box-sizing: content-box,并且只计算内容大小。
  • box-sizing: border-box 改变了元素 widthheight 的计算方式,borderpadding 也包含在计算中。
  • 元素的 height 现在通过内容的 height + 垂直 padding + 垂直 border 宽度来计算。
  • 元素的 width 现在通过内容的 width + 水平 padding + 水平 border 宽度来计算。
  • paddingborder 视为我们盒模型的一部分,这与设计师实际想象内容在网格中的方式更加吻合。

什么是 CSS `display` 属性,你能举几个它的用法的例子吗?

  • noneblockinlineinline-blockflexgridtabletable-rowtable-celllist-item

| display | 描述 | | :-- | :-- | | none | 不显示元素(元素不再影响文档的布局)。所有子元素也不再显示。文档的渲染就像文档树中不存在该元素一样 | | block | 元素在块方向(通常是水平方向)占据整行 | | inline | 元素可以并排放置 | | inline-block | 类似于 inline,但允许某些 block 属性,例如设置 widthheight | | table | 表现得像 <table> 元素 | | table-row | 表现得像 <tr> 元素 | | table-cell | 表现得像 <td> 元素 | | list-item | 表现得像 <li> 元素,允许它定义 list-style-typelist-style-position |

`inline` 和 `inline-block` 有什么区别?

为了更好的衡量,我将与 block 进行比较。

| | block | inline-block | inline | | --- | --- | --- | --- | | 大小 | 填充其父容器的宽度。 | 取决于内容。 | 取决于内容。 | | 定位 | 开始新的一行,并且不容忍任何 HTML 元素在其旁边(除非您添加 float) | 与其他内容一起流动,并允许其他元素在其旁边。 | 与其他内容一起流动,并允许其他元素在其旁边。 | | 可以指定 widthheight | 是 | 是 | 否。如果设置将被忽略。 | | 可以与 vertical-align 对齐 | 否 | 是 | 是 | | 外边距和内边距 | 尊重所有边。 | 尊重所有边。 | 仅尊重水平边。垂直边(如果指定)不影响布局。其占用的垂直空间取决于 line-height,尽管 borderpadding 在视觉上显示在内容周围。 | | 浮动 | - | - | 变成像 block 元素一样,您可以设置垂直外边距和内边距。 |

`relative`、`fixed`、`absolute` 和 `static` 定位元素有什么区别?

定位元素是指其计算出的 position 属性为 relativeabsolutefixedsticky 的元素。

  • static - 默认位置;元素将像通常那样流入页面。toprightbottomleftz-index 属性不适用。
  • relative - 元素的位置相对于自身进行调整,不改变布局(因此为元素留下一个间隙,就像它没有定位一样)。
  • absolute - 元素从页面流中移除,并定位在指定位置,相对于其最近的定位祖先(如果有),否则相对于初始包含块。绝对定位的框可以有外边距,它们不会与任何其他外边距折叠。这些元素不影响其他元素的位置。
  • fixed - 元素从页面流中移除,并定位在相对于视口的指定位置,滚动时不移动。
  • sticky - 粘性定位是相对定位和固定定位的混合。元素被视为 relative 定位,直到它越过指定的阈值,此时它被视为 fixed 定位。

您在本地或生产环境中使用过哪些现有的 CSS 框架?您将如何更改/改进它们?

  • Bootstrap - 发布周期缓慢。Bootstrap 4 已经处于 alpha 状态近 2 年。添加一个微调按钮组件,因为它被广泛使用。
  • Semantic UI - 源代码结构使得主题定制极难理解。其非传统的主题系统难以定制。供应商库中硬编码了配置路径。不像 Bootstrap 那样 хорошо 为覆盖变量而设计。
  • Bulma - 需要大量非语义和多余的类和标记。不向后兼容。升级版本会以微妙的方式破坏应用程序。

您玩过新的 CSS Flexbox 或 Grid 规范吗?

是的。Flexbox 主要用于一维布局,而 Grid 主要用于二维布局。

Flexbox 解决了 CSS 中的许多常见问题,例如容器内元素的垂直居中、粘性页脚等。Bootstrap 和 Bulma 基于 Flexbox,它可能是目前创建布局的推荐方式。以前尝试过 Flexbox,但在使用 flex-grow 时遇到了一些浏览器兼容性问题(Safari),我不得不使用 inline-blocks 和数学方法来计算百分比宽度来重写我的代码,这不是一个愉快的经历。

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

您能解释一下将网站编码为响应式与使用移动优先策略之间的区别吗?

请注意,这两种方法并非相互排斥。

使网站具有响应性意味着某些元素将根据设备的屏幕尺寸(通常是视口宽度)通过 CSS 媒体查询进行响应,调整其大小或其他功能,例如,在较小的设备上使字体大小更小。

@media (min-width: 601px) { .my-class { font-size: 24px; } } @media (max-width: 600px) { .my-class { font-size: 12px; } }

移动优先策略也是响应式的,但它认为我们应该默认并为移动设备定义所有样式,然后只为其他设备添加特定的响应式规则。以下是前面的示例:

.my-class { font-size: 12px; } @media (min-width: 600px) { .my-class { font-size: 24px; } }

移动优先策略有两个主要优点:

  • 它在移动设备上性能更高,因为应用于它们的所有规则都不必通过任何媒体查询进行验证。
  • 它强制编写更清晰的响应式 CSS 规则代码。

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

响应式设计和自适应设计都试图优化不同设备上的用户体验,根据不同的视口大小、分辨率、使用环境、控制机制等进行调整。

响应式设计基于灵活性原则——一个单一的流畅网站,可以在任何设备上看起来都很好。响应式网站使用媒体查询、弹性网格和响应式图像来创建用户体验,该体验根据多种因素进行调整和变化。就像一个球在穿过几个不同大小的箍时会膨胀或收缩一样。

自适应设计更像是渐进增强的现代定义。自适应设计不是一个灵活的设计,而是检测设备和其他功能,然后根据一组预定义视口大小和其他特性提供适当的功能和布局。网站检测所使用的设备类型并为该设备提供预设布局。与其让一个球穿过几个不同大小的箍,不如根据箍的大小使用几个不同的球。

这两种方法都有一些需要权衡的问题:

  • 响应式设计可能非常具有挑战性,因为您基本上使用单一的(尽管是响应式的)布局来适应所有情况。如何设置媒体查询断点就是其中一个挑战。您是使用标准化的断点值吗?或者,您是否使用对您的特定布局有意义的断点?如果布局发生变化怎么办?
  • 自适应设计通常需要用户代理嗅探或 DPI 检测等,所有这些都可能不可靠。

您使用过 Retina 图像吗?如果使用过,何时使用以及使用了哪些技术?

Retina 只是一个营销术语,指像素比大于 1 的高分辨率屏幕。关键在于,使用像素比意味着这些显示器正在模拟较低分辨率的屏幕,以显示相同大小的元素。如今,我们认为所有移动设备都是 Retina 默认显示器。

浏览器默认情况下根据设备分辨率渲染 DOM 元素,图像除外。

为了获得清晰、美观的图形,充分利用 Retina 显示器,我们需要尽可能使用高分辨率图像。然而,始终使用最高分辨率图像会影响性能,因为需要通过网络发送更多字节。

为了克服这个问题,我们可以使用 HTML5 中指定的响应式图像。它要求向浏览器提供相同图像的不同分辨率文件,并让浏览器决定哪个图像最好,使用 HTML 属性 srcset 和可选的 sizes,例如:

<div responsive-background-image> <img src="/images/test-1600.jpg" sizes=" (min-width: 768px) 50vw, (min-width: 1024px) 66vw, 100vw" srcset=" /images/test-400.jpg 400w, /images/test-800.jpg 800w, /images/test-1200.jpg 1200w " /> </div>

值得注意的是,不支持 HTML5 srcset 的浏览器(即 IE11)将忽略它并使用 src。如果我们确实需要支持 IE11,并且出于性能原因希望提供此功能,我们可以使用 JavaScript polyfill,例如:

对于图标,我也会选择尽可能使用 SVG 和图标字体,因为它们无论分辨率如何都能清晰渲染。

有什么理由您会选择使用 `translate()` 而不是 `absolute` 定位,反之亦然?为什么?

translate() 是 CSS transform 的一个值。更改 transformopacity 不会触发浏览器回流或重绘,但会触发合成;而更改绝对定位会触发回流。transform 会使浏览器为元素创建 GPU 层,但更改绝对定位属性会使用 CPU。因此,translate() 更高效,并且会缩短绘制时间,从而使动画更流畅。

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