web-dev-qa-db-fra.com

Possible d'utiliser frontière-rayon avec une image-bordure qui a un dégradé?

J'appelle un champ de saisie qui a une bordure arrondie (border-radius) et j'essaie d'ajouter un dégradé à cette bordure. Je peux réussir à faire le dégradé et la bordure arrondie, mais ni l'un ni l'autre ne fonctionnent ensemble. C'est soit arrondi sans dégradé, soit une bordure avec un dégradé, mais pas de coins arrondis.

-webkit-border-radius: 5px;
-webkit-border-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b0bbc4), to(#ced9de)) 1 100%;

Y a-t-il un moyen de faire en sorte que les deux propriétés CSS fonctionnent ensemble ou est-ce impossible?

50
paulwilde

Probablement pas possible, selon les spécifications du W3C:

Les milieux d'une boîte, mais pas son border-image, sont clipsés dans le courbe appropriée (comme déterminé par ‘background-clip’). Autres effets qui clipser sur la bordure ou le bord de remplissage (par exemple, ‘overflow’ autre que ‘visible’) courbe. Le contenu de remplacé éléments est toujours coupé à la contenu courbe de bord. En outre, la région en dehors de la courbe de la bordure Edge n'accepte pas les événements de souris pour le compte de l'élément.

Ceci est probablement dû au fait que border-image peut prendre des modèles potentiellement compliqués. Si vous souhaitez une bordure d'image arrondie, vous devez en créer une vous-même.

29
Shauna

Ceci est possible et ne nécessite pas de balisage supplémentaire, mais utilise un pseudo-élément ::after .

screenshot

Cela implique de placer un pseudo-élément avec un fond dégradé et de le découper. Cela fonctionne dans tous les navigateurs actuels sans préfixes ni hacks (même IE), mais si vous souhaitez prendre en charge les versions anciennes d'IE, vous devez envisager des solutions de remplacement des couleurs unies, javascript et/ou des extensions CSS MSIE personnalisées (par exemple, filter. , superposition de vecteurs à la CSSPie, etc.).

Voici un exemple en direct ( version jsfiddle ):

@import url('//raw.githubusercontent.com/necolas/normalize.css/master/normalize.css');

html {
    /* just for showing that background doesn't need to be solid */
    background: linear-gradient(to right, #DDD 0%, #FFF 50%, #DDD 100%);
    padding: 10px;
}

.grounded-radiants {
    position: relative;
    border: 4px solid transparent;
    border-radius: 16px;
    background: linear-gradient(orange, Violet);
    background-clip: padding-box;
    padding: 10px;
    /* just to show box-shadow still works fine */
    box-shadow: 0 3px 9px black, inset 0 0 9px white;
}

.grounded-radiants::after {
    position: absolute;
    top: -4px; bottom: -4px;
    left: -4px; right: -4px;
    background: linear-gradient(red, blue);
    content: '';
    z-index: -1;
    border-radius: 16px;
}
<p class="grounded-radiants">
    Some text is here.<br/>
    There's even a line break!<br/>
    so cool.
</p>

Le style supplémentaire ci-dessus est de montrer:

  • Cela fonctionne avec n'importe quel fond
  • Cela fonctionne très bien avec box-shadow, inset ou pas
  • Ne vous oblige pas à ajouter l'ombre au pseudo-élément

Encore une fois, cela fonctionne avec les navigateurs IE, Firefox et Webkit/Blink.

84
Camilo Martin

Travaillant sur le même problème et trouvant une solution non-svg qui est plus succincte que d’autres ici:

.rounded-color-border-element{
  width: 300px;
  height: 80px;
  border: double 4px transparent;
  border-radius: 80px;
  background-image: linear-gradient(white, white), radial-gradient(circle at top left, #f00,#3020ff);
  background-Origin: border-box;
  background-clip: content-box, border-box;
}

Ce n'est pas ma propre solution et a été prise à partir d'ici: https://Gist.github.com/stereokai/36dc0095b9d24ce93b045e2ddc60d7a0

3
theeastcoastwest

Cela fonctionne toujours pour moi dans WebKit, bien que ce soit un peu compliqué!

En gros, il suffit d'agrandir la bordure puis de la masquer avec les bordures de pseudo-éléments plus grandes et plus petites:).

.thing {
  display: block;
  position: absolute;
  left: 50px;
  top: 50px;
  margin-top: 18pt;
  padding-left: 50pt;
  padding-right: 50pt;
  padding-top: 25pt;
  padding-bottom: 25pt;
  border-radius: 6px;
  font-size: 18pt;
  background-color: transparent;
  border-width: 3pt;
  border-image: linear-gradient(#D9421C, #E8A22F) 14% stretch;
}
.thing::after {
  content: '';
  border-radius: 8px;
  border: 3pt solid #fff;
  width: calc(100% + 6pt);
  height: calc(100% + 6pt);
  position: absolute;
  top: -6pt;
  left: -6pt;
  z-index: 900;
}
.thing::before {
  content: '';
  border-radius: 2px;
  border: 1.5pt solid #fff;
  width: calc(100%);
  height: calc(100% + 0.25pt);
  position: absolute;
  top: -1.5pt;
  left: -1.5pt;
  z-index: 900;
}

http://plnkr.co/edit/luO6G95GtxdywZF0Qxf7?p=preview

2
Becky Conning

J'utiliserais SVG pour cela:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 220" width="100%" height="100%" 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>
  <ellipse ry="100" rx="100" cy="110" cx="110" style="fill:none;stroke:url(#gradient);stroke-width:6;" />
</svg>

SVG peut être utilisé en tant que fichier séparé (moyen préféré) ou comme partie de la valeur de background (le code ci-dessous ne fonctionnera que dans les navigateurs webkit):

div {
  width: 250px;
  height: 250px;
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 220" width="100%" height="100%" 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><ellipse ry="100" rx="100" cy="110" cx="110" style="fill:none;stroke:url(#gradient);stroke-width:6;" /></svg>');
}
<div></div>

Pour que cela fonctionne dans MS Edge et Firefox, nous devons échapper notre balisage après le utf8. Nous allons donc remplacer les guillemets doubles " par des guillemets simples ', # avec %23 et % par %25:

div {
  width: 250px;
  height: 250px;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220' width='100%25' height='100%25' preserveAspectRatio='none'><defs><linearGradient id='gradient'><stop offset='0' style='stop-color:%230070d8' /><stop offset='0.5' style='stop-color:%232cdbf1' /><stop offset='1' style='stop-color:%2383eb8a' /></linearGradient></defs><ellipse ry='100' rx='100' cy='110' cx='110' style='fill:none;stroke:url(%23gradient);stroke-width:6;' /></svg>");
  background-size: 100% 100%; /* Fix for Fifefox image scaling */
}
<div></div>

2
Vadim Ovchinnikov

Et si vous appliquez le dégradé à l'arrière-plan. Ensuite, ajoutez un div supplémentaire à l’intérieur, avec une marge définie sur l’ancienne largeur de la bordure et un fond blanc, et bien sûr un borderradius. De cette façon, vous obtenez l’effet d’une bordure, mais vous utilisez en réalité un arrière-plan correctement découpé.

2
Gerben

Solutions pour transparent elements: Travaillant au moins dans Firefox.

Il y a en fait un moyen que j'ai trouvé sans pseudo-classes - mais cela ne fonctionne que pour les gradients radiaux:

body {
  background: linear-gradient(white, black), -moz-linear-gradient(white, black), -webkit-linear-gradient(white, black);
  height: 300px;
  
  }

div{
text-align: center;
  width: 100px;
  height: 100px;
  font-size:30px;
  color: lightgrey;
  border-radius: 80px;
  color: transparent;
  background-clip: border-box, text;
  -moz-background-clip: border-box, text;
  -webkit-background-clip: border-box, text;
  background-image: radial-gradient(circle,
      transparent, transparent 57%, yellow 58%, red 100%), repeating-linear-gradient(-40deg, yellow,
  yellow 10%, orange 21%, orange 30%, yellow 41%);
  line-height: 100px;
}
<body>
<div class="radial-gradient"> OK </div>
</body>

Obtenir un élément transparent avec des pseudo-classes n'a été trouvé que de cette façon - ok, ce n'est pas un dégradé, mais au moins une bordure rayée multicolore (ressemblant à des bouées de sauvetage): 

body {
  background: linear-gradient(white, black, white);
  height: 600px;
  }

div{
  position: absolute;
  width: 100px;
  height: 100px;
  font-size:30px;
  background-color:transparent;
  border-radius:80px;
  border: 10px dashed orange;
  color: transparent;
  background-clip: text;
  -moz-background-clip: text;
  -webkit-background-clip: text;
  background-image: repeating-linear-gradient(-40deg, yellow,
  yellow 10%, orange 11%, orange 20%, yellow 21%);
  text-align:center;
  line-height:100px;
}


div::after {
    position: absolute;
    top: -10px; bottom: -10px;
    left: -10px; right: -10px;
    border: 10px solid yellow;
    content: '';
    z-index: -1;
    border-radius: 80px;
    }
<body>
<div class="gradient"> OK </div>
</body>

avec un svg (plus satisfaisant en terme de variabilité mais nécessite également la plupart des lignes de code): 

body{
  margin: 0;
  padding: 0;
}

div {
  position: absolute;
  display: flex;
  align-items: center;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
}

span {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 100px;
  height: 100px;
  line-height: 105px;
  font-size:40px;
  background-clip: text;
  -moz-background-clip: text;
  -webkit-background-clip: text;
  background-image: repeating-linear-gradient(-40deg, yellow,
  yellow 10%, orange 11%, orange 20%, yellow 21%);
  color: transparent;
}

svg {
  fill: transparent;
  stroke-width: 10px; 
  stroke:url(#gradient);
  
}
<head>

</head>
<body>

<div>
<span>OK</span>
  <svg>
    <circle class="stroke-1" cx="50%" cy="50%" r="50"/>
    <defs>
      <linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="15%" gradientTransform="rotate(-40)" spreadMethod="reflect">
       
        <stop offset="0%" stop-color="orange" />
        <stop offset="49%" stop-color="orange" />
        <stop offset="50%" stop-color="yellow" />
        <stop offset="99%" stop-color="yellow" />

      </linearGradient>
  </defs>
  </svg>
  

</div>

</body>

1
chrichrichri