zhangxinxu/quiz

CSS基础测试23期

Opened this issue · 7 comments

不使用伪元素,一层标签,实现下图所示的提示效果,支持渐变背景。

原图地址

本题需要在线demo,同时附上对应的CSS代码即可,可以使用下面语法进行高亮:

```css
你的代码在这里
```

本期小测无直播答疑,如果有精彩的实现会拿出来点评。

感谢您的参与!

JSBIN

<a>show tip</a>
<div class="tip">替换素材让视频与众不同</div>
.tip {
  display:none;
  position:absolute;
  top: 40px;
  left: 0;
  --h: 5px;
  padding: 10px;
  padding-top: calc(10px + var(--h));
  background:linear-gradient(45deg, red, pink);
  clip-path: polygon(0 var(--h),calc(20% - var(--h)) var(--h),20% 0%, calc(20% + var(--h)) var(--h),100% var(--h),100% 100%,0 100%)    
}
a + .tip{
  display:block;
}

jsbin

.tip {
  --unit: 5px;
  --h: calc(100% - var(--unit));
  display: inline-block;
  padding: 10px 10px calc(10px + var(--unit)) 10px;
  background-image: linear-gradient(to right, #ff607b, #ff3a3e);
  color: #fff;
  clip-path: polygon(0 5px, 1px 1px, 5px 0, calc(100% - 5px) 0, calc(100% - 1px) 1px, calc(100%) 5px, 100% calc(var(--h) - 5px), calc(100% - 1px) calc(var(--h) - 1px), calc(100% - 5px) var(--h), calc(20% - 2*var(--unit)) var(--h), calc(20% - var(--unit)) 100%, 20% var(--h), 5px var(--h), 1px calc(var(--h) - 1px), 0 calc(var(--h) - 5px));
}
<div class="tip">替换素材让视频与众不同</div>

clip-path+polygan()可以实现,但是如果要加上圆角好像有点难搞?

demo

<div class="tip">这是一段提示文字,这是一段提示文字,这是一段提示文字</div>
.tip {
  max-width: 240px;
  padding: 10px 10px 15px 10px;
  clip-path: polygon(0% 0%, 100% 0%, 100% calc(100% - 5px), 23px calc(100% - 5px), 20px 100%, 17px calc(100% - 5px), 0% calc(100% - 5px));
  background: linear-gradient(120deg, lightpink 30%, pink 70%);
}
y2x33 commented

demo

算到头秃
也可以用inset做一个带 border-radius 的框体 + polygan()三角形,但是那样就不得不用伪元素了

<div class="tip show">替换素材让视频与众不同</div>
:root {
    --sin15: 0.2588;
    --sin30: 0.5;
    --sin45: 0.7071;
    --sin60: 0.866;
    --sin75: 0.9659;

    --outer: 6px;  /* 小三角形的高度 */
    --inner: 10px; /* padding */
    --br: 6px;     /* border-radius */
    --diff-0: 0px;
    --diff-15: calc(var(--sin15)* var(--br));
    --diff-30: calc(var(--sin30)* var(--br));
    --diff-45: calc(var(--sin45)* var(--br));
    --diff-60: calc(var(--sin60)* var(--br));
    --diff-75: calc(var(--sin75)* var(--br));
    --diff-90: var(--br);

}

    
.tip {
  display: none;
  max-width: 200px;
  padding: var(--inner);
  border-radius: var(--br);
  padding-bottom: calc(var(--inner) + var(--br));
  color: white;
  background:linear-gradient(45deg, red, pink);
  --x1: calc(100% - var(--br));
  --y1: calc(100% - var(--br) - var(--outer));
  --x2: var(--br);
  --y2: var(--y1);
        
  clip-path: polygon(
          calc(var(--x2) - var(--diff-0))  calc(var(--y2) + var(--diff-90)),
          calc(var(--x2) - var(--diff-15)) calc(var(--y2) + var(--diff-75)),
          calc(var(--x2) - var(--diff-30)) calc(var(--y2) + var(--diff-60)),
          calc(var(--x2) - var(--diff-45)) calc(var(--y2) + var(--diff-45)),
          calc(var(--x2) - var(--diff-60)) calc(var(--y2) + var(--diff-30)),
          calc(var(--x2) - var(--diff-75)) calc(var(--y2) + var(--diff-15)),
          calc(var(--x2) - var(--diff-90))  calc(var(--y2) + var(--diff-0)),
            
          0 0,
          100% 0,
  
          calc(var(--x1) + var(--diff-90)) calc(var(--y1) + var(--diff-0)),
          calc(var(--x1) + var(--diff-75)) calc(var(--y1) + var(--diff-15)),
          calc(var(--x1) + var(--diff-60)) calc(var(--y1) + var(--diff-30)),
          calc(var(--x1) + var(--diff-45)) calc(var(--y1) + var(--diff-45)),
          calc(var(--x1) + var(--diff-30)) calc(var(--y1) + var(--diff-60)),
          calc(var(--x1) + var(--diff-15)) calc(var(--y1) + var(--diff-75)),
          calc(var(--x1) + var(--diff-0))  calc(var(--y1) + var(--diff-90)),
  
          /* 三角形三个点 */          
          calc(var(--x2) + 32px) calc(var(--y2) + var(--diff-90)),
          calc(var(--x2) + 26px) 100%,
          calc(var(--x2) + 20px) calc(var(--y2) + var(--diff-90))
            
            
  );
}
      
.tip.show {
  display: block;
}
        

一开始没看懂题意,不过看懂题意之后也一脸懵比

楼上大佬就硬算出来可太秀了,我觉得我算到真的头秃了也算不出来……

所以最后借助了一个几何作图工具,画出多边形并标出坐标,应该勉强算是符合题意吧。作图工具 Geogebra

Demo

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <a>替换</a>
  <div>替换素材让视频与众不同</div>
  
</body>
</html>
div {
  display: none;
  max-width: 200px;
  padding: 10px;
  
  padding-top: 16px;
  color: white;
  background:linear-gradient(45deg, red, pink);
clip-path: polygon(2px 39px,7px 40px, 190px 40px,195px 39px, 197px 35px,197px 14px,195px 11px, 190px 11px, 45px 10px,40px 0px, 35px 10px, 7px 10px,2px 11px,0px 16px, 0px 35px);


}
      
a:hover+div {
  display: block;
}
    

JSBIN:demo

/**/
.icon {
  display: inline-block;
  width: 3em;
  height: 3em;
  line-height: 3em;
  text-align: center;
  background-color: rgba(0, 0, 0, 0.5);
  color: #ffffff;
  text-decoration: none;
  position: relative;
}

.nu-tip {
  position: absolute;
  bottom: 100%;
  left: -1em;
  font-size: 12px;
  padding: 1em 0.5em 1.5em;
  line-height: 1;
  white-space: nowrap;
  font-style: normal;
  /* 底部左右两个圆角只是近似和顶部左右两个圆角一致 */
  border-radius: 0.25em 0.25em 3em 3em / 0.25em 0.25em 0.8em 0.8em;
  background: linear-gradient(125deg, #fe6480, #f83534);
  clip-path: polygon(0 0, 100% 0, 100% 85%, 28% 85%, 24% 95%, 20% 85%, 0 85%);
}


/* 选中触发 */
.nu-tip-box .nu-tip {
  visibility: hidden;
  opacity: 0;
  transform: 200ms;
}

.nu-tip-box:hover .nu-tip,
.nu-tip-box:focus .nu-tip,
.nu-tip-box._open .nu-tip {
  visibility: visible;
  opacity: 1;
}

/* 以下是伪元素, 原理一样只是感觉这样dom 层级会少一些 */
.nu-tip2:before {
  content: attr(title);
  position: absolute;
  bottom: 100%;
  left: -1em;
  font-size: 12px;
  padding: 1em 0.5em 1.5em;
  line-height: 1;
  white-space: nowrap;
  font-style: normal;
  /* 底部左右两个圆角只是近似和顶部一致 */
  border-radius: 0.25em 0.25em 3em 3em / 0.25em 0.25em 0.8em 0.8em;
  background: linear-gradient(125deg, #fe6480, #f83534);
  clip-path: polygon(0 0, 100% 0, 100% 85%, 28% 85%, 24% 95%, 20% 85%, 0 85%);
}

/* 选中触发 */
.nu-tip2:before {
  visibility: hidden;
  opacity: 0;
  transform: 200ms;
}

.nu-tip2:hover:before,
.nu-tip2:focus:before,
.nu-tip2._open:before {
  visibility: visible;
  opacity: 1;
}

想了好久,感觉纯CSS没有比较完美的方法,然后借助了CSS Paint

demo

// tooltip.js
class Tooltip {
    static get inputProperties() {
        return [
            '--radius', // 圆角的幅度
        ]
    }
    paint(ctx, size, properties) {
        const { width,height } = size;
        const radius = Number(properties.get('--radius'))||5;
        const deg = Math.PI / 2;
        const edge = 10;
        const pos = 30;
        ctx.beginPath();
        ctx.moveTo(radius,0);
        ctx.lineTo(width-2*radius,0);
        ctx.arc(width-radius,radius,radius,-deg,0);
        ctx.lineTo(width,height-2*radius-edge);
        ctx.arc(width-radius,height-radius-edge,radius,0,deg);
        ctx.lineTo(pos+edge*0.6,height-edge);
        ctx.lineTo(pos,height);
        ctx.lineTo(pos-edge*0.6,height-edge);
        ctx.lineTo(radius,height-edge);
        ctx.arc(radius,height-radius-edge,radius,deg,2*deg);
        ctx.lineTo(0,radius-edge);
        ctx.arc(radius,radius,radius,-2*deg,-deg);
        ctx.closePath();
        ctx.fillStyle = '#000';
        ctx.fill();
        //ctx.stroke();
    }
}

registerPaint('tooltip', Tooltip);

HTML引入模块

<script>
if (window.CSS) {
    CSS.paintWorklet.addModule('tooltip.js')
}
</script>

然后在CSS直接使用

.tooptip {
    padding: 10px 10px 20px 10px;
    display: inline-block;
    max-width: 250px;
    color: #fff;
    background-image: linear-gradient(-45deg,red,blue);
    -webkit-mask: paint(tooltip);
}

image