我们经常在手机上看到通讯录列表,这类布局一般有两个显著的效果

  1. 首字母吸顶
  2. 快速定位

下面我们来实现一下

页面结构

这里页面结构很简单,就是两个列表

  1. <div class="con">
  2. <!--联系人列表-->
  3. <div class="contacts" id="contacts">
  4. <dl>A</dt>
  5. <dt>a1</dt>
  6. <dt>a2</dt>
  7. <dl>B</dt>
  8. <dt>b1</dt>
  9. <dt>b2</dt>
  10. ...
  11. </div>
  12. <!--导航列表-->
  13. <div class="index" id="index">
  14. <a>A</a>
  15. <a>B</a>
  16. </div>
  17. </div>

然后加点样式

  1. html,body{
  2. margin: 0;
  3. height: 100%;
  4. padding: 0;
  5. }
  6. dl,dd{
  7. margin: 0;
  8. }
  9. .con{
  10. position: relative;
  11. height: 100%;
  12. overflow-x: hidden;
  13. }
  14. .index{
  15. position: absolute;
  16. right: 0;
  17. top: 0;
  18. bottom: 0;
  19. display: flex;
  20. flex-direction: column;
  21. justify-content: center;
  22. }
  23. .index a{
  24. display: block;
  25. width: 30px;
  26. height: 30px;
  27. text-align: center;
  28. line-height: 30px;
  29. border-radius: 50%;
  30. background: cornflowerblue;
  31. text-decoration: none;
  32. color: #fff;
  33. outline: 0;
  34. margin: 5px;
  35. }
  36. .contacts{
  37. height: 100%;
  38. background: #fff;
  39. overflow: auto;
  40. line-height: 2em;
  41. }
  42. .contacts dt{
  43. background: bisque;
  44. font-size: 1.5rem;
  45. color:cornflowerblue;
  46. height: 2em;
  47. line-height: 2em;
  48. padding: 0 10px;
  49. }
  50. .contacts dd{
  51. padding: 0 10px;
  52. display: block;
  53. cursor: pointer;
  54. }

这样就可以看到布局了

https://codepen.io/xboxyan/pe...

实现吸顶效果

吸顶效果其实很简单,只要用到css中的新属性position:sticky就可以了

粘性定位元素(stickily positioned element)是计算后位置属性为 sticky 的元素。

兼容性还不错,至少在移动端可以放心使用

.contacts dt加上position:sticky

  1. .contacts dt{
  2. /*添加如下属性*/
  3. position: sticky;
  4. top: 0;
  5. }

这样就实现了每个类目吸顶效果

https://codepen.io/xboxyan/pe...

实现快速定位效果

如果不用js,那么可采用href锚点的方式来实现定位

具体做法就是

  1. <a href='#A'></a>
  2. ...
  3. ...
  4. <div id='A'></div>

如果整个页面是可以滚动的,那么只要点击a,那么页面就会迅速跳转到id=A的元素上

现在对我们的页面添加一些herfid

  1. <div class="con">
  2. <!--联系人列表-->
  3. <div class="contacts" id="contacts">
  4. <dl id='A'>A</dt>
  5. <dt>a1</dt>
  6. <dt>a2</dt>
  7. <dl id='B'>B</dt>
  8. <dt>b1</dt>
  9. <dt>b2</dt>
  10. ...
  11. </div>
  12. <!--导航列表-->
  13. <div class="index" id="index">
  14. <a href='#A'>A</a>
  15. <a href='#B'>B</a>
  16. </div>
  17. </div>

https://codepen.io/xboxyan/pe...

点击右侧的导航按钮,页面就可以快速定位了

等等,好像还有些问题,当往回跳转时,发现并没有完全展开,比如像调回A,结果虽然A标签出来了,但是,A下面的列表却没有出来

这是什么问题呢?

经过多次的研究,发现是position:sticky搞的鬼!

当往上定位的时候,我们通过href定位过去,定位的依据是到该元素第一次可见的位置,此时虽然该元素空压机了,但是下面的元素没有展示出来,所以就造成了这样的问题

发现问题就要解决问题

快速定位效果修复

其实我们想要定位的还可以是A下面的第一个列表元素,但是又不能是该元素,因为如果是第一代元素,当跳转的时候就会被上面的A标签遮住。

所以我们在两者之间再插入一个标签,用于定位

如下,添加了<dl class="stikcy-fix"></dt>

  1. <div class="contacts" id="contacts">
  2. <dl>A</dt>
  3. <dl class="stikcy-fix" id='A'></dt>
  4. <dt>a1</dt>
  5. <dt>a2</dt>
  6. <dl>B</dt>
  7. <dl class="stikcy-fix" id='B'></dl>
  8. <dt>b1</dt>
  9. <dt>b2</dt>
  10. ...
  11. </div>

如果直接放在这里肯定会占空间,所以我们把他向上位移,然后设置不可见,使该元素刚好覆盖在原标签位置

如下

  1. .contacts .stikcy-fix{
  2. position: static;
  3. visibility: hidden;
  4. margin-top: -2em;
  5. }

https://codepen.io/xboxyan/pe...

现在看看,是不是完美跳转了?

其他细节

通常我们在选择右侧索引时,页面中间会出现一个大写的字母

这个如果用css实现也比较简单,用到伪元素的content:attr()就可以了,在之前的文章(用纯css实现打星星效果)中也讲到过

具体实现如下

  1. .index a:active:after{
  2. content: attr(data-type);
  3. position: fixed;
  4. left: 50%;
  5. top: 50%;
  6. width: 100px;
  7. height: 100px;
  8. border-radius: 5px;
  9. text-align: center;
  10. line-height: 100px;
  11. font-size: 50px;
  12. transform: translate(-50%,-50%);
  13. background: rgba(0,0,0,.5);
  14. }

这里用到了content: attr(data-type),所以a上面要有一个data-type属性

  1. <!--导航列表-->
  2. <div class="index" id="index">
  3. <a href='#A' data-type='A'>A</a>
  4. <a href='#B' data-type='B'>B</a>
  5. </div>

其次,实际项目中,我们需要用js来生成这些列表

假定我们要求的数据如下

  1. var data = [
  2. {
  3. 'type':'A',
  4. 'user':[
  5. {
  6. name:'a1'
  7. },
  8. {
  9. name:'a2'
  10. },
  11. {
  12. name:'a3'
  13. },
  14. {
  15. name:'a1'
  16. },
  17. {
  18. name:'a2'
  19. },
  20. {
  21. name:'a3'
  22. },
  23. {
  24. name:'a3'
  25. },
  26. {
  27. name:'a1'
  28. },
  29. {
  30. name:'a2'
  31. },
  32. {
  33. name:'a3'
  34. },
  35. ]
  36. },
  37. {
  38. 'type':'B',
  39. 'user':[
  40. {
  41. name:'b1'
  42. },
  43. {
  44. name:'b2'
  45. },
  46. {
  47. name:'b3'
  48. },
  49. {
  50. name:'b1'
  51. },
  52. {
  53. name:'b2'
  54. },
  55. {
  56. name:'b3'
  57. },
  58. {
  59. name:'b3'
  60. },
  61. {
  62. name:'b1'
  63. },
  64. {
  65. name:'b2'
  66. },
  67. {
  68. name:'b3'
  69. },
  70. ]
  71. },
  72. {
  73. 'type':'C',
  74. 'user':[
  75. {
  76. name:'c1'
  77. },
  78. {
  79. name:'c2'
  80. },
  81. {
  82. name:'c3'
  83. },
  84. {
  85. name:'c1'
  86. },
  87. {
  88. name:'c2'
  89. },
  90. {
  91. name:'c3'
  92. },
  93. {
  94. name:'c3'
  95. },
  96. {
  97. name:'c1'
  98. },
  99. {
  100. name:'c2'
  101. },
  102. {
  103. name:'c3'
  104. },
  105. ]
  106. },
  107. {
  108. 'type':'D',
  109. 'user':[
  110. {
  111. name:'d1'
  112. },
  113. {
  114. name:'d2'
  115. },
  116. {
  117. name:'d3'
  118. },
  119. {
  120. name:'d1'
  121. },
  122. {
  123. name:'d2'
  124. },
  125. {
  126. name:'d3'
  127. },
  128. {
  129. name:'d3'
  130. },
  131. {
  132. name:'d1'
  133. },
  134. {
  135. name:'d2'
  136. },
  137. {
  138. name:'d3'
  139. },
  140. ]
  141. },
  142. {
  143. 'type':'E',
  144. 'user':[
  145. {
  146. name:'e1'
  147. },
  148. {
  149. name:'e2'
  150. },
  151. {
  152. name:'e3'
  153. },
  154. {
  155. name:'e1'
  156. },
  157. {
  158. name:'e2'
  159. },
  160. {
  161. name:'e3'
  162. },
  163. {
  164. name:'e3'
  165. },
  166. {
  167. name:'e1'
  168. },
  169. {
  170. name:'e2'
  171. },
  172. {
  173. name:'e3'
  174. },
  175. ]
  176. }
  177. ]

这种格式的数据可以要求后端返回,或者直接前端改造都行

然后对数据进行循环遍历即可

  1. var indexs = document.getElementById('index');
  2. var contacts = document.getElementById('contacts');
  3. var index_html = '';
  4. var contacts_html = '';
  5. data.forEach(el=>{
  6. contacts_html += '<dl><dt>'+el.type+'</dt><dt class="stikcy-fix" id='+el.type+'></dt>';
  7. index_html += '<a href="#'+el.type+'" data-type='+el.type+'>'+el.type+'</a>';
  8. el.user.forEach(d=>{
  9. contacts_html+='<dd>'+d.name+'</dd>';
  10. })
  11. contacts_html+='</dl>'
  12. })
  13. indexs.innerHTML = index_html;
  14. contacts.innerHTML = contacts_html;

https://codepen.io/xboxyan/pe...

这部分js只是生成布局,没有任何功能上的逻辑

一些不足

虽然通过锚点实现列表的快速定位,但是此时浏览器的地址栏会加上#A这样的标识,一不好看,二在使用浏览器默认的返回时会把这些标识全部走一遍,不太方便。

还有一个问题,在滚动列表的时候,没法做到右侧索引当前类别高亮显示,同时右侧索引也不支持滑动快速定位。

这些细节问题也只能通过js来修复了。

不过要是一个简单的小项目,没那么多要求的话,纯css还是能很好的适用的,性能上绝对要比通过js滚动监听强上好多倍,而且引用方便,只要数据生成了就可以直接使用^^

纯css实现手机通讯录的更多相关文章

  1. 演示:纯CSS实现自适应布局表格

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. 纯css实现京东导航菜单

    纯CSS代码实现导航菜单,推荐在chrome预览! 预览请点击这里:mygithub <!doctype html> <html lang="en"> &l ...

  3. 使用纯 CSS 实现响应式的图片显示效果

    有许多方法可以实现页面里图像的响应式显示(Responsive).然而,我碰到的所有方案都使用了JavaScript.这使我疑惑不用 JavaScript 实现图像响应是否可行. 我提出了下面纯CSS ...

  4. 纯CSS(无 JavaScript)实现的响应式图像显示

    有许多方法可以实现web页面里图像的应答.然而,我碰到的所有方案都使用了JavaScript.这使我疑惑不用JavaScript实现图像响应是否可行. 我提出了下面纯CSS的方案. 它是如何工作的呢? ...

  5. 谈谈一些有趣的CSS题目(八)-- 纯CSS的导航栏Tab切换方案

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  6. 一个标签的72变,打造一个纯CSS图标库

    每次要用到图标的时候都会到 icono 去copypaste,但每次用到的时候尺寸都各不一样,总是要调整参数,巨烦.当然你可以会想到用zoom.scale来做缩放,但是这样的缩放会使得线宽也变粗了,不 ...

  7. 利用animation和text-shadow纯CSS实现loading点点点的效果

    经常在网上看到loading状态时的点点点的动态效果,自己也用JS写了一个,思路是使用一个计数参数,然后在需要添加点的元素后面利用setInterval一个一个加点,当计数到3时,把点变为一个--写完 ...

  8. 使用纯CSS实现带箭头的提示框

    爱编程爱分享,原创文章,转载请注明出处,谢谢!http://www.cnblogs.com/fozero/p/6187323.html 1.全部代码 <!DOCTYPE html> < ...

  9. 用纯css改变下拉列表select框的默认样式(不兼容IE10以下)

    在这篇文章里,我将介绍如何不依赖JavaScript用纯css来改变下拉列表框的样式.     事情是这样的,您的设计师团队向您发送一个新的PSD(Photoshop文档),它是一个新的网站的最终设计 ...

随机推荐

  1. python面试题--初级(一)

    一. Python 中有多少种运算符? 这类面试问题可以判断你的 Python 功底,可以举一些实例来回答这类问题. 在 Python 中我们有 7 中运算符: 算术运算符.关系 (比较) 运算符.赋 ...

  2. Mybatis-学习笔记(4)1对1、1对多、多对多

    1.1对1 有2种方式对内嵌Bean设值: 1>关联查询就一条语句.使用association关键字,直接将嵌套对象的映射表的字段赋值内嵌对象. <association property ...

  3. [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)

    [BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆) 题面 给出一个长度为n的序列,选k段长度在L到R之间的区间,一个区间的值等于区间内所有元素之的和,使得k个区间的值之和最大.区 ...

  4. 搜索专题: HDU1429胜利大逃亡

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  5. Vue-cli3 简qian易yi教程

    原文地址 对于没有了解过 vue-cli3 的童鞋,建议先去看看官方的教程: 传送门 新版本的新特性 1. 插件 使用 cli 的插件,可以很快的搭建一个项目的结构.如 axios 的插件 vue-c ...

  6. Codeforces - 1096G - Lucky Tickets - NTT

    https://codeforc.es/contest/1096/problem/G 把数组分成前后两半,那么前半部分的各个值的表示方案的平方的和就是答案. 这些数组好像可以dp出来. 一开始设dp[ ...

  7. css重置的各种版本总结

    个人手机端常用到的: @charset "utf-8"; body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ...

  8. C++ delete仍可访问的问题

    C++ delete和置为NULL 先上一段代码: class Object { public: explicit Object(int num) : m_num(num){} void functi ...

  9. python中字典的美化输出

    一.背景 如果一个字典长度很大,直接print输出则比较难看,我们需要美化输出,可以借鉴json import json beautiful_format = json.dumps(your_dict ...

  10. i3wm 配置刷新生效 和 使用mod快捷打开 ranger 小贴士

    在某处学习到了如何配置i3wm后,对其极感兴趣. 学习到的经验总结: Linux中的各种命令操作其实都要首先查阅 man command  或者  command -h  或者  command -- ...