【问题标题】:Rounded rect with transparent background and gradient border具有透明背景和渐变边框的圆角矩形
【发布时间】:2017-08-01 21:54:19
【问题描述】:

我需要根据以下几点制作一个矩形:

  1. 透明白色背景 (80%)
  2. 渐变边框(来自后端的不同颜色,1px 宽)
  3. 可以根据文本长度进行缩放

我尝试过使用 SVG,除了第 3 点外,它都能正常工作。

我现在的尝试是使用 3 个 svgs(一个用于左/右半圆,一个用于中间部分并绝对定位它们,但我还不能让它工作。

中间部分不应缩放到 100% 高度,但我对 svg 缩放选项不够熟悉。

我正在使用 React 和 Glamour,但这并不重要。 (由于依赖关系,sn-p 不起作用,但您应该得到问题)

import React from 'react';
import ReactDOM from 'react-dom';
import { css, style, after } from 'glamor';

const SectionTag = ({ className, name, url, height, borderWidth, fontSize, theme, fillColor }) => {
  const styles = {
    main: {
      padding: 0,
      display: 'block',
    },
    inline: style({
      display: 'inline-block',
      verticalAlign: 'top',
    }),
    textWrapper: style({
      position: 'relative'
    }),
    background: style({
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      width: '100%',
    }),
    text: css({
      zIndex: 1,
      position: 'relative',
      color: theme.accentColor,
      fontSize: fontSize,
      lineHeight: 1,
      textTransform: 'uppercase',
      padding: '8px 1px',
      height,
      margin: 0,
    }),
  };
  return (
    <div className={css(className, styles.main)}>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width={height / 2}
        height={height}
        viewBox={`0 0 ${height / 2} ${height}`}
        className={styles.inline}
      >
        <rect rx={height / 2} ry={height / 2} x={borderWidth / 2} y={borderWidth / 2}
              width={(height * 2) - (borderWidth)}
              height={height - (borderWidth)}
              style={{
                fill: fillColor,
                stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
                strokeWidth: borderWidth
              }} />
      </svg>
      <div className={css(styles.textWrapper, styles.inline)}>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          height={height}
          viewBox={`0 0 ${height - 4} ${height}`}
          className={css(styles.background)}
          preserveAspectRatio="xMidYMin slice"
        >
          <linearGradient id={`gradient-${name.replace(/ /g, '-').toLowerCase()}`}>
            <stop offset="0" style={{ stopColor: theme.leftColor }} />
            <stop offset="1" style={{ stopColor: theme.rightColor }} />
          </linearGradient>
          <rect
            x={-borderWidth}
            y={0}
            width={height - (borderWidth * 2)}
            height={height - (borderWidth * 2)}
            style={{
              fill: fillColor,
              stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
              strokeWidth: borderWidth,
              vectorEffect: 'non-scaling-stroke',
              height: height,
              top: 0,
              padding: 0,
              margin: 0,
            }} />
        </svg>
        <p
          height={height}
          className={css(styles.text, styles.inline)}
        >
          {name}
        </p>
      </div>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width={height / 2}
        height={height}
        viewBox={`0 0 ${height / 2} ${height}`}
        className={styles.inline}
      >
        <rect rx={height / 2} ry={height / 2} x={-(height * 1.5)} y={borderWidth / 2}
              width={(height * 2) - (borderWidth)}
              height={height - (borderWidth)}
              style={{
                fill: fillColor,
                stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
                strokeWidth: borderWidth
              }} />
      </svg>
    </div>
  );
};

SectionTag.propTypes = {};
SectionTag.defaultProps = {
  name: 'default',
  height: 29,
  borderWidth: 1,
  fontSize: 10,
  fillColor: 'rgba(255, 255, 255, .8)',
  theme: {
    leftColor: 'rgba(255, 188, 0, 0.31)',
    rightColor: '#ff0000',
    accentColor: '#f9811b'
  }
};

const mountNode = document.querySelector('.el');
ReactDOM.render(<SectionTag name="Jane" />, mountNode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="el"></div>

【问题讨论】:

    标签: css svg


    【解决方案1】:

    知道了!渐变中间部分的定位有点棘手,但这是我的代码:

    import React from 'react';
    import { css, style } from 'glamor';
    
    const SectionTag = ({ className, name, url, height, borderWidth, fontSize, theme, fillColor }) => {
      const styles = {
        main: {
          padding: 0,
          display: 'block',
        },
        inline: style({
          display: 'inline-block',
          verticalAlign: 'top',
        }),
        textWrapper: style({
          position: 'relative',
          height,
        }),
        background: style({
          position: 'absolute',
          top: 0,
          left: 0,
          right: 0,
          zIndex: 0,
        }),
        text: css({
          zIndex: 2,
          position: 'relative',
          color: theme.accentColor,
          fontSize: fontSize,
          lineHeight: 1,
          textTransform: 'uppercase',
          padding: `${(height - fontSize)/2}px 1px`,
          margin: 0,
        }),
      };
      return (
        <div className={css(className, styles.main)}>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width={height / 2}
            height={height}
            viewBox={`0 0 ${height / 2} ${height}`}
            className={styles.inline}
          >
            <rect rx={height / 2} ry={height / 2} x={borderWidth / 2} y={borderWidth / 2}
                  width={(height * 2) - (borderWidth)}
                  height={height - (borderWidth)}
                  style={{
                    fill: fillColor,
                    stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
                    strokeWidth: borderWidth,
                    vectorEffect: 'non-scaling-stroke',
                  }} />
          </svg>
          <div className={css(styles.textWrapper, styles.inline)}>
            <p
              height={height}
              className={css(styles.text, styles.inline)}
            >
              {name}
            </p>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              height={height}
              width="100%"
              className={css(styles.background)}
            >
              <linearGradient id={`gradient-${name.replace(/ /g, '-').toLowerCase()}`}>
                <stop offset="0" style={{ stopColor: theme.leftColor }} />
                <stop offset="1" style={{ stopColor: theme.rightColor }} />
              </linearGradient>
              <rect
                x={-height}
                y={borderWidth/2}
                height={height- (borderWidth)}
                style={{
                  width: `calc(100% + ${height * 2}px)`,
                  fill: fillColor,
                  stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
                  strokeWidth: borderWidth,
                  vectorEffect: 'non-scaling-stroke',
                }} />
            </svg>
          </div>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width={height / 2}
            height={height}
            viewBox={`0 0 ${height / 2} ${height}`}
            className={styles.inline}
          >
            <rect rx={height / 2} ry={height / 2} x={-(height * 1.5)} y={borderWidth / 2}
                  width={(height * 2) - (borderWidth)}
                  height={height - (borderWidth)}
                  style={{
                    fill: fillColor,
                    stroke: `url(#gradient-${name.replace(/ /g, '-').toLowerCase()})`,
                    strokeWidth: borderWidth
                  }} />
          </svg>
        </div>
      );
    };
    
    SectionTag.propTypes = {};
    SectionTag.defaultProps = {
      name: 'default',
      height: 29,
      borderWidth: 1,
      fontSize: 10,
      fillColor: 'rgba(255, 255, 255, .8)',
      theme: {
        leftColor: '#73abff',
        rightColor: '#ff8c2b',
        accentColor: '#0000FF'
      }
    };
    
    export default SectionTag;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

    【讨论】:

      【解决方案2】:

      div {
          position: relative;
          border-left: 3px solid red;
          border-right: 3px solid blue;
          border-radius: 12px;
          background: rgba(255, 255, 255, 0.8);
          font-size:24px;
          padding: 5px 20px;
          overflow: hidden;
      }
      
      div:before {
          content: '';
          background: linear-gradient(to right, red, blue);
          position: absolute;
          top: 0;
          left: 1px;
          height: 2px;
         right:1px;
          display:block;
      }
      
      div:after {
          content: '';
          background: linear-gradient(to right, red, blue);
          position: absolute;
          bottom: 0;
          left: 1px;
          right: 1px;
          height: 2px;
          display:block;
      }
      &lt;div&gt;Submit&lt;/div&gt;

      【讨论】:

      • 那不行,渐变需要从边框开始
      【解决方案3】:

      你可以像这样添加 SVG。

      /* just styles for demo */
      body {
        margin: 0;
        height: 100vh;
      }
      <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 105 105" preserveAspectRatio="none">
        <defs>
          <linearGradient id="gradient">
            <stop offset="0" style="stop-color:#0070d8" />
            <stop offset="0.5" style="stop-color:#2cdbf1" />
            <stop offset="1" style="stop-color:#83eb8a" />
          </linearGradient>
        </defs>
        <g transform="ref(svg, 0, 0)">
          <rect x="2" y="2" width="100" height="100" rx="20" ry="20" fill="none" stroke="url(#gradient)" stroke-width="0.5" />
        </g>
      </svg>

      所以使用这个 SVG 的例子。注意:示例仅适用于 Chrome,在所有浏览器中使用外部 SVG(推荐方式)或转义 SVG 标记:

      div {
        display: inline-block;
        padding: 20px 5%;
        background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 105 105" preserveAspectRatio="none"><defs><linearGradient id="gradient"><stop offset="0" style="stop-color:#0070d8" /><stop offset="0.5" style="stop-color:#2cdbf1" /><stop offset="1" style="stop-color:#83eb8a" /></linearGradient></defs><g transform="ref(svg, 0, 0)"><rect x="2" y="2" width="100" height="100" rx="20" ry="50" fill="none" stroke="url(#gradient)" stroke-width="0.5" /></g></svg>');
      }
      <div>
        This is div
      </div>
      
      <div>
        This is also div with very long text.
      </div>
      
      <div>
        This is also div with very long text. This is also div with very long text. This is also div with very long text.
      </div>
      
      <div>
        This is also div with very long text. This is also div with very long text.<br /> This is also div with very long text.
      </div>

      【讨论】:

      • 哇感谢这个例子!我只需要边界半径保持一致,这样这种方法就行不通了。检查我自己的(工作)解决方案的答案。
      猜你喜欢
      • 2016-08-18
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 1970-01-01
      • 2016-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多