记一个tab按钮

UI 如下。 拿到这个设计图的时候,我一眼就看出这里搞起来会比较麻烦, 但是,工期不是很赶,我也有大致的思路,所以就默不作声的接了下来。

image.png

image.png
还有一点很重要,那就是可行性,这个tab栏注定只有两列,特事特办,大于两列的话,UI能画出来我肯定也直接拒绝。

说点题外话,那就是css写起来真的挺费时间的,复制粘贴就快了。

方案1

基本布局

看到这个效果我第一反应就是要用裁剪,因为除了svg,dom元素的形状就只有方圆的组合。这个坡度,看似可以用一个斜线加两个圆弧平凑起来,但是我已经知道可以用裁剪了,就不想去麻烦的拼凑了。

先上结构, 就是简单的grid 布局,因为定死两列了。 宽度也是定死的,我一开始也没意识到,宽度必须定死。

 <div class="tab .grid-2col ">
        <div class='left cell' id="left-cell">
            场景
        </div>
        <div class= ' right cell' id="right- cell">
           元素
        </div>
 </div>
   <div class="next">

   </div>
 
.grid-2col {
  display: grid;
  grid: auto-flow / repeat(2, 1fr);
  align-items: center;
  justify-items: center;
  grid-row-gap: 8px;
  width: 100px;
}



  .next{ 
    position: relative;
    background-color: #fff;
    height: 40px;
    width: 316px;
    border-radius: 12px 12px 0 0 ;
  }

布局和颜色弄好了之后就是这样的, 这个tab下面还有一个元素,而且是必要的,因为下面还有一条弧线, 这个就要依赖下面的元素圆角来实现, 因为加了margin负值所以下面的圆角被挡住了,我当然是要下面的能挡住上面的,所以要给下面的加一点层级。

image.png

image.png

Active

然后来加上Active效果。 Active效果,就是把对应的元素进行放大(宽高和字体,这里没有直接用transform scale,不好控制), 裁剪,变色。

会写path,裁剪是很简单的, 唯一要注意的就是,裁剪里面放的是一个形状,做不了任何变换, 这个形状是以元素的左上角为基准点的, 所以裁剪元素的右上角,只能靠准确的数值。 下图,就是右左按钮要裁剪的形状, 我这里直接用贝塞尔曲线做平滑过渡, 因为用圆太麻烦了。

image.png

搞定裁剪,加上颜色之后,来看看效果。

image.png

.tab .cell.active{ 
   background-color: #fff;
   font-size: 16px;
   width: 55%;
   top: -12px;
   border: none;
   /* filter: drop-shadow(-1px -1px 4px #333 ); */
   padding-bottom: 20px;
   color: #23252A;
   transform: translateZ(.1px);
   
 }


 .cell.active.right{
   clip-path: path('m30 0  c -20 0   -10 40   -30 40  v10 h350 v-50 z');
 }
 .cell.active.left{ 
   clip-path: path('m143 0  c 20 0   10 40   30 40  v10 h-173 v-50 z');
 }

然后,再调整一下相对位置和体积,基本效果已经出来了。现在没有用任何的边框,全部是靠区域颜色的差异,来出效果的。
image.png

但是还有一个夜间模式,需要边框,我可以给几个边框,但是 那条贝塞尔曲线那里是弄不了边框的。我的降级方案就是,仍然利用色差,给Active的tab不一样的黑色,来表现边界。

再加上js事件切换active就行了。

方案2

在方案1的基础上,用阴影模拟边框。 边框管理一直都很麻烦,而且边框是只有方圆的,行内元素可能例外一点,但是不合用。

我之前就想到过任意形状阴影的实现,就是裁剪加投影,但是我现在试了一下发现不太行。 投影也被剪裁了。 翻了一下之前的笔记,果然还是得再套一层。

给内层元素裁剪,外层元素投影,即可实现任意形状阴影。

        <div class= ' right cell' id="right-cell">
          <div class="inner-clip">
 
 
.night .tab .cell.active.right {
  filter: drop-shadow(-.1px -1px 3px #666);
}
.night .tab .cell.active.left {
  filter: drop-shadow(.1px -1px 3px #666);
}


.night .tab .cell.active .inner-clip  {
  border: none;
}

至于投影
drop-shaow和阴影box-shadow的区别,那就是阴影只是边框的延伸,而投影真的是这个元素的影子。

image.png

利用投影的特性,我们就可以得到和元素一模一样的影子,从而模拟边框。 只是模拟而已,人家这个投影,从影子的角度来说是完全没问题的,但是模拟边框的话,就显得不够硬朗。 可以看到多了左边的边框,如果不给next上边框的话,就会少右边,给了就会多,但是不给的话没有区域感。所以这里选择给了。

image.png

这里还有一点小问题,那就是投影被相邻元素挡住了,虽然元素本身没有遮挡,但是它的影子被挡住了,所以不得不提高一下层级,这里用的是加了个transform。

方案3

分层, 正常层和活跃层, 只对活跃层裁剪。没差太多,也就是样式好管理一些,不像上面拼凑的厉害,边框确实不好管理。
裁剪是反着来的,因为活跃层在上面,会遮挡住下面的东西,要让下面的层,露出来,那就的把活跃层对应的部分给裁剪掉。

先看结构, 就是用定位重合在一起的,根据后来居上的原则,把活跃层放在后面就可以遮挡住通常层了。

      <div class="tab">

        <div class="normal-layer grid-2col">
          <span>
            场景  
          </span>
          <span>
            
            元素
          </span>
        </div>
        <div class="active-layer grid-2col">
          <span>
            场景  
          </span>
          <span>
            
            元素
          </span>
        </div>
      </div>
.tab {
  position: relative;
    padding-bottom: 8px;
    margin-bottom: -19px;
    width: 316px;
    height: 40px;
    transform-style: preserve-3d;
}


.tab .active-layer,.tab .normal-layer{ 
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

image.png

然后就是调整活跃层的字号,背景和裁剪。 现在的点击事件,只要给活跃层的外壳改类名就可以。
这次的裁剪路径,也就比上面的多了一个四分之一圆,圆角得手动画,略微有点麻烦。 其余的直角交给css的圆角了。

image.png

.tab .active-layer {
      top: -8px;
      font-size: 16px;
      background-color: #fff;
      padding: 9px 0 27px;
      transition: .2s;
    }

    .tab .normal-layer {
      background-color: #ededed;
      padding: 8px 0 20px;
    }


    .active-left {
      clip-path: path('m0 0 h150  c 20 0   10 40   30 44   h124 a 12 12 0 0 1 12 12 v30 h-316 z');
    }

    .active-right {
      clip-path: path('m 316 0  h-150  c -20 0   -10 40   -30 44   h-124 a 12 12 0 0 0 -12 12  v30 h316 z');
    }

分层之后的css代码少多了,而且结构清晰。加了过渡之后的效果,果然不可能是那种。

夜间模式还是有问题的,因为颜色对比没有白天模式那么清晰,所以需要加个投影充当边框,所以还需要加个父级。 加了父级之后,我发现之前的点击事件不灵了。

因为父级完全遮挡了下面,因为父级是用来加投影的,所以不能裁剪,下面的肯定就不能露出。 没办法,只能额外加两个元素用来触发事件了。

方案4

不如直接用svg算了,反正高宽都定死了。让我想想, 如果用svg ,那就是<path>元素绘制背景和边框,<text>元素写文本,但是图标呢,在上层弄一个<use>吧。 但是,这样要切换就不太方便, 只能是if else 切换元素的显示和隐藏了。

算了,我们直接快进到方案5,这和方案5也没啥差别了。

方案5

让UI 切图, 那就应该需要4张图,左右黑白。 这个图应该给父级容器作为背景,这样点击事件才不会受到影响。 实际上,前面已经把这个背景图画出来了。没错,就是那几个svg。这里就不用码上掘金演示了,不然还得发个沸点当图床。

基本思路就是,有四张图,分别是左右活跃,和白天黑夜的组合。 如下所示。 根据对应的状态切换底图即可,而不是给每个元素都来一张图。 因为这里的高宽尺寸是固定的,这就是大家常说的让UI切图。

192.168.110.82_12346_my-code_svg_wb.html.png

因为前面其实已经用svg画出来了,所以差别不大。这里竖线之所以看上去有问题,是因为stroke的宽度是均匀分布在路径两边的,所以要显示完整的边框,就要把边框的厚度计算进去,这里就不继续发散了。

结语

以上纯粹是个人的思维发散,实际上我也就是还没做,就想的是方案一。 做的时候,发现边框合成确实麻烦,又想起来任意形状的边框。 方案三的分层,是后面的思考。 至于方案四五,就如同上文所写,我也就想想而已,就放弃了。

最重要的是时间, 这个样式可以说在整个项目中无足轻重, 花费如此大的时间占比是相当不值得的。当然了,千金难买我乐意。有时候,就想鼓捣一下,项目里用不用,那也不是我能决定的。

UI的眼光是比较毒辣的,一眼就看出来我用的是阴影(他肯定不知道投影),而不是边框。我就反映了一下这个设计的问题,后面改成没有这种曲线的样式了。
工作之中还是要相互协商的。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYbENBcS' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片