【问题标题】:Sigmoid Curve Shape with CSS带有 CSS 的 S 形曲线形状
【发布时间】:2017-03-14 00:35:39
【问题描述】:

我想为全屏布局创建一个类似sigmoid curve 的形状,在一侧显示装饰图案背景,在另一侧显示纯色背景,以便将文本放置在顶部它。

我们的目标是让全屏页面的左上角充满图案,而页面的其余部分只有白色背景。

JSFiddle:Unfinished sigmoid curve

#container {
  padding-top: 10%;
  padding-bottom: 10%;
  background: white url(http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg) top left / 26px 32px repeat;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#parallelogram {
  margin-left: 35%;
  width: 100%;
  height: 900px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
  background: white;
  -moz-border-radius: 100px;
  -webkit-border-radius: 100px;
  border-radius: 100px;
  -moz-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  -webkit-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
}
<div id="container">
  <div id="parallelogram">
  </div>
</div>

我不知道如何在左下角附近创建(或模拟)倒圆角。

或者也许有一个概念上不同(更好)的解决方案可用?

更新:我想出了如何完全使用 CSS 创建 shape I need

#container {
  padding-top: 100px;
  background: red;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#parallelogram {
  margin-left: 400px;
  width: 100%;
  height: 900px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
  background: white;
  -moz-border-top-left-radius: 100px;
  -webkit-top-left-border-radius: 100px;
  border-top-left-radius: 100px;
}
#bottom {
  height: 200px;
  width: 100%;
  background: white;
}
#bottom-corner {
  height: 100px;
  width: 300px;
  margin-left: -34px;
  background: red;
  -moz-border-bottom-right-radius: 100px;
  -webkit-bottom-right-border-radius: 100px;
  border-bottom-right-radius: 100px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
}
<div id="container">
  <div id="parallelogram">
  </div>

  <div id="bottom">
    <div id="bottom-corner">
    </div>
  </div>
</div>

但是,这仍然不是最终解决方案,因为形状不允许我使用我想到的那种背景效果。当我尝试时会发生以下情况:fiddle

#container {
  padding-top: 100px;
  background: white url(http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg) bottom left / 26px 32px repeat;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#parallelogram {
  margin-left: 400px;
  width: 100%;
  height: 900px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
  background: white;
  -moz-border-top-left-radius: 100px;
  -webkit-top-left-border-radius: 100px;
  border-top-left-radius: 100px;
  -moz-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  -webkit-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
}
#bottom {
  height: 200px;
  width: 100%;
  background: white;
  -moz-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  -webkit-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
}
#bottom-corner {
  height: 100px;
  width: 300px;
  margin-left: -34px;
  background: white url(http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg) top left / 26px 32px repeat;
  -moz-border-bottom-right-radius: 100px;
  -webkit-bottom-right-border-radius: 100px;
  border-bottom-right-radius: 100px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
  -moz-box-shadow: 0 0 15px rgba(0, 0, 0, .4);
  -webkit-box-shadow: 0 0 15px rgba(0, 0, 0, .4);
  box-shadow: 0 0 15px rgba(0, 0, 0, .4);
}
<div id="container">
  <div id="parallelogram">
  </div>

  <div id="bottom">
    <div id="bottom-corner">
    </div>
  </div>
</div>

稍后更新:经过一番反复试验,我最终得到了一个ridiculously crude hack solution,它达到了我需要的视觉效果:

#container {
  padding-top: 100px;
  background: white url(http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg) top left / 26px 32px repeat;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
#parallelogram {
  margin-left: 385px;
  width: 100%;
  height: 900px;
  -webkit-transform: skew(-15deg);
  -moz-transform: skew(-15deg);
  -o-transform: skew(-15deg);
  transform: skew(-15deg);
  background: white;
  -moz-border-top-left-radius: 100px;
  -webkit-top-left-border-radius: 100px;
  border-top-left-radius: 100px;
  -moz-box-shadow: inset 0 15px rgba(0, 0, 0, .4);
  -webkit-box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
  box-shadow: inset 0 0 15px rgba(0, 0, 0, .4);
}
#bottom-rounded-corner {
  height: 122px;
  position: relative;
  width: 200%;
  z-index: 1000;
  margin-top: -80px;
  margin-left: -185px;
  background: url(http://famok.com/wp-content/uploads/2016/11/CornerAndMask.png) top left no-repeat;
}
#bottom-white {
  height: 100px;
  width: 100%;
  background: white;
}
<div id="container">
  <div id="parallelogram">
  </div>
  <div id="bottom-rounded-corner">

  </div>
  <div id="bottom-white">
  </div>
</div>

尽我所能实现下面 Harry 建议的概念上更好的替代方案,但我无法使用它来创建我想要的效果。如果有人可以提供帮助,或者通过展示如何做到这一点,或者通过对我的解决方案提出优化建议,我仍然会很感激。

提前谢谢你!

【问题讨论】:

  • 不,这样的效果不要使用 CSS。他们非常棘手。最好使用 SVG。在这个线程中有几个 CSS 方法可以创建类似波浪的图案(或 sigmoid 曲线)-stackoverflow.com/questions/27777470/…,但也有一个 SVG 解决方案。快速比较会告诉你哪个更好用:)
  • 非常感谢@Harry! SVG 似乎正是我所需要的。你能帮我进一步吗?考虑到我需要全屏 sigmoid 形状 - 左下方的水平线,弯曲的角度和向右上方上升,然后是右侧的弯曲角度和水平线 - 这如何用 SVG 实现?您能否将其发布为答案,以便我接受?
  • 我在前面的线程中链接的 SVG 答案确实有水平线,并且曲线 + SVG 默认情况下是可缩放的。我建议您尝试使 SVG 适应您的情况,如果遇到砖墙,请在答案中发布 SVG 代码。
  • 谢谢@Harry。另一个问题 - 如何将插入框阴影添加到 SVG?除非我弄错了,否则该单独线程中提供的解决方案似乎不允许这样做。
  • 抱歉,我现在没有时间起草答案,但你可以看看这个在 SVG 中创建嵌入阴影的线程 - stackoverflow.com/questions/20778568/…

标签: css svg css-shapes rounded-corners


【解决方案1】:

对复杂形状使用 SVG 而不是 CSS:

正如我在 cmets 中提到的,请不要使用 CSS 来创建如此复杂的形状。 SVG 是此类复杂事物的推荐工具。 SVG 易于创建、维护,并且默认情况下也具有响应性(可扩展),因此具有很多优势。


创建 sigmoid 形状:

使用 SVG 本身创建 sigmoid 曲线形状非常简单,只需要一个路径元素:

  • M0,750 将假想的笔移动到靠近 SVG 元素的左下角(坐标设置为略低于 SVG 的高度,以便在底部有一个间隙可以看到阴影)。
  • L250,750 生成从点 (0,768) 到 (250,768) 的水平 Line
  • C650,730 500,154 1024,154 创建实际曲线。这里前两个坐标是曲线的控制点((650,730),(500,154)),第三个坐标是终点(1024,154)。可以通过修改控制点来调整曲线的曲率。
  • L1024,0 0,0 0,750 用于完成形状。形状需要完整,填充才能起作用。

body {
  margin: 0;
}
svg {
  width: 100%;
  height: 100vh;
}
<svg viewBox='0 0 1024 768' preserveAspectRatio='none'>

  <!-- For the shadow -->
  <defs>
    <filter id="dropShadow">
      <feGaussianBlur in="SourceAlpha" stdDeviation="6" />
      <feOffset dx="3" dy="3" result="offsetBlur" />
      <feFlood flood-color="#AAA" flood-opacity="1" result="offsetColor" />
      <feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur" />
      <feMerge>
        <feMergeNode />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
  </defs>
  <!-- End of shadow -->

  <!-- For filling the top-left with pattern -->
  <pattern id='dots' patternUnits='userSpaceOnUse' width='25' height='25'>
    <polygon points='0,0 0,25 25,25 25,0' fill='yellowgreen' />
    <circle cx='12.5' cy='12.5' r='4' fill='rebeccapurple' />
  </pattern>
  <!-- End of pattern -->

  <!-- Actual sigmoid curve -->
  <path d='M0,750 L250,750 C650,730 500,154 1024,154 L1024,0 0,0 0,750' fill='url(#dots)' filter='url(#dropShadow)' />

</svg>

将图案应用于形状:

在上面的演示中,我使用 polygoncircle 元素创建了一个圆点图案,但在 SVG 本身中创建它不是强制性的,我们也可以使用 image 元素并填充形状图像模式。

如果您想将背景图片(图案)更改为您选择的另一张图片,只需在image 标记的xlink:href 属性中指定图片的 URL,如下面的 sn-p 所示。根据您的需求和形象,您可能需要更改patternimageheightwidth

<pattern id='dots' patternUnits='userSpaceOnUse' width='25' height='25'>
  <image xlink:href='https://yourwebsite.com/yourpath' x='0' y='0' width='15' height='15' />
</pattern>

body {
  margin: 0;
}
svg {
  width: 100%;
  height: 100vh;
}
<svg viewBox='0 0 1024 768' preserveAspectRatio='none'>
  <defs>
    <filter id="dropShadow">
      <feGaussianBlur in="SourceAlpha" stdDeviation="6" />
      <feOffset dx="3" dy="3" result="offsetBlur" />
      <feFlood flood-color="#AAA" flood-opacity="1" result="offsetColor" />
      <feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur" />
      <feMerge>
        <feMergeNode />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
    <pattern id='dots' patternUnits='userSpaceOnUse' width='36.6' height='46'>
      <image xlink:href='http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg' x='0' y='0' width='36.6' height='46' />
    </pattern>
  </defs>
  <path d='M0,750 L250,750 C650,730 500,154 1024,154 L1024,0 0,0 0,750' fill='url(#dots)' filter='url(#dropShadow)' />
</svg>

注意:以上演示中使用的图片不是我自己的。取自网络。


影子:

阴影效果是通过使用 SVG filter 元素以及 feGaussianBlurfeOffsetfeMerge 元素创建的。 feGaussianBlur 元素通过指定的标准偏差值模糊源图形(我们的 sigmoid),feOffset 通过dxdy 值偏移结果图像。使用feMerge 合并原始图像和模糊图像。添加 feFloodfeComposite 以防万一你想给阴影一个不同的颜色。可以使用flood-colorflood-opacity 属性指定颜色。 (更改 SVG 投影颜色的方法取自 Joe W 的 this answer。)


添加文字:

现在这是整个事情中真正棘手的部分。如果您只需要将文本放置在页面的纯色区域,那么您需要谨慎使用定位属性。如果文本很小或只有一行文本,那么我们可以使用 SVG text 元素本身,就像我之前链接的演示中一样。如果不是,那么您必须确保文本的容器框不会与 sigmoid 形状的区域重叠。

body {
  margin: 0;
}
div.container {
  position: relative;
  width: 100%;
  height: 100vh;
}
svg {
  position: absolute;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
}
.container div {
  position: absolute;
  top: 50%;
  right: 0px;
  height: 30vh;
  width: 33.33%;
  font-size: 20px;
}
<div class='container'>
  <svg viewBox='0 0 1024 768' preserveAspectRatio='none'>

    <defs>
      <!-- For the shadow -->
      <filter id="dropShadow">
        <feGaussianBlur in="SourceAlpha" stdDeviation="6" />
        <feOffset dx="3" dy="3" result="offsetBlur" />
        <feFlood flood-color="#AAA" flood-opacity="1" result="offsetColor" />
        <feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur" />
        <feMerge>
          <feMergeNode />
          <feMergeNode in="SourceGraphic" />
        </feMerge>
      </filter>
      <!-- End of shadow -->

      <!-- For filling the top-left with pattern -->
      <pattern id='dots' patternUnits='userSpaceOnUse' width='25' height='25'>
        <polygon points='0,0 0,25 25,25 25,0' fill='yellowgreen' />
        <circle cx='12.5' cy='12.5' r='4' fill='rebeccapurple' />
      </pattern>
      <!-- End of pattern -->
    </defs>

    <!-- Actual sigmoid curve -->
    <path d='M0,750 L250,750 C650,730 500,154 1024,154 L1024,0 0,0 0,750' fill='url(#dots)' filter='url(#dropShadow)' />

  </svg>
  <div>Hello! Here is some text that is placed on the solid colored area of the page.</div>
</div>

我们可以尝试使用 CSS shape-outside 属性,但目前使用 browser support for that is pretty poor。这是一个使用shape-outside 属性的demo。无法在现场托管它,因为它需要创建一个单独的 SVG 文件。该演示是W3C CSS Shapes Spec 中提供的演示的改编版本。


替代方法:(将模式应用于容器而不是 SVG)

由于您不希望图像被压扁或拉伸,另一种方法是执行以下操作:

  • 创建 SVG 形状,使其只有纯色部分(而不是图案区域)
  • 将该模式应用于div.container,然后将SVG 绝对放置在元素的顶部。 SVG 形状(具有白色填充)将防止图案在另一侧可见。
  • 将 SVG 上的阴影从普通投影更改为嵌入阴影。 (Inset Shadow 的代码完全取自here

body {
  margin: 0;
}
div.container {
  position: relative;
  background: white url(http://famok.com/wp-content/uploads/2016/10/WhiteOnWhite.jpg) top left / 26px 32px repeat;
  width: 100%;
  height: 100vh;
}
svg {
  position: absolute;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
}
.container div {
  position: absolute;
  top: 50%;
  right: 0px;
  height: 30vh;
  width: 33.33%;
  font-size: 20px;
}
<div class='container'>
  <svg viewBox='0 0 1024 768' preserveAspectRatio='none'>
    <defs>
      <filter id="dropShadow" x="-50%" y="-50%" width="200%" height="200%">
        <feComponentTransfer in=SourceAlpha>
          <feFuncA type="table" tableValues="1 0" />
        </feComponentTransfer>
        <feGaussianBlur stdDeviation="6" />
        <feOffset dx="2" dy="2" result="offsetblur" />
        <feFlood flood-color="#AAA" result="color" />
        <feComposite in2="offsetblur" operator="in" />
        <feComposite in2="SourceAlpha" operator="in" />
        <feMerge>
          <feMergeNode in="SourceGraphic" />
          <feMergeNode />
        </feMerge>
      </filter>
    </defs>
    <path d='M0,750 L250,750 C650,730 500,154 1024,154 L1024,768 0,768 0,750' fill='white' filter='url(#dropShadow)' />
  </svg>
  <div>Hello! Here is some text that is placed on the solid colored area of the page.</div>
</div>

这里是 Plunker Demo 的替代方法。这比前一个复杂一点,因为这里我们需要一个 SVG 来生成纯色区域(用作 img)和另一个 SVG,它是与 shape-outside 一起使用的反向(图案区域)。

【讨论】:

  • 谢谢你,哈利 - 很好的答案!我有三个明确的问题:如果我需要改变对角线的角度,如何实现? (我需要精确的 33 度角)。另外,阴影如何延伸到左下角的水平线以下?最后,我如何才能专门使用我需要使用的背景图像?能否请您进一步提供帮助?
  • @DimitriVorontzov:(1) 我不是数学专家,所以对此无能为力。我会尝试看看我是否能找到任何东西,但不能保证。您可以使用控制点坐标来获得最接近您期望的任何东西。 (2)我会更新我的答案。我们只需将形状坐标向上移动一点,以便在 SVG 的盒子内可以看到阴影。 (3) 在代码中使用第二个sn-p,在image 标签的xlink:href 属性中提供图片的URL。应该这样做。
  • 哈利,你能在答案中显示阴影和背景图像吗?
  • 太棒了。谢谢@Harry - 但它不适用于我的图片:jsfiddle.net/CybArt/myh6e1hc。不幸的是,这使得该解决方案对我来说无法使用,尽管它很棒。如何使它与我需要它的背景一起工作?请给我看看好吗?
  • 就是那个!谢谢@Harry!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-10
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 2014-09-02
  • 2019-06-15
  • 1970-01-01
相关资源
最近更新 更多