349

I'm trying to apply a gradient to a border, I thought it was as simple as doing this:

border-color: -moz-linear-gradient(top, #555555, #111111);

But this does not work.

Does anyone know what is the correct way to do border gradients?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Mark
  • 32,293
  • 33
  • 107
  • 137
  • related question to have gradient with border-radius: https://stackoverflow.com/q/51496204/8620333 – Temani Afif Jan 28 '21 at 12:09
  • this answer also works fine with bg gradient and padding for border-width : https://stackoverflow.com/questions/23751274/can-we-set-a-gradient-color-to-border-bottom-property/23752288#23752288 see the linked codepen about rounded boxes and animated gradients on the edges. (just discovered that question turned to a duple of this one **unsure if i should add an answer here not involving webkit prefix ?** – G-Cyrillus Jul 16 '21 at 21:41
  • @G-Cyrillus If the solution doesn't exist here, yes it should be added here instead. Then we can delete that duplicate. – TylerH Aug 24 '23 at 18:32

21 Answers21

242

The border-image property can accomplish this. You'll need to specify border-style and border-width too.

border-image: linear-gradient(#f6b73c, #4d9f0c) 30;
border-width: 4px;
border-style: solid;

Read more on MDN.

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
Tony
  • 2,690
  • 1
  • 15
  • 8
  • 24
    Does not work in any browser when using border-radius! Apparently the border-image property always creates square borders even if border-radius is on. So the alternative with nested elements (or a :before element) is the most flexible solution. Here is a JSFiddle thats shows the easyest way this can be done: http://jsfiddle.net/wschwarz/e2ckdp2v/ – Walter Schwarz Nov 25 '14 at 11:19
  • 3
    The solution is finally here. https://codyhouse.co/nuggets/css-gradient-borders – NFT Master Sep 08 '21 at 05:26
  • For a simple example, use: `border: solid; border-image: linear-gradient(to top, red, blue) 1 / 5px;` [jsfiddle: border-image with linear-gradient](https://jsfiddle.net/SelectNt/pLj2azhu/) – Nor.Z Aug 24 '22 at 21:49
130

Instead of borders, I would use background gradients and padding. Same look, but much easier.

A simple example:

.g {
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.33, rgb(14,173,173)), color-stop(0.67, rgb(0,255,255)));
background-image: -moz-linear-gradient(center bottom, rgb(14,173,173) 33%, rgb(0,255,255) 67% );
padding: 2px;
}

.g > div { background: #fff; }
<div class="g">
    <div>bla</div>
</div>

You can also leverage the ::before selector as Walter Schwarz pointed out:

body {
    padding: 20px;
}
.circle {
    width: 100%;
    height: 200px;
    background: linear-gradient(to top, #3acfd5 0%, #3a4ed5 100%);
    border-radius: 100%;
    position: relative;
    text-align: center;
    padding: 20px;
    box-sizing: border-box;
}
.circle::before {
    border-radius: 100%;
    content: '';
    background-image: linear-gradient(to bottom, #3acfd5 0%, #3a4ed5 100%);
    top: -10px;
    left: -10px;
    bottom: -10px;
    right: -10px;
    position: absolute;
    z-index:-1;
}
<div class="circle"></div>
TylerH
  • 20,799
  • 66
  • 75
  • 101
szajmon
  • 1,629
  • 1
  • 10
  • 7
  • 4
    Using a :before element is better, as you then have full control via CSS and the HTML markup stays clean. Here is a JSFiddle that shows the easiest way this can be done: http://jsfiddle.net/wschwarz/e2ckdp2v/ – Walter Schwarz Nov 25 '14 at 11:25
94

border-image-slice will extend a CSS border-image gradient

This (as I understand it) prevents the default slicing of the "image" into sections - without it, nothing appears if the border is on one side only, and if it's around the entire element four tiny gradients appear in each corner.

body{
  border: 16px solid transparent;
  border-image: linear-gradient(45deg, red , yellow);
  border-image-slice: 1;
  height: 120px;
  border-radius: 10px;  /* will have no effect */
}
Erik
  • 35
  • 8
Dave Everitt
  • 17,193
  • 6
  • 67
  • 97
  • 37
    In Chrome, if this is combined with `border-radius`, the border-radius gets ignored :( – Ben May 23 '18 at 16:25
50

Mozilla currently only supports CSS gradients as values of the background-image property, as well as within the shorthand background.

https://developer.mozilla.org/en/CSS/-moz-linear-gradient

Example 3 - Gradient Borders

border: 8px solid #000;
-moz-border-bottom-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-top-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-left-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-right-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
padding: 5px 5px 5px 15px; 

http://www.cssportal.com/css3-preview/borders.htm

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
28

Try this, works fine on web-kit

.border { 
    width: 400px;
    padding: 20px;
    border-top: 10px solid #FFFF00;
    border-bottom:10px solid #FF0000;
    background-image: 
        linear-gradient(#FFFF00, #FF0000),
        linear-gradient(#FFFF00, #FF0000)
    ;
    background-size:10px 100%;
    background-position:0 0, 100% 0;
    background-repeat:no-repeat;
}
<div class="border">Hello!</div>
GibboK
  • 71,848
  • 143
  • 435
  • 658
23

You can achieve this without removing the border radius with background, background-clip, and background-origin:

<style>
.border-gradient-rounded {
  /* Border */
  border: 4px solid transparent;
  border-radius: 20px;
  background: 
    linear-gradient(to right, white, white), 
    linear-gradient(to right, red , blue); 
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
  
  /* Other styles */
  width: 100px;
  height: 40px;
  padding: 12px;
}
</style>

<div class="border-gradient-rounded">
  Content
</div>

Basically, this positions the white background over the gradient background, clips the white background from the inner border, and clips the gradient background from the outer border. This is why you need to define the border as solid transparent.

Credit to Method 2 from this dev.to post.

Michael Hays
  • 2,947
  • 3
  • 20
  • 30
14

It's a hack, but you can achieve this effect in some cases by using the background-image to specify the gradient and then masking the actual background with a box-shadow. For example:

p {
  display: inline-block;
  width: 50px;
  height: 50px;
  /* The background is used to specify the border background */
  background: -moz-linear-gradient(45deg, #f00, #ff0);
  background: -webkit-linear-gradient(45deg, #f00, #ff0);
  /* Background origin is the padding box by default.
  Override to make the background cover the border as well. */
  -moz-background-origin: border;
  background-origin: border-box;
  /* A transparent border determines the width */
  border: 4px solid transparent;
  border-radius: 8px;
  box-shadow:
    inset 0 0 12px #0cc, /* Inset shadow */
    0 0 12px #0cc, /* Outset shadow */
    inset -999px 0 0 #fff; /* The background color */
}

From: http://blog.nateps.com/the-elusive-css-border-gradient

Nate Smith
  • 459
  • 4
  • 6
8

Try the below example:

.border-gradient {
      border-width: 5px 5px 5px 5px;
      border-image: linear-gradient(45deg, rgba(100,57,242,1) 0%, rgba(242,55,55,1) 100%);
      border-image-slice: 9;
      border-style: solid;
}
NDBoost
  • 10,184
  • 6
  • 53
  • 73
Vijay Chauhan
  • 1,282
  • 19
  • 18
6

Try this, it worked for me.

div{
  border-radius: 20px;
  height: 70vh;
  overflow: hidden;
}

div::before{
  content: '';
  display: block;
  box-sizing: border-box;
  height: 100%;

  border: 1em solid transparent;
  border-image: linear-gradient(to top, red 0%, blue 100%);
  border-image-slice: 1;
}
<div></div>

The link is to the fiddle https://jsfiddle.net/yash009/kayjqve3/1/

TylerH
  • 20,799
  • 66
  • 75
  • 101
Yash009
  • 523
  • 4
  • 18
6

The most straight forward way is to use border-image property. You can use whatever linear-gradient or repeat-gradient you want. The border-image slice property needs to be 1 for linear gradient.

.gradient-border {
    border-style: solid;
    border-width: 2px;
    border-image: linear-gradient(45deg, red, blue) 1;
}

References MDN - https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-slice digital ocean - https://www.digitalocean.com/community/tutorials/css-gradient-borders-pure-css

  • 5
    Using border-image is already have been suggested twice. Why bring it again as an answer? – Vega Jun 19 '21 at 15:49
4

Webkit supports gradients in borders, and now accepts the gradient in the Mozilla format.

Firefox claims to support gradients in two ways:

  1. Using border-image with border-image-source
  2. Using border-right-colors (right/left/top/bottom)

IE9 has no support.

SamGoody
  • 13,758
  • 9
  • 81
  • 91
  • 1
    This appears to be a link-only answer. It should have information from the links added to the answer so that when the links die, your answer doesn't lose what little value it currently contains. – TylerH Aug 24 '23 at 18:36
3

Example for Gradient Border

Using border-image css property

Credits to : border-image in Mozilla

.grad-border {
  height: 1px;
  width: 85%;
  margin: 0 auto;
  display: flex;
}
.left-border, .right-border {
  width: 50%;
  border-bottom: 2px solid #695f52;
  display: inline-block;
}
.left-border {
  border-image: linear-gradient(270deg, #b3b3b3, #fff) 1;
}
.right-border {
  border-image: linear-gradient(90deg, #b3b3b3, #fff) 1;
}
<div class="grad-border">
  <div class="left-border"></div>
  <div class="right-border"></div>
</div>
Magaesh
  • 488
  • 6
  • 19
3

I agree with szajmon. The only problem with his and Quentin's answers is cross-browser compatibility.

HTML:

<div class="g">
    <div>bla</div>
</div>

CSS:

.g {
background-image: -webkit-linear-gradient(300deg, white, black, white); /* webkit browsers (Chrome & Safari) */
background-image: -moz-linear-gradient(300deg, white, black, white); /* Mozilla browsers (Firefox) */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#000000', gradientType='1'); /* Internet Explorer */
background-image: -o-linear-gradient(300deg,rgb(255,255,255),rgb(0,0,0) 50%,rgb(255,255,255) 100%); /* Opera */
}

.g > div { background: #fff; }
Scotty
  • 39
  • 1
  • 4
    Please, no `filter` to support IE for such minor thing, just use a solid border. – Ricardo Zea Mar 16 '12 at 19:06
  • 1
    @Ricardo - care to explain why? – Alohci Dec 10 '12 at 13:21
  • @Alohci, sure, plenty of reasons. Note that my explanation is not for you since someone with your reputation already knows these things, it's for others that either don't know it and/or are learning: 1. It's smarter to use [Graceful Degradation](http://goo.gl/3eEju). 2. We as Web Designers/Developers should be thinking about building websites for the users, not for the browsers. And just to leave it at 3 points, 3. Just because you 'can' do it doesn't mean you 'should' do it. Same as with inline styling and the unavoidable `!important`. Now, Alohci, your turn explaining why as well :) – Ricardo Zea Dec 11 '12 at 03:08
  • And then [this comment](http://coding.smashingmagazine.com/2010/04/28/css3-solutions-for-internet-explorer/#comment-456390) and [this one](http://coding.smashingmagazine.com/2010/04/28/css3-solutions-for-internet-explorer/#comment-456406) sum it all up. I'm sure there are pleeenty more there. – Ricardo Zea Dec 11 '12 at 03:25
  • This answer could benefit from an explanation as to how this achieves cross-browser compatibility missing from the answers it criticizes. – TylerH Aug 24 '23 at 18:37
2

Another hack for achieving the same effect is to utilize multiple background images, a feature that is supported in IE9+, newish Firefox, and most WebKit-based browsers: http://caniuse.com/#feat=multibackgrounds

There are also some options for using multiple backgrounds in IE6-8: http://www.beyondhyper.com/css3-multiple-backgrounds-in-non-supportive-browsers/

For example, suppose you want a 5px-wide left border that is a linear gradient from blue to white. Create the gradient as an image and export to a PNG. List any other CSS backgrounds after the one for the left border gradient:

#theBox {
    background:
        url(/images/theBox-leftBorderGradient.png) left no-repeat,
        ...;
}

You can adapt this technique to top, right, and bottom border gradients by changing the background position part of the background shorthand property.

Here is a jsFiddle for the given example: http://jsfiddle.net/jLnDt/

Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
2

Gradient Borders from Css-Tricks: http://css-tricks.com/examples/GradientBorder/

.multbg-top-to-bottom {
  border-top: 3px solid black;
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#000), to(transparent));
  background-image: -webkit-linear-gradient(#000, transparent);
  background-image:
      -moz-linear-gradient(#000, transparent),
      -moz-linear-gradient(#000, transparent);
  background-image:
      -o-linear-gradient(#000, transparent),
      -o-linear-gradient(#000, transparent);
  background-image: 
      linear-gradient(#000, transparent),
      linear-gradient(#000, transparent);
  -moz-background-size: 3px 100%;
  background-size: 3px 100%;
  background-position: 0 0, 100% 0;
  background-repeat: no-repeat; 
}
VVS
  • 2,147
  • 1
  • 13
  • 13
1

For cross-browser support you can try as well imitate a gradient border with :before or :after pseudo elements, depends on what you want to do.

Denees
  • 9,100
  • 13
  • 47
  • 76
0

try this code

.gradientBoxesWithOuterShadows { 
height: 200px;
width: 400px; 
padding: 20px;
background-color: white; 

/* outer shadows  (note the rgba is red, green, blue, alpha) */
-webkit-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.4); 
-moz-box-shadow: 0px 1px 6px rgba(23, 69, 88, .5);

/* rounded corners */
-webkit-border-radius: 12px;
-moz-border-radius: 7px; 
border-radius: 7px;

/* gradients */
background: -webkit-gradient(linear, left top, left bottom, 
color-stop(0%, white), color-stop(15%, white), color-stop(100%, #D7E9F5)); 
background: -moz-linear-gradient(top, white 0%, white 55%, #D5E4F3 130%); 
}

or maybe refer to this fiddle: http://jsfiddle.net/necolas/vqnk9/

x'tian
  • 734
  • 2
  • 14
  • 40
0

Here's a nice semi cross-browser way to have gradient borders that fade out half way down. Simply by setting the color-stop to rgba(0, 0, 0, 0)

.fade-out-borders {
min-height: 200px; /* for example */

-webkit-border-image: -webkit-gradient(linear, 0 0, 0 50%, from(black), to(rgba(0, 0, 0, 0))) 1 100%;
-webkit-border-image: -webkit-linear-gradient(black, rgba(0, 0, 0, 0) 50%) 1 100%;
-moz-border-image: -moz-linear-gradient(black, rgba(0, 0, 0, 0) 50%) 1 100%;
-o-border-image: -o-linear-gradient(black, rgba(0, 0, 0, 0) 50%) 1 100%;
border-image: linear-gradient(to bottom, black, rgba(0, 0, 0, 0) 50%) 1 100%;
}

<div class="fade-out-border"></div>

Usage explained:

Formal grammar: linear-gradient(  [ <angle> | to <side-or-corner> ,]? <color-stop> [, <color-stop>]+ )
                              \---------------------------------/ \----------------------------/
                                Definition of the gradient line         List of color stops  

More here: https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient

Yes Barry
  • 9,514
  • 5
  • 50
  • 69
0

Here's a gradient border with transparent background that works with border-radius

.gradient-border {
  border-radius: 999px;
  padding: 10px 3rem;
  display: inline-block;
  position: relative;
  background: transparent;
  border: none;
}

.gradient-border::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 2px;
  border-radius: 9999px;
  background: linear-gradient(87.36deg, blue 6.42%, red 84.24%),
linear-gradient(0deg, #FFFFFF, #FFFFFF);
  -webkit-mask: 
     linear-gradient(#fff 0 0) content-box, 
     linear-gradient(#fff 0 0);
          mask: 
     linear-gradient(#fff 0 0) content-box, 
     linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

Live demo: https://jsfiddle.net/jbernier/0eypxc74/1/

Jeremy Bernier
  • 1,746
  • 1
  • 17
  • 17
-1

There is a nice css tricks article about this here: https://css-tricks.com/gradient-borders-in-css/

I was able to come up with a pretty simple, single element, solution to this using multiple backgrounds and the background-origin property.

.wrapper {
  background: linear-gradient(#222, #222), 
              linear-gradient(to right, red, purple);
  background-origin: padding-box, border-box;
  background-repeat: no-repeat; /* this is important */
  border: 5px solid transparent;
}

The nice things about this approach are:

  1. It isn’t affected by z-index
  2. It can scale easily by just changing the width of the transparent border

Check it out: https://codepen.io/AlexOverbeck/pen/axGQyv?editors=1100

Alex
  • 2,312
  • 1
  • 14
  • 5
-1

Try this which supports transparent background and rounded corner not that concise though.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
    <defs>
        <mask id="cut-off-center">
            <rect x="0" y="0" rx="2" ry="2" width="78" height="28" fill="white"/>
            <rect x="1" y="1" rx="2" ry="2" width="76" height="26" fill="black"/>
        </mask>
        <linearGradient id="border">
            <stop offset="0" stop-color="rgba(0, 164, 255, 1)"/>
            <stop offset="1" stop-color="rgba(0, 127, 216, .47)"/>
        </linearGradient>
        <linearGradient id="background">
            <stop offset="0" stop-color="#72C5FF"/>
            <stop offset="1" stop-color="#0090FE"/>
        </linearGradient>
    </defs>
    <rect x="0" y="0" rx="2" ry="2" width="78" height="28" fill="url(#border)" mask="url(#cut-off-center)"/>
    <rect x="1" y="1" rx="2" ry="2" width="76" height="26" fill="url(#background)" fill-opacity="0.3"/>
</svg>

also you can use it as background image.

.box {
  width: 78px;
  height: 28px;
  color: orange;
  text-align: center;
  line-height: 28px;
  background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiPgogICAgPGRlZnM+CiAgICAgICAgPG1hc2sgaWQ9ImN1dC1vZmYtY2VudGVyIj4KICAgICAgICAgICAgPHJlY3QgeD0iMCIgeT0iMCIgcng9IjIiIHJ5PSIyIiB3aWR0aD0iNzgiIGhlaWdodD0iMjgiIGZpbGw9IndoaXRlIi8+CiAgICAgICAgICAgIDxyZWN0IHg9IjEiIHk9IjEiIHJ4PSIyIiByeT0iMiIgd2lkdGg9Ijc2IiBoZWlnaHQ9IjI2IiBmaWxsPSJibGFjayIvPgogICAgICAgIDwvbWFzaz4KICAgICAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJvcmRlciI+CiAgICAgICAgICAgIDxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0icmdiYSgwLCAxNjQsIDI1NSwgMSkiLz4KICAgICAgICAgICAgPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSJyZ2JhKDAsIDEyNywgMjE2LCAuNDcpIi8+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgICAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJhY2tncm91bmQiPgogICAgICAgICAgICA8c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM3MkM1RkYiLz4KICAgICAgICAgICAgPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA5MEZFIi8+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDwvZGVmcz4KICAgIDxyZWN0IHg9IjAiIHk9IjAiIHJ4PSIyIiByeT0iMiIgd2lkdGg9Ijc4IiBoZWlnaHQ9IjI4IiBmaWxsPSJ1cmwoI2JvcmRlcikiIG1hc2s9InVybCgjY3V0LW9mZi1jZW50ZXIpIi8+CiAgICA8cmVjdCB4PSIxIiB5PSIxIiByeD0iMiIgcnk9IjIiIHdpZHRoPSI3NiIgaGVpZ2h0PSIyNiIgZmlsbD0idXJsKCNiYWNrZ3JvdW5kKSIgZmlsbC1vcGFjaXR5PSIwLjMiLz4KPC9zdmc+')
}
<div class="box">text</div>
Dictator
  • 105
  • 1
  • 9
  • Your first example is SVG, which is neither HTML nor CSS, and doesn't involve CSS borders at all. Your second example also has no borders involved with it whatsoever. The question was about achieving gradients with CSS *borders*, not just using gradients as backgrounds. – TylerH Aug 24 '23 at 18:40
  • I've found all the answers have some pros & cons, there's no perfect css solution to this question for now, but there are pefect answers for specific senarios. So I propose a different approach to implement the demanded style which maybe helpful to some other coders. – Dictator Aug 28 '23 at 09:02