以下是 Parker Bennett 的客座文章。Parker 是这里常客,以用独特解决方案解决常见问题而闻名。这次他回来了,创造了具有图像背景、阴影和曲线的复杂形状,而且灵活多变。
我喜欢在设计上进行合作,因为它经常促使我去尝试新事物。最近,我得到了一份类似这样的设计草图:一个圆润的复合形状用作固定标题,有一个带内阴影的纹理内嵌(一个“井”)。好吧,我想,这能有多难呢?

当然,一个答案非常简单:我可以选择切片图像并使用透明的 .png 文件来制作弯曲的底部——阴影和所有——并使用一个“端盖”,允许右侧响应式地调整大小(第一列设计为固定宽度)。
但我想在未来拥有更多的灵活性,所以我决定使用 CSS 来解决它。这是我最终采用的方法,没有什么神奇的,只是老式的 CSS
- 在 CodePen 上编辑(只是要点)
- 在 CodePen 上编辑(完整的最终布局)
CodePen 真棒!
CodePen 对我所有的实验以及客户审核都不可或缺。一个很大的优势是可以编写 SCSS 并快速查看结果:我可以通过更改变量来尝试不同的宽度、颜色、阴影、圆角等。
我使用变量来表示某些高度和宽度,以及 box-shadow
和 border-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-radius
和 box-shadow
大小作为变量来确定角的大小和位置。
它们是如何堆叠的
以下是我如何将这些部分拼凑在一起
这里有幻灯片。如果您通过聚合阅读,请查看真实的博客文章以查看幻灯片。












我的天啊,太棒了。简直是绝妙的解决方案,现在让我想要重构一大堆代码!
非常巧妙,但这不是每个人都会经常使用的技术。感觉很糟糕而且很 hacky。
这绝对是一个需要解决的问题,而 CSS 目前没有提供解决方案。
我同意——确实感觉很糟糕而且很 hacky。
它很复杂,但我不会认为这里有任何东西是“hack”(就该词的相关含义而言,即使用工具来实现它原本不设计的功能)。但没错,这确实突出了当前 CSS 状态下严重缺乏的一些地方。
WebKit 有一个很棒的 drop-shadow 过滤器,它可以解决重叠阴影问题(它会绘制阴影,同时考虑到伪元素,请参见 此 CodePen)。
很棒的解决方案。
有用的技巧!
我不知道“hacky”是否公平——我只是无法接受所有多余的非语义标记。
哇,真是篇好文章。我一直用 CSS 来创建类似于这种的复杂圆角。非常感谢这篇文章。这正是我一直在寻找的东西!
很棒的文章!我很喜欢“How It All Stacks Up”部分,可以看出它的演变。谢谢!
又一篇很棒的文章。
非常感谢你,Chris!
这前端工作绝对是狂野的创意,太令人惊叹了。向你致敬,Parker Bennett 先生。
但我必须同意上面 Jon Hobbs 和 G Givan 的说法,很难忽略 G Givan 所说的“...多余的非语义标记。”
另一方面,是你实际被给予的设计:这清楚地表明了一个平面设计师在做网页设计。完全“不切实际”和被破坏的设计。那位设计师是世界上最幸运的人之一,因为有你,一位知识渊博的开发者,来实现他的设计。
你在这里做的一切让我想起了我在大学学习设计(用于印刷)的日子,我们使用 CorelDRAW(是的,根本不需要 Illustrator;]),我们都在使用白色方块来隐藏周围的东西等等。当你以线框模式查看设计时,你会看到整个设计中到处都是这些矩形(尤其是在覆盖元素出血的侧面)。后来才发现 Powerclips 的强大功能:)。
CSS 还有很多东西需要学习……
从技术上来说,很酷。从实际角度来说,不酷。
如果我看到一个类似这样的设计,有斜角边缘和圆角,但没有看到代码,我会立即假设它是一个切片好的 PSD,用了一些透明 PNG。
让我想起了我在 2005 年大学时创作的东西。我再也不会设计出这样的网站了:)
太尴尬了。我不希望 CSS 使这种布局更容易创建……在我看来,这只是退步。