为CSS边框箭头指定一侧的边框

时间:2016-07-14 12:06:55

标签: html css css3 css-shapes

我希望有人可以帮我找到一个优雅的方法来获得CSS箭头边框上的边框。

我正在努力创造这个:

enter image description here

到目前为止,这是我的代码:

HTML

<div class="message-container customer">
    <p class="message">Great thanks</p>
</div>

CSS

.message {
    width: auto;
    max-width: 66%;
    padding: 12px 30px;
    box-sizing: border-box;
    background: #ffffff;
    box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
    margin: 4px 0 0 0;
    position: relative;
    float: right;
    border-right: 4px solid #0892cb;
    border-radius: 5px 0 0 5px;
}

.message:after {
    top: 100%;
    right: 0;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
    border-color: rgba(255, 255, 255, 0);
    border-bottom-color: #FFFFFF;
    border-width: 10px;
    margin-right: -14px;
    margin-top: -10px;
    transform: rotate(45deg);
    box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
}

这是一个有效的JS小提琴https://jsfiddle.net/kdeo3wpg/

正如你所看到的那样,我在主要信息的右边有一个蓝色边框,但我也想不出办法在箭头上找到蓝色边框。如果可能的话我真的想避免使用图像。找到一个只有CSS的解决方案会很棒。

我曾考虑尝试使用:before sudo元素,但我无法获得所需的完全控制权。

非常感谢任何帮助。

更新

我设法找到了解决方案,但说实话,它不是很干净。

https://jsfiddle.net/kdeo3wpg/1/

我所做的是添加一个新元素,它是边框的宽度并具有相同的背景颜色。然后我将高度设置为略小于CSS箭头的高度。然后我给我的新元素一个CSS箭头边框的背景颜色。

这是新代码:

HTML

<div class="message-container customer">
    <p class="message">
        Great thanks
        <span class="arrow-border"></span>
    </p>
</div>

CSS

.message {
  width: auto;
  max-width: 66%;
  padding: 12px 30px;
  box-sizing: border-box;
  background: #ffffff;
  box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
  margin: 4px 0 0 0;
  position: relative;
  float: right;
  border-right: 4px solid #0892cb;
  border-radius: 5px 0 0 5px;
}

.message:after {
    top: 100%;
    right: 0;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
    border-color: rgba(255, 255, 255, 0);
    border-bottom-color: #FFFFFF;
    border-width: 10px;
    margin-right: -14px;
    margin-top: -10px;
    transform: rotate(45deg);
    box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
  }

.arrow-border {
    position: absolute;
    background: #0892cb;
    width: 4px;
    height: 9px;
    bottom: -9px;
    right: -4px;
    z-index: 1;
}

.arrow-border:after {
    top: 100%;
    right: 0;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
    border-color: rgba(255, 255, 255, 0);
    border-bottom-color: #0892cb;
    border-width: 3px;
    margin-right: -3px;
    margin-top: -3px;
    transform: rotate(45deg);
    box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
}

虽然这个解决方案有效,但我觉得可能有更好更清洁的选择,所以我仍然愿意接受建议。

4 个答案:

答案 0 :(得分:5)

使用svg您可以创建文字气泡并将linearGradient应用于其中。

body {
  background: #eee;
}
<svg width="100" height="50" preserveAspectRatio="none" viewBox="-1 -1 102 52">
  <defs>
    <linearGradient id="grad">
      <stop offset="97%" stop-color="#fff" />
      <stop offset="97%" stop-color="#237ACB" />
    </linearGradient>
  </defs>
  <path d="M0,5 a5,5 0 0,1 5,-5 h95 v45 l-10,-10 h-85 a5,5 0 0,1 -5,-5" fill="url(#grad)" />
  <text x="50%" y="40%" text-anchor="middle" font-size="10">Great Thanks</text>
</svg>

要使文字气泡具有动态文字,您需要将三角形用作svg。该文字将在svg之外。

body {
  background: #eee;
}
#container {
  position: relative;
  display: table;
}
#text {
  position: relative;
  max-width: 200px;
  padding: 10px;
  box-sizing: border-box;
  background: linear-gradient(to right, #fff calc(100% - 3px), #237ACB calc(100% - 3px));
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
}
#tri {
  position: absolute;
  z-index: 1;
  top: calc(100% - 1px);
  right: 0;
}
<div id="container">
  <svg id="tri" width="15" height="15" preserveAspectRatio="none" viewBox="0 0 15 15">
    <defs>
      <linearGradient id="grad">
        <stop offset="79%" stop-color="#fff" />
        <stop offset="79%" stop-color="#237ACB" />
      </linearGradient>
    </defs>
    <path d="M0,0 h15 v15 l-15,-15" fill="url(#grad)" />
  </svg>
  <div id="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

应用box-shadow

要向box-shadow添加svg,您必须在路径上应用svg filter。通过CSS完成它将无法工作,因为CSS无法查看实际路径。

feFuncA元素的slope属性控制阴影的不透明度,feOffset是不言自明的。

body {
  background: #eee;
}
#container {
  position: relative;
  display: table;
}
#text {
  width: auto;
  max-width: 66%;
  padding: 12px 30px;
  box-sizing: border-box;
  background: #ffffff;
  box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
  margin: 4px 0 0 0;
  position: relative;
  float: right;
  border-right: 5px solid #0892cb;
  border-radius: 5px 0 0 5px;
}
#tri {
  position: absolute;
  z-index: 1;
  top: calc(100% - 1px);
  right: 0;
}
<div id="container">
  <svg id="tri" width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
    <defs>
      <linearGradient id="grad">
        <stop offset="70%" stop-color="#fff" />
        <stop offset="70%" stop-color="#0892cb" />
      </linearGradient>
      <filter id="shadow" height="130%">
        <feOffset dx="0" dy="2" in="SourceAlpha" result="offout" />
        <feComponentTransfer>
          <feFuncA type="linear" slope="0.1" />
        </feComponentTransfer>
        <feMerge>
          <feMergeNode/>
          <feMergeNode in="SourceGraphic" />
        </feMerge>
      </filter>
    </defs>
    <path d="M0,0 h15 v15 l-15,-15" filter="url(#shadow)" fill="url(#grad)" />
  </svg>
  <div id="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

重用svg

要多次使用相同的svg path,您可以在path元素中定义defs元素,并使用use多次使用它元素如下例所示。

body {
  background: #eee;
}
.containerIn, .containerOut {
  position: relative;
  display: table;
  margin: 4px 0 15px;
}
.text {
  width: auto;
  max-width: 66%;
  padding: 12px 30px;
  box-sizing: border-box;
  background: #ffffff;
  box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
  margin: 4px 0 0 0;
  position: relative;
  float: right;
  border-right: 5px solid #0892cb;
  border-radius: 5px 0 0 5px;
}
.containerIn .text {
  border: 0;
  border-left: 5px solid #689F38;
  border-radius: 0 5px 5px 0;
  float: left;
}

.tri {
  position: absolute;
  z-index: 1;
  top: calc(100% - 1px);
  right: 0;
}
.containerIn .tri {
  left: 0;
}
<svg width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
  <defs>
    <linearGradient id="gradRight">
      <stop offset="70%" stop-color="#fff" />
      <stop offset="70%" stop-color="#0892cb" />
    </linearGradient>
    <linearGradient id="gradLeft">
      <stop offset="31%" stop-color="#689F38" />
      <stop offset="31%" stop-color="#fff" />
    </linearGradient>
    <filter id="shadow" height="130%">
      <feOffset dx="0" dy="2" in="SourceAlpha" result="offout" />
      <feComponentTransfer>
        <feFuncA type="linear" slope="0.1" />
      </feComponentTransfer>
      <feMerge>
        <feMergeNode/>
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
    <path id="triRight" d="M0,0 h15 v15z" filter="url(#shadow)" fill="url(#gradRight)" />
    <path id="triLeft" d="M0,0 v15 l15,-15z" filter="url(#shadow)" fill="url(#gradLeft)" />
  </defs>
</svg>

<div class="containerOut">
  <svg class="tri" width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
    <use xlink:href="#triRight" x="0" y="0" />
  </svg>
  <div class="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

<div class="containerIn">
  <svg class="tri" width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
    <use xlink:href="#triLeft" x="0" y="0" />
  </svg>
  <div class="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

<div class="containerIn">
  <svg class="tri" width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
    <use xlink:href="#triLeft" x="0" y="0" />
  </svg>
  <div class="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

<div class="containerOut">
  <svg class="tri" width="15" height="18" preserveAspectRatio="none" viewBox="0 0 15 18">
    <use xlink:href="#triRight" x="0" y="0" />
  </svg>
  <div class="text">Text bubble that will change its width to <code>max-width</code>(200px) and height to contain the dynamic text</div>
</div>

答案 1 :(得分:2)

如果您希望边框比元素更大,则可以在span元素上使用p作为蓝色边框而不是边框​​。你还需要调整位置。

这仅适用于白色背景。

&#13;
&#13;
* {
  box-sizing: border-box;
}
body {
  background: white;
}
.message {
  width: auto;
  max-width: 66%;
  padding: 12px 30px;
  box-sizing: border-box;
  background: #ffffff;
  box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
  margin: 4px 0 0 0;
  position: relative;
  float: right;
  border-radius: 5px 0 0 5px;
  margin: 10px;
}
.message:after {
  bottom: -9px;
  right: -5px;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
  border-color: rgba(255, 255, 255, 0);
  border-bottom-color: #FFFFFF;
  border-width: 10px;
  transform: rotate(45deg);
  box-shadow: 0 2px 0 2px rgba(177, 177, 177, .07), 0 2px 0 0 rgba(0, 0, 0, .1);
}
span {
  content: '';
  right: 0;
  top: 0;
  position: absolute;
  height: calc(100% + 18px);
  border-right: 5px solid #0892cb;
  display: inline-block;
}
span:after {
  content: '';
  width: 11px;
  height: 11px;
  background: white;
  position: absolute;
  bottom: -7px;
  right: -3px;
  transform: rotate(50deg);
}
&#13;
<div class="message-container customer">
  <p class="message">Great thanks <span></span>
  </p>
</div>
&#13;
&#13;
&#13;

您也可以使用SVG

&#13;
&#13;
body {
  background: #F4F4F3;
}
.st0 {
  fill: #B2B3B3;
}
.st1 {
  font-size: 30px;
}
.st2 {
  fill: #FFFFFF;
}
.st3 {
  fill: none;
}
.st4 {
  fill: #3079BE;
}
.st5 {
  font-size: 20;
}
&#13;
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="260.5px" height="120.5px" viewBox="0 0 260.5 120.5" style="enable-background:new 0 0 260.5 120.5;" xml:space="preserve">

  <path class="st0" d="M256.016,20.217l0.961,97.533l-22.195-22L24.75,96.167c-6.653,0-11.417-5.834-11.917-10.972V20.217
	c0-6.429,5.389-11.637,12.042-11.637h219.099c3.51,0,12.041,0,12.041,0S256.016,17.182,256.016,20.217z" />
  <g>
    <path class="st2" d="M256.018,15.976v99.42l-21.16-20.42H25.688c-6.63,0-12-5.38-12-12v-67c0-6.63,5.37-12,12-12h218.33
		c3.499,0,12,0,12,0S256.018,12.845,256.018,15.976z" />
    <polygon class="st4" points="256.5,116.524 249.813,110.064 249.813,4.493 256.643,4.493 	" />
  </g>
  <rect x="84.5" y="36" class="st3" width="109.5" height="19.75" />
  <text x="50%" y="60px" text-anchor="middle" class="st1 st5">Great thanks</text>
  <path class="st0" d="M234.448,97.333" />
</svg>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

如果您希望使用单个元素创建此设计,您可以使用伪元素来使用Skew之类的东西来创建底部三角形以及这些元素上的右边界创建蓝色部分。

快速演示如下:

.message{
  display:inline-block;
  min-width:100px;
  position:relative;
  padding:10px;
  padding-right:30px;
  background:lightgray;
  border-radius:10px 0 0 10px;
  box-shadow: 0 2px 2px #222;
  }
.message:before,.message:after{
  content:"";
  position:absolute;
  top:0;right:0;
  height:100%;
  width:20px;
  background:inherit;
  border-right:5px solid cornflowerblue;
  }
.message:before{
  height:50%;top:50%;
  width:10px;
  box-shadow:inherit;
  transform:skewY(45deg);
  transform-origin:top left;
  }
<div class="message">I'm Doing Well Thanks</div>

答案 3 :(得分:0)

已经回答了,但是有一个元素和一个伪+渐变,它可以做得很安静。

body {
  background: #F4F4F3;
}

span {
  display: inline-block;
  position: relative;
  padding: 1em;
  margin: 0 1em;
  border-radius: 5px 0 0 5px;
  box-shadow: -2px 2px 3px -2px gray;
  background: #FFFFFF;
  font-size: 18px;
}

span:after {
  content: '';
  position: absolute;
  top:0;
  /* from here it is a matter of tunning */
  bottom:-10px;
  width:4.5em;/* see this to increase/decrease angle */
  background:linear-gradient(230deg, #237ACB 50%,transparent 50% ) no-repeat top right,/* degrees to follow width/angle set earlier */
    linear-gradient(to bottom left, #FFFFFF 50%, gray calc(50% + 1px) , transparent calc(50% + 2px)  );/* about blending bg and drawing the the slant bottom shadow */
  background-size:5px 197%, auto auto;/* about to draw the blue line just as big as it needs */
  z-index:-1;
  right:-11px;/* tune about width /angle given earlier */
}
<span> Great thanks</span>

http://codepen.io/gc-nomade/pen/qNyAVa