Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rounded rect with transparent background and gradient border

Tags:

css

svg

I need to make a rectangle with the following things in mind:

  1. transparent white background (80%)
  2. gradient border (different colors that come from the backend, 1px wide)
  3. can scale according to text length

Like this

I've tried using SVG and got it working except point 3.

My attempt now is to use 3 svgs (one for the left/right half circle and one for the middle part and position them absolutely but i can't get it to work just yet.

enter image description here

The middle part shouldn't scale to 100% height but im not familiar enough with svg scaling options.

Im using React and Glamor but that shouldnt matter for this. (snippet doesnt work because of dependencies, but you should get the issue)

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>
like image 668
Mettin Parzinski Avatar asked Jun 12 '26 04:06

Mettin Parzinski


1 Answers

Got it! The positioning of the middle part of the gradient was a bit tricky but here's my code: enter image description here

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>
like image 162
Mettin Parzinski Avatar answered Jun 13 '26 18:06

Mettin Parzinski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!