创建响应式云形状

Creating a responsive cloud shape

我一直在尝试在 CSS 中为一个项目创建响应式云形状。由于 HTTP 请求和响应能力的要求,我尽量不对图像、CSS 或内联 SVG 执行此操作。

有问题的形状是这样的:(但可以类似 - 轻微的 variations/improvements 会很酷):

我已经找到了这两个问题,但它们似乎并不适合我的确切需求:

我曾尝试(但失败了)使用 borderbox-shadow 创建云,并且需要知道使用 CSS 或作为替代方案的内联 SVG 是否可行.我也看到 Canvas 也是一个选项,但我宁愿远离它,因为它可能非常复杂。

这是我的可怜的尝试

body {
  background: skyblue;
}

.cloud {
  width: 15%;
  height: 10vh;
  background: white;
  position: relative;
  margin: 100px 100px;
  border-radius: 65px;
  box-shadow: black 0 0 10px 10px;
}
.cloud:after {
  content: '';
  position: absolute;
  width: 150px;
  height: 150px;
  top: -60px;
  left: 100px;
  border-radius: 75px;
  background: white;
}
.cloud:before {
  content: '';
  position: absolute;
  width: 70px;
  height: 70px;
  background: white;
  left: 50px;
  top: -30px;
  border-radius: 35px;
}
<div class="cloud"></div>

如您所见,我在响应能力和准确计算 heights/widths 一切所需方面遇到了问题。

我也在努力将 HTML 的数量保持在绝对最小值,因此我真的更喜欢使用单个 div 或短 SVG 代码。

浮云和彩虹。

Disclaimer: There are no rainbows here

但是,下面是一个基本的 'cloud',由单个元素构成,并且由于它使用 vw 单位,因此它也相当灵敏。

它使用两个形状为圆形的伪元素在顶部创建云 'puffs'。这也允许使用边框,因为您可以旋转圆圈并将边框颜色应用于其中两个边。

.cloud {
  height: 30vw;
  width: 90vw;
  background: lightgray;
  border-radius: 40vw;
  border: 5px solid black;
  position: relative;
  margin-top: 20vw;
}
.cloud:before {
  content: "";
  position: absolute;
  top: -10vw;
  box-sizing: border-box;
  height: 20vw;
  width: 20vw;
  left: 15vw;
  border-radius: 50%;
  border: 5px solid black;
  border-bottom-color: transparent;
  border-right-color: transparent;
  background: lightgray;
  transform: rotate(40deg);
}
.cloud:after {
  content: "";
  position: absolute;
  height: 40vw;
  width: 40vw;
  top: -20vw;
  left: 32vw;
  border-radius: 50%;
  box-sizing: border-box;
  border: 5px solid black;
  border-bottom-color: transparent;
  background: lightgray;
  border-right-color: transparent;
  transform: rotate(55deg);
}
<div class="cloud"></div>

Whilst this answer is using CSS, it may be more beneficial using an SVG if you required more control over the output of the cloud shape.


或者,SVG 也可以使用 path 声明实现这样的形状 请注意这是生成的,而不是手动创建的 等等我不以此为荣):

<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
  <g>
    <path d="M320,128c52,0,95,42,96,94c-0,1-0,3-0.5,5l-0.812,23l22,7
  C462,268,480,293,480,320c0,35-28,64-64,64H96c-35,0-64-28-64-64c0-34,28-63,63-64
  c1,0,3,0,4,0l24,1l8-22C140,209,165,192,192,192c3,0,6,0,11,1
  l22,4.031l11-19C253.875,146,285,128,320,128 M320,96c-47,0-89,26-111,65
  C203,160.719,197,160,192,160c-41,0-77.219,27-90.281,64.563C99.813,224.438,97.969,224,96,224c-53,0-96,43-96,96
  s43,96,96,96h320c53,0,96-43,96-96c0-41-27-77-64-90C447.5,227.75,448,225.938,448,224
  C448,153,390,96,320,96L320,96z" />
  </g>
</svg>

可以使用 SVG 和 SVG 中的单个 path 元素创建云形状。 SVG 本质上是可缩放的,不会对形状造成任何扭曲。 browser support for SVG 非常好,可以使用 VML 提供 IE8 和更低版本(如果需要)的回退。

形状创建

绘制形状时使用的命令及其含义如下:

  • M 25,60 - 此命令将笔移动到 X 轴原点 (0,0) 前面 25px 和 Y 轴原点前面 60px 的点。 (注意:命令是大写表示是absolute运动,不是relative运动。
  • a 20,20 1 0,0 0,40 - 此命令创建一个弧,其 X 和 Y 半径为 20px。圆弧起点在 (25,60),终点在 (25,100)(即 X 轴 0px,Y 轴 40px)。
  • h 50 - 此命令绘制一条水平线,相对于起点提前 50 像素。由于它是相对的,终点将在 (75,100)。
  • a 20,20 1 0,0 0,-40 - 与第二个命令类似,这将创建另一个圆弧,其半径在任一轴上均为 20px,其终点相对于前一个点在 40px 之前。所以本质上这会创建一个从 (75,100) 到 (75,60) 的弧。这个和第二个命令一起形成了云两侧的弧线。
  • a 10,10 1 0,0 -15,-10 - 另一个弧形命令,用于创建云的弯曲顶部的一部分。半径为 10px,弧度为 (75,60) 到 (60,50)。
  • a 15,15 1 0,0 -35,10 - 完成云的最后弧线。半径为 15px,弧度为 (60,50) 到 (25,60)。 (25,60) 是原始起点,因此完成了形状。
  • z - 关闭路径。

svg {
  height: 50%;
  width: 50%;
}
path {
  fill: white;
  stroke: black;
  stroke-width: 2;
  stroke-linejoin: round;
}
path:hover {
  fill: aliceblue;
  stroke: lightskyblue;
}
<svg viewBox='0 0 105 105'>
  <path d='M 25,60 
           a 20,20 1 0,0 0,40 
           h 50 
           a 20,20 1 0,0 0,-40 
           a 10,10 1 0,0 -15,-10 
           a 15,15 1 0,0 -35,10  
           z' />
</svg>


使用 SVG 的优势

  • 它们易于创建和维护
  • 命令简单易懂,不需要复杂的定位或技巧
  • 默认情况下它们是可扩展的(响应式的)
  • 只要 SVG 是内联的,就不需要额外的 HTTP 请求
  • 更好地控制圆弧、它们的半径等
  • 悬停效果(如下面的代码片段所示)可以限制为仅在鼠标位于形状边界内时触发。
  • 可以轻松添加额外效果。也就是说,您可以模仿在屏幕上绘制的形状等行为。

额外效果 - 云绘图动画

下面是一个带有云绘制动画的示例片段,其中通过重复递减路径的 stroke-dashoffset 属性 直到变为 0 来绘制路径。初始偏移值等于使用 getTotalLength() 方法计算的路径总长度。云的形状也添加了模糊阴影。

动画是使用window.requestAnimationFrame方法实现的。

window.onload = function() {
  var offset;
  var path = document.getElementsByTagName('path')[0];
  var len = path.getTotalLength();

  function paint() {
    path.style.strokeDashoffset = len;
    path.style.strokeDasharray = len + ',' + len;
    animate();
  }

  function animate() {
    if (!offset) offset = len;
    offset -= 0.5;
    path.style.strokeDashoffset = offset;
    if (offset < 0)
      window.cancelAnimationFrame(anim);
    else anim = window.requestAnimationFrame(function() {
      animate();
    });
  }

  paint();
};
svg {
  height: 40%;
  width: 40%;
}
path {
  fill: white;
  stroke: black;
  stroke-width: 2;
  stroke-linejoin: round;
}
path:hover {
  fill: aliceblue;
  stroke: lightskyblue;
}
<svg viewBox='0 0 105 105'>
  <filter id='shadow'>
    <feGaussianBlur in='SourceAlpha' stdDeviation='2' />
    <feOffset dx='2' dy='0' result='blur' />
    <feMerge>
      <feMergeNode in='blur' />
      <feMergeNode in='SourceGraphic' />
    </feMerge>
  </filter>
  <path d='M 25,60 
           a 20,20 1 0,0 0,40 
           h 50 
           a 20,20 1 0,0 0,-40 
           a 10,10 1 0,0 -15,-10 
           a 15,15 1 0,0 -36,10  
           z' filter='url(#shadow)' />
</svg>