laitimes

A different way to use SVG!SVG in CSS

author:Flash Gene
Here are some SVG tips that you may not have used.

In normal development, SVG is often used. In most cases, we don't need to pay attention to what is inside SVG, and just introduce it as an image resource, such as a common icon resource

A different way to use SVG!SVG in CSS

There are many ways we can use this particular picture

<img src="a.svg">
           
.icon{
  background: url("a.svg")
}
           

Or even directly into HTML

<div>
  <svg>
  	...
  </svg>
</div>
           

All this is fine, but sometimes, we need something that can be adaptive, such as a gradient border like this one, where the size changes as the text content changes, rather than a fixed size, as shown below

A different way to use SVG!SVG in CSS

Or maybe it's a dotted gradient border like this

A different way to use SVG!SVG in CSS

Let's take a look at how to dynamically implement this with SVG

1. Limitations of SVG export

SVG is usually not handwritten (those who can write any path by hand are gods), and almost all designers draw and generate them with the help of software, such as Figma, which is very popular with design (very friendly to the front-end, you can try it)

A different way to use SVG!SVG in CSS

For example, the aforementioned gradient borders are like this in Figma

A different way to use SVG!SVG in CSS

For designers, gradient borders are easy, just choose the border type

A different way to use SVG!SVG in CSS

For CSS, this is a more troublesome thing, usually we need to nest an additional layer of gradient background, through masking or mask cropping, if you are interested, you can try it, I won't expand it here.

So, can this design be implemented directly by exporting SVG?

Try it first, you can copy this border directly into SVG format in Figma

A different way to use SVG!SVG in CSS

Here's a copy of the SVG code (probably still understandable...) )

<svg width="41" height="25" viewBox="0 0 41 25" fill="none" xmlns="http://www.w3.org/2000/svg">
  <rect x="1" y="1" width="39" height="23" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
  <defs>
  <linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
  	<stop stop-color="#FFD75A"/>
  	<stop offset="1" stop-color="#ED424B"/>
  </linearGradient>
  </defs>
</svg>
           

Let's try to make this SVG size follow the size of the button, and that's it

<style>
  svg{
    position: absolute;
    inset: 0;
  }
</style>
<button>
  CSS
  <svg>...</svg>
</button>
           

In the case of uncertain content, it becomes like this

A different way to use SVG!SVG in CSS

Obviously, no, because the generated SVG width and height are fixed and cannot follow the adaptive size of the text content

Since SVG is great at gradient borders and CSS is good at adaptive, is there a way to complement each other's strengths?

Of course, there is, but it needs to be "transformed" and read on

2. SVG adaptive size

First of all, let's take the SVG above

<svg width="41" height="25" viewBox="0 0 41 25" fill="none" xmlns="http://www.w3.org/2000/svg">
  <rect x="1" y="1" width="39" height="23" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
  <defs>
  <linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
  	<stop stop-color="#FFD75A"/>
  	<stop offset="1" stop-color="#ED424B"/>
  </linearGradient>
  </defs>
</svg>
           

If you want to achieve self-adaptation, we need to change these values to percentages, pay attention to this rect, there is an x, y coordinates, we are now 100% wide and high, so the coordinates here should also be changed to 0, otherwise it will be stretched out.

<svg width="100%" height="100%" viewBox="0 0 100% 100%" fill="none" xmlns="http://www.w3.org/2000/svg">
  <rect x="0" y="0" width="100%" height="100%" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
  <defs>
  <linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
  	<stop stop-color="#FFD75A"/>
  	<stop offset="1" stop-color="#ED424B"/>
  </linearGradient>
  </defs>
</svg>
           

To verify the adaptability of this SVG, we put this SVG in a div

<div style="width: 100px;height: 80px;">
  <svg>...</svg>
</div>

<div style="width: 200px;height: 180px;">
  <svg>...</svg>
</div>
           

The effect is as follows

A different way to use SVG!SVG in CSS

Is it already adaptive?

However, there is still a bit of a problem, and if you look closely, the rounded corners are a little unnatural, and it feels like they have been cropped

A different way to use SVG!SVG in CSS

There are two reasons for this:

  1. SVG strokes are centered strokes and cannot be modified
  2. SVG默认是超出隐藏的,也就是自带overflow:hidden

If we make the border a little larger, it's obvious that the stroke is centered

A different way to use SVG!SVG in CSS

Because it is centered, so without modification, we see only half of the original border, using this principle we can actually achieve the commonly said 0.5px border, if you are interested, you can refer to my previous article: use svg stroke to achieve mobile 1px

Here, I'm going to introduce a new way to take advantage of CSS calc!

Yes, you can also use CSS functions in SVG, for example, if the border is 4px, then the coordinates x and y should be 2, and then the width and height should be calc (100% - 4px), so it can be changed to this naturally

<div style="width: 100px;height: 80px;">
  <svg width="100%" height="100%">
    <rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);"  rx="4" stroke="url(#paint0_linear_1_2)" stroke-width="4" stroke-linecap="round"/>
     <defs>
    <linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
      <stop stop-color="#FFD75A"/>
      <stop offset="1" stop-color="#ED424B"/>
    </linearGradient>
    </defs>
  </svg>
</div>
           

It's perfect, there won't be any cropping!(You can also copy the above code and put it in the HTML for verification)

A different way to use SVG!SVG in CSS

In this way, SVG size adaptation is "easily".

Here's a summary

  1. Change the size of the SVG to 'percentage.'
  2. Since it is a centered stroke, the coordinates and size need to be corrected

In addition to that, you can add style directly, just like this

<svg width="100%" height="100%" viewBox="0 0 100% 100%" fill="none" xmlns="http://www.w3.org/2000/svg">
  <style>
    rect{
      width: calc(100% - 4px);
      height: calc(100% - 4px);
    }
  </style>
  <rect x="2" y="2" width="100%" height="100%" rx="4" stroke="url(#paint0_linear_1_2)" stroke-width="4" stroke-linecap="round"/>
  <defs>
    <linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
      <stop stop-color="#FFD75A"/>
      <stop offset="1" stop-color="#ED424B"/>
    </linearGradient>
  </defs>
</svg>
           

Although it looks like a lot, it has a bigger role in the back, and more CSS styles can be added

3. Application of SVG in HTML

In fact, the SVG in the previous paragraph can be used directly in HTML, for example

<button>
  <svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
    <rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" rx="16" stroke-width="2" stroke="url(#paint0_linear_3269_5233)"/>
    <defs>
      <linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
        <stop stop-color="#FFD75A"/>
        <stop offset="1" stop-color="#ED424B"/>
      </linearGradient>
    </defs>
  </svg>
  CSS
</button>
           

We need to fill the entire button with this SVG, so we can position it absolutely

button{
  position: relative;
}
button>svg{
  position: absolute;
  inset: 0;
}
           

The result is an adaptive-sized button with a gradient border, and the effect is as follows

A different way to use SVG!SVG in CSS

You can also visit the online link: buton with SVG (juejin.cn)[1]

Fourth, the application of SVG in CSS

I don't know if you feel like this, putting a large chunk of SVG in HTML is not particularly elegant, and it always feels too bloated.

If that's the way you feel, you might want to convert this SVG into inline CSS code.

Here you can use this tool by Mr. Zhang Xinxu: SVG Online Compression and Merge Tool[2]

A different way to use SVG!SVG in CSS

We paste this SVG over and we get an inline SVG like this

data:image/svg+xml,%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1' y='1' width='100%25' height='100%25' style='width:calc(100%25 - 2px);height:calc(100%25 - 2px)' rx='16' stroke-width='2' stroke='url(%23paint0_linear_3269_5233)'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_3269_5233' y2='100%25' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23FFD75A'/%3E%3Cstop offset='1' stop-color='%23ED424B'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E
           

With this inline SVG, we can use it directly on background

button{
  background: url("data:image/svg+xml,%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1' y='1' width='100%25' height='100%25' style='width:calc(100%25 - 2px);height:calc(100%25 - 2px)' rx='16' stroke-width='2' stroke='url(%23paint0_linear_3269_5233)'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_3269_5233' y2='100%25' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23FFD75A'/%3E%3Cstop offset='1' stop-color='%23ED424B'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E")
}
           

HTML, on the other hand, only requires a clean button element

<button>CSS</button>
<button>CSS & SVG</button>
           

The amazing thing is that even after switching to inline, SVG still maintains the adaptive nature, so it can achieve the same effect, isn't it much better?

A different way to use SVG!SVG in CSS

你也可以访问在线链接:button with SVG background (juejin.cn)[3]

5. The unique charm of SVG

If the above effect CSS can barely simulate it, what if it's a dotted line?

A different way to use SVG!SVG in CSS

For SVG, it's very easy, just set the stroke-dasharray property, and you can change the interval of the dashed lines at will

<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
  <rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" rx="16" stroke-width="2" stroke="url(#paint0_linear_3269_5233)"  stroke-dasharray="8 4"/>
  <defs>
    <linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
      <stop stop-color="#FFD75A"/>
      <stop offset="1" stop-color="#ED424B"/>
    </linearGradient>
  </defs>
</svg>  
           

There's also this case where the dotted edges are rounded, and CSS is even more powerless

A different way to use SVG!SVG in CSS

SVG only needs to set stroke-linecap

<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
  <rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" stroke-width="2" rx="16" stroke-linecap="round"  stroke="url(#paint0_linear_3269_5233)"  stroke-dasharray="8 6"/>
  <defs>
    <linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
      <stop stop-color="#FFD75A"/>
      <stop offset="1" stop-color="#ED424B"/>
    </linearGradient>
  </defs>
</svg> 
           

Furthermore, SVG can also implement dotted scrolling animations, which should not be possible with CSS

A different way to use SVG!SVG in CSS

It seems complicated, but in fact, we only need to change the stroke-dashoffset property, and we can insert CSS animations directly into the SVG

<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
  <style>
    .rect{
      width: calc(100% - 4px);
      height: calc(100% - 4px);
      animation: move .3s infinite linear;
    }
    @keyframes move {
      0% { stroke-dashoffset: 0; }
      100% { stroke-dashoffset: 14; }
    }
  </style>
  <rect class="rect" x="2" y="2" width="100%" height="100%" stroke-width="2" rx="16" stroke-linecap="round"  stroke="url(#paint0_linear_3269_5233)"  stroke-dasharray="8 6"/>
  <defs>
    <linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
      <stop stop-color="#FFD75A"/>
      <stop offset="1" stop-color="#ED424B"/>
    </linearGradient>
  </defs>
</svg>  
           

In all cases, SVG can be converted to inline CSS and used directly in the background, which greatly ensures the simplicity of the HTML

你也可以访问在线链接:dot border with animation (juejin.cn)[4]

6. To sum up

That's all for this article, which focuses on how to take advantage of SVG and CSS to achieve a more flexible layout

  1. The SVGs exported by the design software are all fixed in size and cannot be adapted to the size
  2. SVG is great at gradient borders, and CSS is good at adaptive sizing, so you have to find a way to complement each other's strengths
  3. Some SVG attributes support the percentage type, which can achieve size adaptation
  4. SVG strokes are centered strokes and cannot be modified, so you need to adjust the size of the coordinates of the rounded rectangle
  5. SVG also supports some CSS features, such as calc calculation functions
  6. SVG also supports embedding style tags for direct insertion of CSS code
  7. SVG can be converted to inline CSS code, which supports SVG features and greatly ensures that the HTML is clean
  8. With SVG, gradient dotted borders can be easily implemented
  9. CSS animations are also supported in SVG, which can implement dashed scrolling animations

As you may have noticed, SVG is not a very isolated language, and can now be linked to CSS and HTML to take advantage of each other's strengths, so you can do more with less.

[1]buton with SVG (juejin.cn): https://code.juejin.cn/pen/7341373491785236532

[2] SVG Online Compression & Merge Tool: https://www.zhangxinxu.com/sp/svgo/

[3]button with SVG background (juejin.cn): https://code.juejin.cn/pen/7341378448348643379

[4]dot border with animation (juejin.cn): https://code.juejin.cn/pen/7341382517888876582

作者:XboxYan

Source-WeChat public account: front-end detective

Source: https://mp.weixin.qq.com/s/VH2U-jqm3cXI0yQFrR3adQ