104

我有以下 SVG:

<svg>
  <g>
    <path id="k9ffd8001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="#a0a700"></path>
    <path id="kb8000001" d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z" stroke="#808600" stroke-width="0" transform="rotate(0 0 0)" stroke-linecap="square" stroke-linejoin="round" fill-opacity="1" stroke-opacity="1" fill="url(#k9ffb0001)"></path>
  </g>
</svg>

我想获得类似 CSS 的border-top-right-radius效果border-top-bottom-radius

我怎样才能达到那种圆角效果?

4

15 回答 15

166

以下是使用 SVG 路径创建圆角矩形的方法:

<path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" />

解释

m100,100: 移动到点(100,100)

h200: 从我们所在的位置画一条 200px 的水平线

a20,20 0 0 1 20,20: 顺时针绘制一条 X 半径为 20px、Y 半径为 20px 的圆弧,到 X 轴和 Y 轴相差 20px 的点

v200: 从我们所在的位置画一条 200px 的垂直线

a20,20 0 0 1 -20,20: 顺时针绘制一条 X 和 Y 半径为 20px 的圆弧,到 X 轴差为 -20px,Y 轴差为 20px 的点

h-200: 从我们所在的位置画一条-200px的水平线

a20,20 0 0 1 -20,-20: 顺时针绘制一条 X 和 Y 半径为 20px 的圆弧,到 X 轴差为 -20px,Y 轴差为 -20px 的点

v-200: 从我们所在的位置画一条-200px的垂直线

a20,20 0 0 1 20,-20: 顺时针绘制一条 X 和 Y 半径为 20px 的圆弧,到 X 轴相差 20px,Y 轴相差 -20px 的点

z: 关闭路径

<svg width="440" height="440">
  <path d="M100,100 h200 a20,20 0 0 1 20,20 v200 a20,20 0 0 1 -20,20 h-200 a20,20 0 0 1 -20,-20 v-200 a20,20 0 0 1 20,-20 z" fill="none" stroke="black" stroke-width="3" />
</svg>

于 2016-06-30T09:20:15.467 回答
65

不知道为什么没有人发布实际的 SVG 答案。这是一个顶部带有圆角(半径为 3)的 SVG 矩形:

<path d="M0,0 L0,27 A3,3 0 0,0 3,30 L7,30 A3,3 0 0,0 10,27 L10,0 Z" />

这是移动到 (M)、线到 (L)、弧到 (A)、线到 (L)、弧到 (A)、线到 (L)、闭合路径 (Z)。

逗号分隔的数字是绝对坐标。圆弧是用指定圆弧半径和类型的附加参数定义的。这也可以通过相对坐标来完成(L 和 A 使用小写字母)。

这些命令的完整参考在 W3C SVG 路径页面上,关于 SVG 路径的其他参考资料可以在这篇文章中找到。

于 2015-09-30T20:46:17.777 回答
54

正如我对Applying rounded corners to paths/polygons的回答中所引用的,我在 javascript 中编写了一个例程,用于对 SVG 路径进行一般圆角,并附有示例:http: //plnkr.co/edit/kGnGGyoOCKil02k04snu

它将独立于您可能拥有的任何中风效果。要使用,请包含 Plnkr 中的 rounding.js 文件并像这样调用函数:

roundPathCorners(pathString, radius, useFractionalRadius)

结果将是圆形路径。

结果如下所示:

SVG 路径舍入示例

于 2014-11-20T04:49:12.770 回答
46

您已明确设置您的stroke-linejointoround但您的stroke-widthto 0,所以如果您没有要圆的笔划,您当然不会看到圆角。

这是一个通过笔划制作的圆角的修改示例:http:
//jsfiddle.net/8uxqK/1/

<path d="M64.5 45.5 82.5 45.5 82.5 64.5 64.5 64.5 z"
      stroke-width="5"
      stroke-linejoin="round"
      stroke="#808600"
      fill="#a0a700" />

否则——如果你需要一个真正的圆形填充而不仅仅是一个圆形的脂肪笔划——你必须按照@Jlange 所说的做一个真正的圆形。

于 2012-04-17T03:08:37.457 回答
44

我还考虑使用<rect>提供rxandry属性的普通旧的

MDN SVG docs <- 注意第二个绘制的 rect 元素

于 2014-09-01T06:42:50.213 回答
18

我今天自己也遇到了这个问题,并设法通过编写一个小的 JavaScript 函数来解决它。

据我所知,没有简单的方法在 SVG 圆角中提供路径元素,除非您只需要圆角边框,在这种情况下,(CSS)属性strokestroke-width最重要stroke-linejoin="round"的是完全足够了。

但是,在我的例子中,我使用了一个路径对象来创建具有n 个角的自定义形状,这些角用某种颜色填充并且没有可见的边框,就像这样:

在此处输入图像描述

我设法编写了一个快速函数,该函数采用 SVG 路径的坐标数组并返回完成的路径字符串以放入d路径 html 元素的属性中。生成的形状将如下所示:

在此处输入图像描述

这是功能:

/**
 * Creates a coordinate path for the Path SVG element with rounded corners
 * @param pathCoords - An array of coordinates in the form [{x: Number, y: Number}, ...]
 */
function createRoundedPathString(pathCoords) {
    const path = [];
    const curveRadius = 3;

    // Reset indexes, so there are no gaps
    pathCoords = pathCoords.slice();

    for (let i = 0; i < pathCoords.length; i++) {

      // 1. Get current coord and the next two (startpoint, cornerpoint, endpoint) to calculate rounded curve
      const c2Index = ((i + 1) > pathCoords.length - 1) ? (i + 1) % pathCoords.length : i + 1;
      const c3Index = ((i + 2) > pathCoords.length - 1) ? (i + 2) % pathCoords.length : i + 2;

      const c1 = pathCoords[i];
      const c2 = pathCoords[c2Index];
      const c3 = pathCoords[c3Index];

      // 2. For each 3 coords, enter two new path commands: Line to start of curve, bezier curve around corner.

      // Calculate curvePoint c1 -> c2
      const c1c2Distance = Math.sqrt(Math.pow(c1.x - c2.x, 2) + Math.pow(c1.y - c2.y, 2));
      const c1c2DistanceRatio = (c1c2Distance - curveRadius) / c1c2Distance;
      const c1c2CurvePoint = [
        ((1 - c1c2DistanceRatio) * c1.x + c1c2DistanceRatio * c2.x).toFixed(1),
        ((1 - c1c2DistanceRatio) * c1.y + c1c2DistanceRatio * c2.y).toFixed(1)
      ];

      // Calculate curvePoint c2 -> c3
      const c2c3Distance = Math.sqrt(Math.pow(c2.x - c3.x, 2) + Math.pow(c2.y - c3.y, 2));
      const c2c3DistanceRatio = curveRadius / c2c3Distance;
      const c2c3CurvePoint = [
        ((1 - c2c3DistanceRatio) * c2.x + c2c3DistanceRatio * c3.x).toFixed(1),
        ((1 - c2c3DistanceRatio) * c2.y + c2c3DistanceRatio * c3.y).toFixed(1)
      ];

      // If at last coord of polygon, also save that as starting point
      if (i === pathCoords.length - 1) {
        path.unshift('M' + c2c3CurvePoint.join(','));
      }

      // Line to start of curve (L endcoord)
      path.push('L' + c1c2CurvePoint.join(','));
      // Bezier line around curve (Q controlcoord endcoord)
      path.push('Q' + c2.x + ',' + c2.y + ',' + c2c3CurvePoint.join(','));
    }
    // Logically connect path to starting point again (shouldn't be necessary as path ends there anyway, but seems cleaner)
    path.push('Z');

    return path.join(' ');
}

您可以通过在顶部设置curveRadius变量来确定舍入强度。对于 100x100(视口)坐标系,默认值为 3,但根据 SVG 的大小,您可能需要对其进行调整。

于 2018-10-15T14:34:51.900 回答
5

这个问题是谷歌搜索“svg圆角路径”的第一个结果。Phrogz 的使用建议stroke有一些限制(即,我不能将笔画用于其他目的,并且必须根据笔画宽度校正尺寸)。

Jlange 建议使用曲线更好,但不是很具体。我最终使用二次贝塞尔曲线来绘制圆角。考虑这张在相邻边缘上标有蓝点和两个红点的角的图片:

标记为蓝色的图形的角,相邻边缘上有两个点

这两行可以用L命令来完成。要将这个尖角变成一个圆角,从左边的红点开始画一条曲线(M x,y用来移动到那个点)。现在,二次贝塞尔曲线只有一个控制点,您必须将其设置在蓝点上。将曲线的终点设置在右侧的红点。由于两个红点处的切线与前面的线的方向一致,您将看到流畅的过渡,“圆角”。

现在继续圆角之后的形状,可以通过在两个角之间的线上设置控制点来实现贝塞尔曲线中的直线。

为了帮助我确定路径,我编写了这个接受边缘和半径的 Python 脚本。矢量数学使这实际上非常容易。输出的结果图像:

从脚本输出创建的形状

#!/usr/bin/env python
# Given some vectors and a border-radius, output a SVG path with rounded
# corners.
#
# Copyright (C) Peter Wu <peter@lekensteyn.nl>

from math import sqrt

class Vector(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def sub(self, vec):
        return Vector(self.x - vec.x, self.y - vec.y)

    def add(self, vec):
        return Vector(self.x + vec.x, self.y + vec.y)

    def scale(self, n):
        return Vector(self.x * n, self.y * n)

    def length(self):
        return sqrt(self.x**2 + self.y**2)

    def normal(self):
        length = self.length()
        return Vector(self.x / length, self.y / length)

    def __str__(self):
        x = round(self.x, 2)
        y = round(self.y, 2)
        return '{},{}'.format(x, y)

# A line from vec_from to vec_to
def line(vec_from, vec_to):
    half_vec = vec_from.add(vec_to.sub(vec_from).scale(.5))
    return '{} {}'.format(half_vec, vec_to)

# Adds 'n' units to vec_from pointing in direction vec_to
def vecDir(vec_from, vec_to, n):
    return vec_from.add(vec_to.sub(vec_from).normal().scale(n))

# Draws a line, but skips 'r' units from the begin and end
def lineR(vec_from, vec_to, r):
    vec = vec_to.sub(vec_from).normal().scale(r)
    return line(vec_from.add(vec), vec_to.sub(vec))

# An edge in vec_from, to vec_to with radius r
def edge(vec_from, vec_to, r):
    v = vecDir(vec_from, vec_to, r)
    return '{} {}'.format(vec_from, v)


# Hard-coded border-radius and vectors
r = 5
a = Vector(  0,  60)
b = Vector(100,   0)
c = Vector(100, 200)
d = Vector(  0, 200 - 60)

path = []
# Start below top-left edge
path.append('M {} Q'.format(a.add(Vector(0, r))))

# top-left edge...
path.append(edge(a, b, r))
path.append(lineR(a, b, r))
path.append(edge(b, c, r))
path.append(lineR(b, c, r))
path.append(edge(c, d, r))
path.append(lineR(c, d, r))
path.append(edge(d, a, r))
path.append(lineR(d, a, r))

# Show results that can be pushed into a <path d="..." />
for part in path:
    print(part)
于 2014-05-31T23:07:38.663 回答
3

对于我的情况,我需要半径开始和结束path

在此处输入图像描述

随着stroke-linecap: round;我将其更改为我想要的:

在此处输入图像描述

于 2021-02-10T10:58:28.683 回答
3

以下是选项卡的一些路径:

https://codepen.io/mochime/pen/VxxzMW

<!-- left tab -->
<div>
  <svg width="60" height="60">
    <path d="M10,10 
             a10 10 0 0 1 10 -10
             h 50   
             v 47
             h -50
             a10 10 0 0 1 -10 -10
             z"
      fill="#ff3600"></path>
  </svg>
</div>

<!-- right tab -->
<div>
  <svg width="60" height="60">
    <path d="M10 0   
             h 40
             a10 10 0 0 1 10 10
             v 27
             a10 10 0 0 1 -10 10
             h -40
             z"
      fill="#ff3600"></path>
  </svg>
</div>

<!-- tab tab :) -->
<div>
  <svg width="60" height="60">
    <path d="M10,40 
             v -30
             a10 10 0 0 1 10 -10
             h 30
             a10 10 0 0 1 10 10
             v 30
             z"
      fill="#ff3600"></path>
  </svg>
</div>

其他答案解释了机制。我特别喜欢 hossein-maktoobian 的回答。

笔中的路径首当其冲,可以修改值以适应任何所需的尺寸。

于 2018-05-11T17:28:09.867 回答
2

这基本上与Mvins answer相同,但它是一个更加压缩和简化的版本。它的工作原理是返回与拐角相邻的线的半径距离,并用控制点在原始拐角点的贝塞尔曲线连接两端。

function createRoundedPath(coords, radius, close) {
  let path = ""
  const length = coords.length + (close ? 1 : -1)
  for (let i = 0; i < length; i++) {
    const a = coords[i % coords.length]
    const b = coords[(i + 1) % coords.length]
    const t = Math.min(radius / Math.hypot(b.x - a.x, b.y - a.y), 0.5)

    if (i > 0) path += `Q${a.x},${a.y} ${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == 0) path += `M${a.x},${a.y}`
    else if (i == 0) path += `M${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`

    if (!close && i == length - 1) path += `L${b.x},${b.y}`
    else if (i < length - 1) path += `L${a.x * t + b.x * (1 - t)},${a.y * t + b.y * (1 - t)}`
  }
  if (close) path += "Z"
  return path
}
于 2020-12-07T17:22:46.450 回答
2

只是为了简化@hmak.me 的实现答案,这里有一段注释的 React 代码来生成圆角矩形。

const Rect = ({width, height, round, strokeWidth}) => {
    // overhang over given width and height that we get due to stroke width
    const s = strokeWidth / 2;

    // how many pixels do we need to cut from vertical and horizontal parts
    // due to rounded corners and stroke width
    const over = 2 * round + strokeWidth;

    // lengths of straight lines
    const w = width - over;
    const h = height - over;

    // beware that extra spaces will not be minified
    // they are added for clarity
    const d = `
        M${round + s},${s}
        h${w}
        a${round},${round} 0 0 1 ${round},${round}
        v${h}
        a${round},${round} 0 0 1 -${round},${round}
        h-${w}
        a${round},${round} 0 0 1 -${round},-${round}
        v-${h}
        a${round},${round} 0 0 1 ${round},-${round}
        z
    `;
    return (
        <svg width={width} height={height}>
            <path d={d} fill="none" stroke="black" strokeWidth={strokeWidth} />
        </svg>
    );
};

ReactDOM.render(
    <Rect width={64} height={32} strokeWidth={2} round={4} />,
    document.querySelector('#app'),
);

Jsfiddle 链接。

于 2020-04-26T23:11:25.157 回答
1

我找到了一个解决方案,但它有点老套,所以它可能并不总是有效。我发现如果你有一个值非常小的弧(A 或 a),它会迫使它在一个点创建一条曲线,从而形成一个圆角......

<svg viewBox="0 0 1 0.6" stroke="black" fill="grey" style="stroke-width:0.05px;">
  <path d="M0.7 0.2 L0.1 0.1 A0.0001 0.0001 0 0 0 0.099 0.101 L0.5 0.5Z"></path>
</svg>

于 2019-07-09T04:43:29.273 回答
0

我编写了这个小打字稿函数,这样我就可以动态地为一个复杂的圆角矩形创建路径,该矩形的功能类似于带有border-radius.

export function roundedRectPath( x: number, y: number, width: number, height: number, bevel: [number, number, number, number] = [3, 3, 3, 3] ): string { return "M" + x + "," + y + `m 0 ${bevel[0]}` + `q 0 -${bevel[0]} ${bevel[0]} -${bevel[0]}` + `l ${width - bevel[0] - bevel[1]} 0` + `q ${bevel[1]} 0 ${bevel[1]} ${bevel[1]}` + `l 0 ${height - bevel[1] - bevel[2]}` + `q 0 ${bevel[2]} -${bevel[2]} ${bevel[2]}` + `l -${width - bevel[2] - bevel[3]} 0` + `q -${bevel[3]} 0 -${bevel[3]} -${bevel[3]}` + `z`; }
于 2022-01-26T22:20:18.550 回答
0

这是一段反应代码,用于生成具有不同角半径的矩形:

const Rect = ({width, height, tl, tr, br, bl}) => {
    const top = width - tl - tr;
    const right = height - tr - br;
    const bottom = width - br - bl;
    const left = height - bl - tl;
    const d = `
        M${tl},0
        h${top}
        a${tr},${tr} 0 0 1 ${tr},${tr}
        v${right}
        a${br},${br} 0 0 1 -${br},${br}
        h-${bottom}
        a${bl},${bl} 0 0 1 -${bl},-${bl}
        v-${left}
        a${tl},${tl} 0 0 1 ${tl},-${tl}
        z
    `;
    return (
        <svg width={width} height={height}>
            <path d={d} fill="black" />
        </svg>
    );
};

ReactDOM.render(
    <Rect width={200} height={100} tl={20} tr={0} br={20} bl={60} />,
    document.querySelector('#app'),
);

https://jsfiddle.net/v1Ljpxh7/

于 2021-12-29T23:07:47.630 回答
-4

您正在使用路径元素,为什么不给路径一条曲线?请参阅此处了解如何使用路径元素制作曲线:http: //www.w3.org/TR/SVG/paths.html#PathDataCurveCommands

于 2012-04-16T22:49:57.067 回答