纯CSS实现多选组件

最近我在 SF 开直播分享,针对这个话题作了更全面的讲解,感兴趣的同窗推荐观看:css

写 CSS 也要开脑洞:万能的 :checked + labelhtml


产品篇

在咱们的后台中,须要设置广告精准投放的区域,也就是要在全国31个省、自治区、直辖市中选择。那么,出现下面这幅景象也就理所应当了:segmentfault

典型的多选表单

这样作有几个问题:浏览器

  1. 选项不少,没有规律,找起来很累布局

  2. 若是是一个已经选择了部分选项的广告,修改时仍然须要用肉眼寻找,没法一眼看出来投放到哪些省份学习

  3. 选完一个,再选下一个,还要从头找,甚至会被已经选过的影响测试

因而我想,首先应该把全部选项分为“已选中”和“未选中”两批,解决第2个问题,减轻第3个问题;其次复选框自己的价值不大,能够被替换为其它样式;惟一可能引入的问题,就是点选时,用户的预期是看到复选框里出现一个小对勾,表示选中,若是我把它移开放到“已选中”组里,用户可能会迷惑,须要一些时间学习。flex

因而我跟某产品经理朋友聊了聊这个想法,他表示确实可能形成用户迷惑,不过若是能加入动画效果,那么基本没问题。嗯,开始动手。动画

技术实现篇

近日flexbox规范定案,各浏览器相继支持display:flex;,同时传来一条好消息,新实现比老实现display:box;快不少。此次我打算用flexbox来解决问题,由于里面有一个很重要的属性:order(以前叫box-ordinal-group),它能够改变布局中元素的排列顺序,配合CSS3新增的选择器,应该能够知足须要。网站

第一步 分拆选中/未选中

(关于flexbox的知识,能够经过Google了解,虽然搜到的可能是上一个版本,不过和最终版差异不大,只是叫法不一样。本文再也不过多讲解,我就当你们都会了)

<input type="checkbox">自己的样式不能修改,因此咱们必须借助<label>的帮助;实现选中/未选中区分,那天然就要用到伪类:checked;选择器必定是从外到内、从前到后的,无法选择父级元素,因此不能用<label>去包<input>,那么最终布局就只能是:

<div>
    <input type="checkbox" name="q[]" id="q1" />
    <label for="q1">小宝3225</label>
    <input type="checkbox" name="q[]" id="q2" />
    <label for="q2">王老白白白</label>
    <input type="checkbox" name="q[]" id="q3" />
    <label for="q3">空夫31</label>
    <input type="checkbox" name="q[]" id="q4" />
    <label for="q4">谷大白话</label>
    <input type="checkbox" name="q[]" id="q5" />
    <label for="q5">Meathill</label>
    <input type="checkbox" name="q[]" id="q6" />
    <label for="q6">爱财如命大师</label>
</div>

很简单哈,不解释了。CSS3新增了“下一节点”选择器 +,用来选择某节点的下一个节点,结合:checked伪类就能够将选中的<input>和它临近的<label>经过改变order属性移到前面去:

#container {
  display:flex;
  flex-direction:row;
  flex-wrap:wrap;
}
#container input,
#container label {
  order: 2; //全部选项、label顺序为2
}
input[type=checkbox]:checked,
input[type=checkbox]:checked + label {
  order: 0; // 越小越靠前
}

不过这样只是把选中的内容提早,视觉上没有真正的分割。因此我决定再加入一根分割线,上面是选中的,下面是未选的。这个时候咱们须要用到 ~ 这个选择器,选择某节点后面的节点:

hr {
  display:none; // 默认状况下,没选任何选项,分割线隐藏
  order: 1; // 分割线顺序为1
  width:100%; // 保证独霸一行
}
input[type=checkbox]:checked ~ hr {
  display:block; // 有选项被选中后才会显示分割线
}

http://jsfiddle.net/meathill/...

这样基础功能实现了。不过视觉上,排版仍然不整齐,选中的选项和未选中的选项区分不算太明显,因此下一步我准备美化下checkbox。

第二步,美化CHECKBOX

作法与前面相似,也要用到CSS3新增的选择器。前面为了实现<label>提早,没有用它包裹<input>,因此在选项不少很长致使换行的时候,可能出现复选框和标签脱离的尴尬情况。好在复选框的价值能够用别的样式取代,因此先把小方框隐藏起来,转而将<label>做为操做目标,再来点边框底色圆角(参考自Bootstrap 3),就能够了:

input[type=checkbox] {
  display: none;
}
label {
  min-width: 120px;
  border: 1px solid #CCC;
  padding: 2px 8px;
  text-align: center;
  margin: 0 5px 5px 0;
  background: #FFF;
  color: #333;
  border-radius: 3px;
  box-sizing: border-box;
}
label:hover {
  border-color: #ADADAD;
  background: #EBEBEB;
  cursor: pointer;
}
input[type=checkbox]:checked + label {
  order: 0;
  background-color: #5cb85c;
  border-color: #4cae4c;
  color: #FFF;
}
input[type=checkbox]:checked + label:hover {
  background-color: #47a447;
  border-color: #398439;
}

这样看起来还有上升空间,若是加上几个图标响应用户操做,那么学习成本会更低,对操做后的预期也会更准确。因而引用CDN上的font-awesome,使用:before伪类加上小图标,就获得了最终效果

http://jsfiddle.net/meathill/...

我无心中发现,这样批量添加删除时,鼠标能够常点不动,应该也是个意外的收获吧。

第三步,加入动画教育用户(失败)

至此功能基本作好了,不过因为修改了行为,可能致使用户迷惑,因此准备加个动画帮助用户理解这个交互。

惋惜做为一个新功能,浏览器的支持尚不完善,虽然规范中规定“animatable: yes”,可是实测在Chrome v.30下也没法工做:

http://jsfiddle.net/meathill/...

看来只有等新版浏览器发布后再去完善了。

兼容性

使用纯CSS作组件,几乎不用担忧兼容性问题,由于浏览器自己就作了很好的向下兼容,代码最多不生效,通常不会错。

具体到这个组件,由于只针对视觉效果,没有增删改任何浏览器行为,因此兼容性也没有任何问题。不过最终效果呢,只有支持flexbox和CSS3选择符的浏览器才能正常渲染。

个人环境是Window 8 + Chrome v.30,以及小米2 + Chrome v.30,测试经过。

后记

现在CSS很强,纯CSS能够实现不少功能,但愿从此能作出更多有价值的东西。分享这个组件的实现,但愿对你们有用。


首发个人我的网站:[[教程]纯CSS实现多选组件](http://blog.meathill.com/tech...

相关文章
相关标签/搜索