如何编写一个按钮样式系统

最近计划开源一个框架,这里把其中一部分拿出来作个引子。看一下咱们如何完成一个按钮的制做。如下代码用SCSS编写 咱们先来作一个简单的。css

简单的上手

.btn{
    display: inline-block;
    font-weight: 400;
    text-align: center;
    vertical-align: middle;
    white-space: nowrap;
    line-height:26px;
}
复制代码

增长浏览器支持

够简单吧,下面咱们逐步丰富一下html

.btn{
    //上面写过的代码就省略了
    touch-action: manipulation;//解决移动端延迟问题
    cursor: pointer;//修改PC端鼠标样式
    white-space: nowrap;//对文字进行一下处理
}
复制代码
<div class="btn">这是个案例</div>
复制代码
这是个案例

禁用选择

若是用户出现了滑动选择的操做行为,浏览器的默认样式会看起来很难看,因此禁用一下选择web

.btn{
    //上面写过的代码就省略了
    -webkit-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
}
复制代码

案例展现bootstrap

<div class="btn">这里是不能选择的</div>
复制代码
这里是不能选择的

进行封装

这个看起来不是特别友好因此封装起来,总体以下浏览器

@mixin user-select($select) {
  -webkit-user-select: $select;
     -moz-user-select: $select;
      -ms-user-select: $select;
          user-select: $select;
}
.btn{
    display: inline-block;
    font-weight: 400;
    text-align: center;
    vertical-align: middle;
    white-space: nowrap;
    line-height:26px;
    touch-action: manipulation;//解决移动端延迟问题
    cursor: pointer;//修改PC端鼠标样式
    white-space: nowrap;//对文字进行一下处理
    @include user-select(none);
}
复制代码

色彩系统与样式组合

如今咱们给按钮上色,说到颜色,这个问题就比较难讲,从bootstrap开始,按钮的命名彷佛就是一成不变的,全部的绿色都叫success,全部的红色都加error,这种现象已经持续了将近十年,几乎全部的UI框架都是这么作的。可是实际上存在一个问题,就是业务和展现融合在了一块儿,好比我须要作一个加入购物车的按钮,为何我要命名为btn-error呢?或者有一天UI要将这个按钮的颜色从红色变成绿色,你又该如何操做呢。微信

在个人思惟逻辑里,最但愿看到的就是所想即所写,所写即所得。也就是说,当我看到设计稿的上绘制的是红色,我写的就应该是红色,网页显示的也应该是红色,一样的逻辑咱们能够采用彻底脱离业务的命名系统,经过class的组合来拓展样式,所以咱们须要创建一个色彩系统,这里以赤橙黄绿青蓝紫来举例;框架

$bg_colorList:(
	'red': #ff4c48,
	'orange': #ff9800,
	'yellow': #ff6705,
	'green': #2eb252,
	'coffee': #853f3a,
	'blue': #25aaff,
	'purple': #7000C8,
	'black':#000000,
	'white':#ffffff
);
.btn{
    //上面写过的代码就省略了
    color: white;//设置文字颜色
}
@each $colorName,$colorValue in $bg_colorList{
  .btn.#{$colorName}{
    background-color: $colorValue;
  }
}
复制代码

案例展现flex

<div class="btn red"></div>
复制代码
this is a btn

样式翻转

在咱们使用的按钮中并非全部的都是实心白字的,不少时候会用到彩色的边框,彩色的字的按钮,所以咱们给按钮一个翻转的样式优化

@each $colorName,$colorValue in $bg_colorList{
  .btn.#{$colorName}{
    background-color: $colorValue;
    &.reverse{
        background-color: white;
        border:1px solid $colorValue;
        color:$colorValue;
    }
  }
}
复制代码

案例展现this

<div class="btn red reverse"></div>
复制代码
this is a btn

边框调整

如今问题出现了,翻转的按钮多了一像素的边框,高度增长了两个像素(看下面的案例),为了保证全部按钮的尺寸统一,咱们能够采用两种方式,给实心按钮增长和背景色相同的边框,或者修改实心按钮的高度,这里咱们采用第一种方式。

this is a btn
this is a btn

这里另个btn高度明显看到差一个像素

@each $colorName,$colorValue in $bg_colorList{
  .btn.#{$colorName}{
    background-color: $colorValue;
    border:1px solid $colorValue;//增长边框
    &.reverse{
        background-color: white;
        border:1px solid $colorValue;
        color:$colorValue;
    }
  }
}
复制代码

案例展现

<div class="btn red"></div>
<div class="btn red reverse"></div>
复制代码
this is a btn
reverse btn

调整后的效果

样式抽取合并

你会发现这里有不少样式是重复的,因此咱们能够进行样式抽取

@mixin button-variant($color, $background, $border) {
  color: $color;
  background-color: $background;
  border-color: $border;
}
.btn{
    border: 1px solid transparent;
    @include button-variant(#666, #eee, #ccc);//设置默认色一般不会用到
    &.reverse{
        @include button-variant(#666, white, #ccc);
    }
}
@each $colorName,$colorValue in $bg_colorList{
  .btn.#{$colorName}{
    @include button-variant(white, $colorValue, $colorValue);
    &.reverse{
      @include button-variant(map-get($colorList,#{$colorName}), white, $colorValue);
    }
  }
}
复制代码

disable

接下来增长对disable和active的处理(这里只写出移动端的样式,PC端会稍复杂一些)

@mixin button-variant($color, $background, $border) {
  color: $color;
  background-color: $background;
  border-color: $border;
}
.btn{
    &.disabled,
    &[disabled],
    fieldset[disabled] & {
        cursor: not-allowed;
        opacity:.55;
        box-shadow:none
    }
}
a.btn {//a标签须要的额外处理
  &.disabled,
  fieldset[disabled] & {
    pointer-events: none; 
  }
}
复制代码
<div class="btn red disable"></div>
<div class="btn red reverse disable"></div>
复制代码
red disable
reverse and disable

效果展现

设置padding

接下来咱们设置pading并调整一下按钮的高度,若是咱们想作一个高度为36的按钮,行高26 边框1像素,那么上下的padding就应该是(36-26-2)/2 结果为4;水平方向没有影响,至于为何会选择44 36 28 而不选择其余的数值做为默认值,不在咱们本次的讨论范围内,之后会讲到。

.btn{
    padding:4px 15px;
}
复制代码

按钮固然不能只有一个尺寸,咱们能够多设计几个,并把相关代码提取出来。

$btn-size-list:(//$height, $padding-horizontal, $font-size
	'base':(36px,15px,16px),
	'small':(28px,15px,14px),
	'big':(44px,15px,16px),
);
@mixin button-size($height, $padding-horizontal, $font-size) {
  padding: ($height - 26px - 2) / 2 $padding-horizontal;
  font-size: $font-size;
}
.btn{
    @include button-size(
        nth(map-get($btn-size-list,'base'),1),
        nth(map-get($btn-size-list,'base'),2),
        nth(map-get($btn-size-list,'base'),3)
    );
}
@each $btnSizeName,$btnSizeValue in $btn-size-list{
  @if(#{$btnSizeName}!='base'){
    .btn.#{$btnSizeName}{
      @include button-size(
          nth($btnSizeValue,1),
          nth($btnSizeValue,2),
          nth($btnSizeValue,3)
      );
    }
  }
}
复制代码
<div class="btn red small"></div>
<div class="btn red "></div>
<div class="btn red big "></div>
复制代码
small
default
big

效果展现

圆角处理

$border-radius-base:        4px !default;
.btn{
    &.radius{
        border-radius: $border-radius-base;
      }
}
复制代码
<div class="btn red radius"></div>
<div class="btn red reverse radius"></div>
复制代码
default
reverse

效果展现

分组支持

在一些表单展现中会出现练成一排的按钮,若是带有圆角的话一般只有第一个和最后一个带有圆角。所以咱们增长一下分组的支持;

.btn-group{
  padding-left:1px;//抵消按钮负边距的距离
  @include clearfix();//清除浮动
  .btn{
    position: relative;//修改定位
    float: left;
    margin-left:-1px;//设置负边距让两个翻转按钮连在一块儿的时候边框只有一像素
    &.radius{
      border-radius:0;
      &:first-child{
        border-radius: $border-radius-base 0 0 $border-radius-base;
      }
      &:last-child{
        border-radius: 0 $border-radius-base  $border-radius-base 0;
      }
    }
  }
}
复制代码
<div class="btn-group">
    <div class="btn red reverse radius"></div>
    <div class="btn red reverse radius"></div>
    <div class="btn red reverse radius"></div>
</div>

复制代码
reverse
reverse
reverse

效果展现

块级支持

接下来咱们再给按钮增长一个铺满一行的状态,这个一般是用于展现一个比较长的按钮,好比登录注册,加入购物车,当即购买等。

.btn.block {
  display: block;
}
.btn.block + .btn.block{
  margin-top: 5px;
}
input[type="submit"],
input[type="reset"],
input[type="button"] {
  &.btn.block {
    width: 100%;
  }
}
复制代码
<div class="btn red block"></div>
复制代码
宽度占据整个容器的btn

效果展现

完整结构

至此一个按钮就基本完成了,咱们来看一下完整代码;

$border-radius-base:4px;
$btn-size-list:(//$height, $padding-horizontal, $font-size
	'base':(36px,15px,16px),
	'small':(28px,15px,14px),
	'big':(44px,15px,16px),
);
$bg_colorList:(
	'red': #ff4c48,
	'orange': #ff9800,
	'yellow': #ff6705,
	'green': #2eb252,
	'coffee': #853f3a,
	'blue': #25aaff,
	'purple': #7000C8,
	'black':#000000,
	'white':#ffffff
);
@mixin clearfix() {
  &:before,
  &:after {
    content: " ";
    display: table;
  }
  &:after {
    clear: both;
  }
}
@mixin user-select($select) {
  -webkit-user-select: $select;
     -moz-user-select: $select;
      -ms-user-select: $select;
          user-select: $select;
}
@mixin button-variant($color, $background, $border) {
  color: $color;
  background-color: $background;
  border-color: $border;
}
@mixin button-size($height, $padding-horizontal, $font-size) {
  padding: ($height - 26px - 2) / 2 $padding-horizontal;
  font-size: $font-size;
}
.btn {
  display: inline-block;
  margin-bottom: 0; 
  font-weight: 400;
  text-align: center;
  vertical-align: middle;
  touch-action: manipulation;
  cursor: pointer;
  background-image: none; 
  border: 1px solid transparent;
  white-space: nowrap;
  line-height:26px;
  @include button-variant(#666, #eee, #ccc);
  @include button-size(
      nth(map-get($btn-size-list,'base'),1)
      ,nth(map-get($btn-size-list,'base'),2)
      ,nth(map-get($btn-size-list,'base'),3)
  );
  @include user-select(none);
  &.radius{
    border-radius: $border-radius-base;
  }
  &.reverse{
    @include button-variant(#666, white, #ccc);
  }
  &.disabled,
  &[disabled],
  fieldset[disabled] & {
    cursor: not-allowed;
    opacity:.55;
    box-shadow:none
  }
}
@each $btnSizeName,$btnSizeValue in $btn-size-list{
  @if(#{$btnSizeName}!='base'){
    .btn.#{$btnSizeName}{
      @include button-size(
          nth($btnSizeValue,1),
          nth($btnSizeValue,2),
          nth($btnSizeValue,3)
      );
    }
  }
}
a.btn {
  &.disabled,
  fieldset[disabled] & {
    pointer-events: none; 
  }
}
@each $colorName,$colorValue in $bg_colorList{
  .btn.#{$colorName}{
    @include button-variant(white, $colorValue, $colorValue);
    &.reverse{
      @include button-variant($colorValue, white, $colorValue);
    }
  }
}
.btn.block {
  display: block;
}
.btn.block + .btn.block{
  margin-top: 5px;
}
input[type="submit"],
input[type="reset"],
input[type="button"] {
  &.btn.block {
    width: 100%;
  }
}
//btn-group
.btn-group{
  padding-left:1px;
  @include clearfix();
  .btn{
    position: relative;
    float: left;
    margin-left:-1px;
    &.radius{
      border-radius:0;
      &:first-child{
        border-radius: $border-radius-base 0 0 $border-radius-base;
      }
      &:last-child{
        border-radius: 0 $border-radius-base  $border-radius-base 0;
      }
    }
  }
}
复制代码
<div class="btn red radius"></div>
<div class="btn red reverse radius"></div>
复制代码
default
red
orange
yellow
green
coffee
blue
purple

效果展现

操做举例

如今咱们已经能够经过组合的方式来展现各类各样的按钮了,你可使用任何你须要使用的标签,这里均已DIV举例

<div class="btn">默认</div>
<div class="btn red">红色按钮</div><!--也能够将red替换成blue green等-->
<div class="btn small red">红色小按钮</div><!--也能够将替换成big-->
<div class="btn small red radius">红色圆角小按钮</div>
<div class="btn small red radius reverse">红色翻转圆角小按钮</div>
<div class="btn small red radius reverse block">宽红色翻转圆角小按钮</div>
<div class="btn-group">
    <div class="btn small red radius">第一个</div>
    <div class="btn small red radius">第二个</div>
    <div class="btn small red radius">第三个</div>
</div>
复制代码

后续优化

前文展现的代码只是按钮系统的一部分,实际的代码要比这个复杂的多,包括以下一些没有讲到的内容

  • 按钮和标签以及图标的组合
  • PC端不一样状态的切换
  • 表单的组合使用
  • 不一样色彩浓度的调整
  • 按需加载:动态生成和加载色彩系统
  • 动态修改:两个页面都使用了红色按钮但要求颜色不一样
  • 对方形 药片形 圆形等样式的支持

可是如今的已经能够直接编译使用,若是须要设置其余的尺寸或颜色能够修改默认的配置,编译生成直接使用就能够了。

若是你以为还有什么功能是你须要可是在这里没提到的能够添加个人微信给我留言,更多文章及直播教程能够关注冰山工做室公众号

相关文章
相关标签/搜索