圆润饱满:CSS 中的复合形状

Avatar of Parker Bennett
Parker Bennett

DigitalOcean 提供适用于您旅程各个阶段的云产品。立即开始使用 $200 免费信用额度!

以下是 Parker Bennett 的客座文章。Parker 是这里常客,以用独特解决方案解决常见问题而闻名。这次他回来了,创造了具有图像背景、阴影和曲线的复杂形状,而且灵活多变。

我喜欢在设计上进行合作,因为它经常促使我去尝试新事物。最近,我得到了一份类似这样的设计草图:一个圆润的复合形状用作固定标题,有一个带内阴影的纹理内嵌(一个“井”)。好吧,我想,这能有多难呢?

曲线美!

当然,一个答案非常简单:我可以选择切片图像并使用透明的 .png 文件来制作弯曲的底部——阴影和所有——并使用一个“端盖”,允许右侧响应式地调整大小(第一列设计为固定宽度)。

但我想在未来拥有更多的灵活性,所以我决定使用 CSS 来解决它。这是我最终采用的方法,没有什么神奇的,只是老式的 CSS

CodePen 真棒!

CodePen 对我所有的实验以及客户审核都不可或缺。一个很大的优势是可以编写 SCSS 并快速查看结果:我可以通过更改变量来尝试不同的宽度、颜色、阴影、圆角等。

我使用变量来表示某些高度和宽度,以及 box-shadowborder-radius 大小,然后使用它们来计算额外的大小——在有意义的情况下使用比率将设计的元素绑定在一起。

变量很棒!

陷入困境

对于大多数项目,我使用一个居中的 .page-wrap,它占浏览器窗口的百分比。但是,当您使用 position: fixed 将标题固定在顶部时,它不再包含在页面包装中。一种解决方案是在固定标题之后开始页面包装,并包含一个标题包装,它复制页面包装的宽度、边距和填充(此 CodePen 中的详细信息).

为了保持滚动内容在标题下方“剪切”部分的错觉,我使用 overflow: hidden 在侧面裁剪标题的阴影。这意味着需要一个第二个包装 div,以便在小宽度下也保持内容与窗口框架之间的一点填充(是的,我真的很注重细节)。

z-index:升级

当然,我想保持标记精简,并且不依赖于源顺序进行布局。我在有意义的地方使用伪元素,并大量依赖绝对定位来放置元素——使用 z-index 来更改它们重叠的方式。因为绝对定位会将元素从布局流中移除,所以我需要在某些情况下进行补偿,例如,向其他元素添加 padding 来填补该空间。

当我解决定位问题时,我发现由于堆叠顺序的特殊性,我可以陷入 z-index 死角:z-index 要求定位才能工作,未定位元素优先渲染,并且很容易跟踪哪些元素受到“堆叠上下文”约束——例如,伪元素不能高于其父元素的 z-index (在 CodePen 上查看演示).

我还改变了阴影的 z-index,使它们成为一个单独的伪元素。这让我可以将阴影塞到需要被遮挡的对象后面,或者像 .main 滚动内容的侧面那样,将它们提升到覆盖到达边缘的任何内容,从而不会破坏深度的错觉。

/* elements that reach the edges of .main need to fall
   under edge shadow to maintain "cut-out" illusion */

.well-sides {
  /* child elements absolute */
  position: relative;
  overflow: hidden; }

.well-sides:before, .well-sides:after {
  content: "";
  display: block;
  position: absolute;
  /* higher than any z-index in .main, lower than header */
  z-index: 99;
  /* shadow size */
  top: -20px;
  height: 120%;
  /* shadow size */
  width: 20px;
  background: transparent; }

.well-sides:before {
  left: 0;
  /* negative spread */
  -webkit-box-shadow: inset 20px -20px 20px -20px rgba(0,0,0,0.35);
     -moz-box-shadow: inset 20px -20px 20px -20px rgba(0,0,0,0.35);
          box-shadow: inset 20px -20px 20px -20px rgba(0,0,0,0.35); }

.well-sides:after {
  right: 0;
  /* negative spread */
  -webkit-box-shadow: inset -20px 20px 20px -20px rgba(0,0,0,0.35);
     -moz-box-shadow: inset -20px 20px 20px -20px rgba(0,0,0,0.35);
          box-shadow: inset -20px 20px 20px -20px rgba(0,0,0,0.35); }

切角

不幸的是,没有实用的方法可以在 CSS 中创建具有凹形曲线的对象。在两个圆角矩形连接的地方,我使用了一个“补丁”来覆盖 inset box-shadow 的“缝隙”,并将纹理背景延伸到内角区域。然后,我用一个圆角的白色角将其覆盖,将负空间作为正空间。最后,我在圆角上添加了一个普通的 box-shadow(被 overflow: hidden 裁剪),使其与 inset box-shadow 融合。

“补丁”中的外阴影必须稍微“不透明”一些,以匹配内阴影。
内圆

对于其他内曲线,我在每侧放置一个具有一个圆角和一条厚白色边框的透明正方形,以完成错觉。我使用 border-radiusbox-shadow 大小作为变量来确定角的大小和位置。

它们是如何堆叠的

以下是我如何将这些部分拼凑在一起

这里有幻灯片。如果您通过聚合阅读,请查看真实的博客文章以查看幻灯片。

<
>

  • 总结

    确实我喜欢挑战,但以这种方式解决问题也让我在过程中获得了很大的灵活性,并在移动响应式布局上领先一步(在更小的尺寸下将弯曲的底部拉直,截断菜单等)。无论如何,我希望您在我过于详尽的探索中发现了一些有用的东西。如果您有任何问题、评论或更正,请给我留言:parker@parkerbennett.com.