您对CSS的了解程度如何? (+迷你测试)

图片

成功使用CSS与痛苦的尝试之间的区别通常取决于小的细节。 实际上,CSS有很多细微差别。 我经常注意到这种挣扎的最常见区域之一就是样式布局。 我个人喜欢学习CSS模式。 我注意到,我倾向于使用少数几个来解决大多数布局问题。 本文是关于我用来克服布局问题的CSS模式的。 无论使用哪种CSS方法,都将考虑各种情况:无论是SMACSS,BEM还是热门的CSS-in-JS主题,因为它们都只关注CSS属性本身,而不关注体系结构,组织或策略。



为了好玩,让我们从测试开始。


我们将使用我开发的名为Questionable.io的平台并使用它来创建测试,然后继续进行下面的测试。 不用担心,不会收集任何个人数据,结果是匿名的,并且绝对免费。

测试的目的是查看您是否可以在不首先阅读本文的情况下识别出特定的CSS行为和一些问题。 我本来不会使测试困难,但是CSS样式的细微差别可能会非常复杂。 请记住,此测试只是为了好玩。 测试结果不能证明您的冷静,但我希望它们仍然有用。

测验包含10个问题,测验时间不得超过10分钟
来自翻译者:

在有关Habr的文章的末尾,添加了关于该测试中得分的民意测验。

通过测试


注意:如果您不想浪费时间, 这里是带有正确答案的问题的链接

你通过考试了吗 太好了! 让我们一个个地研究这些问题,以更好地了解测试中受影响的样式样式。

问题1:块模型


研究块模型应该是任何FrontEnd开发人员列表中的优先事项。 也许“ CSS Box Model ”一文有些陈旧,请不要低估它对现代CSS的价值和相关性。 块模型是几乎所有与CSS布局相关的问题的基础。

这个特定问题检查如何根据块模型的原理找出宽度。 块在width: 100px具有明确的宽度,但事实证明, 默认块模型规则width属性应用于此块的“内容”层。 结果宽度(在页面上绘制块的宽度)是内容,填充和边框层的总和。 因此,答案是112px。

 .box { width: 100px; /* Take this */ height: 50px; padding: 5px; /* Plus this x2 for left and right */ border: 1px solid red; /* Plus this x2 for left and right */ background-color: red; /* = 112px of computed width */ } 

如果您面临这样的情况,尽管您为所有width: 20%;指定了width: 20%; ,但界面中的最后一列或选项卡将向下移动到下一行width: 20%; 并确保它们可以适合父元素的100%,这可能正在成为一个问题。 五列宽度为20%的列放置在100%中,但是如果另外给它们填充和/或边框,这将增加每列的宽度,在当前行中没有足够的空间用于最后一列。

引入CSS3后,出现了一种称为box-sizing的新工具。 它允许我们控制要将width属性应用于块模型的哪一层。 例如,我们可以指定box-sizing: border-box 。 这意味着我们希望将任何宽度规则应用于外边界层而不是内容层。 在测试的问题中,如果应用了box-sizing: border-box属性,则结果块宽度为100px。

对于某些人来说,这是一个众所周知的事实,但对于专业人士和初学者而言,这仍然是一个很好的提醒。

关于块模型以及如何将box-sizing属性用作重置内容以将其立即应用于整个项目的文章很多。 Box Sizing继承Box- Sizing 可能略好一些最佳实践是阅读CSS技巧的两篇不错的文章。

问题2:元素边界


第二个测试问题可以部分视为第一个测试问题的延续。 请记住,这是一回事:“块模型具有图层(内容,填充,边框),它们都影响元素的总宽度和高度”,另一件事是能够在实际情况下识别出块模型的问题。 在使用CSS已有一段时间的人中,这个特殊的问题有点经典。 这是因为框架是块模型的一部分,因此框架将占据一定的额外空间并推开周围的元素。 在更改元素状态(例如:hover添加框架将意味着这些块将变大,然后其后的块将被下推。 这可能很烦人


在测试问题中提到的所有可能的解决方案中,添加border: 2px solid transparent对原始状态border: 2px solid transparent (无悬停)是解决该问题的唯一方法。 box-sizing无法解决此问题,因为我们没有明确设置高度。 如果这样做,框架将成为元素整体高度的一部分,并且不会发生移位,但这不是我们的情况。

还有其他答案未在答案选项中提及的解决方案。 其中之一是使用box-shadow属性或使用outline而不是border来添加伪border 。 它们中的每一个都不会导致偏差,因为它不是模块模型的一层。 这是另一篇CSS-Tricks文章 ,您可以在其中阅读有关此类解决方案的更多信息。

注意事项:
请记住, outline不支持border-radius

问题3:定位-绝对vs固定


除了了解何时使用每种类型以及它们在视觉表示方式上的区别外,使用top,right,bottom或left属性了解每种定位方法如何绑定到父元素的规则也非常重要。

首先,让我们看一下contains块 。 一个简短的定义是,包含块通常是所讨论元素的父元素。 但是,对于绝对位置和固定位置的元素,包含块的规则不同。

1)对于绝对元素 。 包含块是位​​置不是static的最接近的祖先。 例如,当一个元素绝对定位并包含toprightbottomleft属性时,它们将相对于具有absoluterelativefixedsticky定位的任何父对象进行定位。
2)对于固定元件 。 尽管存在任何除static之外的父元素,但包含块仍是视口。 此外,滚动行为与绝对定位的元素不同。 固定元素在查看区域中保持“固定”状态,因此命名。

许多开发人员认为绝对定位的元素只会寻找具有相对定位position: relative的最接近的父元素position: relative 。 这种误解已经很普遍了,这仅仅是因为position: relative通常与position: absolute配对以构成一个包含块。 经常使用它的原因是父块的相对位置使其留在流中 ,这通常是首选。 在某些情况下,绝对定位元素的父代本身也绝对定位。 这是完全正常的。 如果所有父对象都是静态的,则将绝对定位的元素附加到视口-但它会随视口一起滚动。


上面提到的规则鲜为人知:在父元素具有transform属性( 除其他外 )的值( 除其他值之外)的情况下,它成为绝对固定位置元素的包含块。 可以在CodePen中看到对此的确认,其中元素为文本“ Notice!”。 是一个固定元素,父元素具有transform属性,但仅当鼠标光标:hover在其上时(状态:hover


问题4:父元素和子元素的折叠边距


如果您不知道CSS的工作原理,那么这就是其中的一些小问题。 有一个称为崩溃边距的概念,许多人都熟悉这种现象的表现,称为相邻兄弟姐妹的崩溃边距。 但是,还有另一种形式,称为父级和第一个/最后一个子级的折叠边距,鲜为人知。 以下是这两种情况的演示:


每个段落标签的顶部和底部边距等于1em,由浏览器设置样式。 到目前为止,这是情况中最容易的部分。 但是,为什么段落之间的间距不是2em(顶部和底部的总和)? 这称为相邻兄弟姐妹的折叠边距。 边距重叠的方式是,两个边距中的较大者将是间隙的大小,因此在这种情况下,间隙将为1em。

但是,正在发生其他奇怪的事情。 您是否注意到第一段的上边距与蓝色容器div之间没有空隙? 似乎没有拆分,而是在父div中嵌入了一个边距,好像div有一个顶部边距。 这称为父级和第一个/最后一个孩子的折叠边距。 如果以下特征是父级的特征,则在某些情况下不会发生这种崩溃边距:

  • 上/下填充大于零
  • 上下边界大于零
  • 指定了可以使用overflow: hiddenoverflow: auto创建的块格式化上下文
  • 显示:流根属性集(浏览器支持差)

当我高兴地向人们解释这个CSS小细节并使用padding或border解决它时,答案几乎总是:“ padding或border等于0怎么办?”。 好吧,这不起作用,因为该值必须是一个正整数。

在前面的示例中,1px填充允许我们在使用折叠和防止父子折叠边距之间切换。 在第一个/最后一个段落和父段落之间出现的空间是1px填充,但现在边缘被视为容器的内部,因为填充层创建了一个屏障来防止边缘塌陷。

至于问题,我确定您可以在此界面中看到问题所在:


具有.comment类(不含.moderator类)的第一个元素折叠边距。 即使不看代码,我们也可以看到带有.moderator类的元素具有框架,而没有此类的元素则没有。 在这个问题上实际上有三个答案被认为是正确的,实际上每个答案都已经在CodePen源代码中应用,只是被注释掉了。

这种倒塌边距没有广为人知的原因之一,是因为在许多情况下我们可以不小心避免这种情况。 Flexbox和Grid元素创建块格式化上下文,因此在使用它们时,我们不会遇到这种折叠边距。 如果我们的评论的界面是一个真实的项目,则很有可能在所有四个面上都设置了填充物以留出空间,这反过来又为我们解决了利润率下降的问题。

问题5:百分比是多少?


使用百分比单位时,百分比基于包含块(通常是父块)的宽度或高度。 如前所述,具有transform属性的元素将成为包含块,因此当该元素使用transform时,以百分比为单位的单位(仅适用于transform )是元素自身的大小,而不是父元素的大小。

在下面的示例中,我们可以看到50%根据上下文采用两个不同的值。 第一个红色块具有margin-left: 50%属性margin-left: 50% ,第二个红色块使用transform: translateX(50%)


问题6:区块模型再次出现...


只有您认为我们已经结束了关于块模型的讨论...


问题是由于我们使用width: 100%页脚为width: 100% ,同时添加了填充这一事实。 容器的宽度为500px,这意味着在将填充添加到此大小之前,页脚内容层(为100%)也是500px。

可以通过以下两种常用技术之一解决此问题:

  1. 直接或通过前面提到的重置为页脚使用box-sizing属性
  2. 从元素中删除width属性,并改用left: 0right: 0属性。 这是同时使用leftright属性的一个很好的例子。 此方法避免了块模型的问题,因为当设置left: 0right:0时, width属性将使用其默认值auto填充填充和边框之间的任何可用空间。

注意:一种选择是从页脚中删除填充。 从技术上讲,这将解决此问题,因为内容层将为100%,并且没有填充或边框来扩展超出容器的宽度。 但是我认为这种解决方案是错误的方法,因为我们不必为了适应块模型的问题而更改接口,而无需使用它就可以轻松解决。

对我来说,现实是,我始终将box-sizing: border-box属性box-sizing: border-box为常规样式重置的一部分。 如果执行相同的操作,则极有可能很少遇到此问题。 但是我仍然喜欢同时设置属性left:0right:0的技术,因为如时间所示,它比解决由于宽度引起的块模型问题更可靠(无论如何,根据我的经验)。 100%

问题7:将绝对元素和固定元素居中


现在,我们真的开始结合绝对和固定元素的居中组合上述所有材料:


由于我们已经在该测试问题中涵盖了大多数材料,因此我仅表示可以使用老式方法通过负边距完成水平居中和垂直居中,或者使用transform属性来更新居中。 我还提醒您注意出色的CSS-Tricks元素居中指南

注意 :前段时间有人争论说,如果我们知道块的宽度和高度,则应该使用负边距,因为它们比新的转换属性更稳定地工作。 此刻,转换工作稳定,并且我几乎总是使用此属性,除非需要避免将块转换为包含该块的属性。

问题8:在正常流程中居中放置元素


Flexbox为我们带来了许多神奇的工具来解决复杂的布局问题。 据报道,在发布之前,垂直居中是CSS中实现的最复杂的功能之一。 随着Flexbox的出现,垂直居中已成为常规做法:

 .parent { display: flex; } .child { margin: auto; } 

https://codepen.io/bradwestfall/pen/GPNmbM
注意 :请注意,对于flex元素,margin:auto应用于顶部,底部,右侧和左侧,以使元素垂直和水平居中。 以前,垂直居中不适用于图块元素,因此margin: 0 auto;很常见margin: 0 auto;

问题9:使用不同单位的计算


当您需要使用两个我们无法单独加起来的度量单位时,或者需要使分数更易于理解时,使用calc()函数非常有用。 这个测试问题使我们能够从div元素的宽度为100px的事实开始,找出calc(100% + 1em)表达式的结果。 这可能有点令人困惑,因为事实上,div元素的宽度为100px无关紧要。 百分比总是从​​父对象的宽度开始,因此正确的答案是:“包含(父)块的100%加上1em”。

在几种情况下,我会定期使用calc() 。 首先,每当我想将内容移动100%时,还要添加固定数量的额外空间。 下拉菜单可能是一个很好的例子:


这里的特殊之处是我们希望创建一个下拉菜单,该菜单可以与不同大小的调用元素(在这种情况下,是两个不同大小的按钮)一起使用。 我们不知道调用此菜单的元素的高度,但是我们知道top: 100%的高度top: 100%会将下拉菜单的顶部边缘放在调用按钮的底部边缘。 如果每个菜单应位于相应按钮的底部边缘,加上0.5em,则可以使用calc(100% + 0.5em)来实现。 当然,我们也可以使用top: 110% ,但是这另外的10%取决于调用按钮和容器的高度。

问题10:负边距


与排斥同胞的正边距不同,负边距使它们彼此靠近而不移动同胞 。 这个最后的测试问题提供了两种解决方案,从技术上来讲,这两种方法都消除了按钮组中的双边框,但是我强烈希望使用负边距技术,因为删除边框会使得执行某些技术(如鼠标悬停效果)更加困难。


结果是在按钮之间显示了一个“公共边框”。 实际上,按钮不能具有公共边界,因此我们需要使用负边距技术,以便一帧与另一帧重叠。 然后,根据鼠标悬停的状态,使用z-index设置我要适合哪个框架。 请注意,即使没有使用绝对定位, z-index在这里也很有用,但是您必须设置position: relative 。 如果我使用了删除第二个按钮的左框架的技术,则将很难实现这种效果。

这一切都说得通。


我想向您展示另一个最新的演示,该演示使用了我们之前讨论的许多技巧。 该任务是考虑到凹痕,创建可扩展到容器左右边缘的图块。 我说的是图块,是指当宽度不足时,可以具有包装到下一行的块列表的功能。 将鼠标悬停在图块上方即可查看结果:


执行此任务的障碍是缩进。 如果不使用填充,则很容易获得与容器左右边缘相邻的图块。 问题是缩进将使用边距创建,并且当我们在图块的所有侧面上添加边距时,我们会创建两个问题:

  1. 三个宽度为33.33%瓷砖与边距一起无法连续容纳。 尽管box-sizing允许我们在.tile元素上具有填充和边框并适合33.33% ,但这在边距的情况下无济于事-这意味着三个图块的计算宽度将超过100%,这将迫使最后一个图块移动到下一个图块字符串。
  2. 左右瓷砖将不再靠着容器的边缘。

第一个问题可以用解决calc((100% / 3) - 1em)。这意味着33.33%减去每个图块的左边界和右边界。相邻姊妹元素的折叠不会在这里发生,因为这仅可能在上下边界处发生。结果,两个图块之间的水平距离是两个边距之和(1em)。在这种情况下,塌陷也不适用于上下边缘,因为即使在视觉上一个在另一个下方,第一个和最后一个图块在技术上也不相邻。

通过与calc()可以连续放置三块瓷砖,但它们仍然不会碰到容器的边缘。为此,我们可以使用负边距,其大小等于每个图块的左右边距。该示例中的绿色虚线是一个容器,在其中我们应用负边距来绘制与周围内容的边缘相对应的图块。我们可以看到它们如何适合父元素的填充区域。这是正常现象,因为负边距不会排斥周围的相邻元素。

结果,我们得到的图块具有足够的空间,可以从一个边到另一个边扩展,以便它们与图块外的相邻段落标签对齐。

制作瓷砖的方法有很多(通常都有优点和缺点)。例如,Haydon Pickering谈到了一个非常优雅的CSS Grid解决方案。此解决方案使用模拟容器请求的技术(但使用Grid Magic)实现。最终,他的使用Grid的解决方案比flexbox更好,我已演示了它,但对浏览器的支持较差。

总结


一开始,我说过我倾向于寻找解决问题的模式。本文与以上演示的场景无关;它更多是关于可以用来解决我们都可能遇到的这些以及许多其他排版问题的一组工具。希望这些工具对您有所帮助。

顺便说一下,有许多优秀的资源可以仔细地检查块模型的主题。首先,Rachel Andrew和Jen Simmons的文章绝对值得一读。

  • 框对齐备忘单是一种出色的材料,具有视觉元素,这些元素会强调影响元素单独或相对于其他元素对齐方式的各种属性。
  • Jen Simmons Labs — , .

Source: https://habr.com/ru/post/zh-CN467555/


All Articles