使用CSS改变DOM元素顺序

时不时,偶尔,会有一些神奇的需求。在制作RWD页面的时候,偶尔会遇到元素重排序的问题。我之前遇到的情况,是PC版中,导航栏菜单横向排列,搜索框在最右侧;在移动版中,搜索栏跑到菜单的最上面,然后菜单纵向排列。非常典型的菜单处理策略。

| 菜单1 | 菜单2 | ··· | 菜单n | 搜索栏 |

变成

| 搜索栏 |
| 菜单1 |
| 菜单2 |

你准备怎么处理?

一个有原则、有追求、有理想的切图工前端工程师,是打从心底深处瞧不起使用JS移动DOM这种行为的,这样怎么能展现CSS的强大威力。虽然其实大都时候是因为懒…还有对性能问题担忧的迷思……总之信仰问题先放在一边,需求是,使用CSS重新排列DOM的显示顺序,方法比茴香豆的茴字的写法要多些。

方法一:direction

对于一行内的元素来说,direction是首选,兼容好,效果佳,只不过并非它本意。direction原本是用于为那些从右向左书写的语言(使用阿拉伯字母的语言)而准备的…可以让浏览器以不同的方向渲染行内元素。对于我的这个需求来说,代码类似于这样:

1
2
3
4
5
6
7
<div class="container">
<input type="text" placeholder="搜索" />
<ul>
<li>菜单1</li>
<li>菜单2</li>
</ul>
</div>
1
2
3
4
5
6
\* 以下对应的是PC版的CSS *\
.container{ direction: rtl; }
input, ul{
display: inline-block;
direction: ltr;
}

这是个极度简化的示例,direction的默认值是ltr(left to right,从左到右),反过来就是rtl ┑( ̄Д  ̄)┍ 。让元素成为inline-block也是为了让direction得以发挥效力,网上还有一个sample是使用了tabletable-cell,这样可以消除inline-block的幽灵空白,但是table-cell可以应用的属性有限(我到现在都还经常得去查文档)……

方法二:float

这是个新手最爱用的暴力方法,只要让input向右浮动就可以了。前提是需要对宽度加以限制,并且需要做好清除浮动的工作。哎呀但是说到这个[哔~]的[哔~]浮动啊就能洋洋洒洒写出老么长的,比狗屎还长的文章,随便百度一下也是[哔~]多的文章…

我个人不爱用float的主要原因是,在横向垂直对齐方面,除了像素级调整别无他法,也就是说你的css里会充斥着诸如position:relative;top:3px或者margin-top: 3px这样的代码…RWD不就是为了全自动化解放双手吗?!!为什么还要做像素级调整?!Tell me why?!!

方法三: position

position的自由度相对高一些,上面两种方法都是比较有针对性的一行内解决方法,position就可以不受这个限制,无论是relative还是暴力的absolute都可以。无论是纯倒序还是自由顺序也都OK。

使用relative的话:

1
2
3
4
5
6
7
8
9
input,ul{ position: relative; }
input{
width: 25%;
left: 75%;
}
ul{
width: 75%;
left: -25%;
}

使用absolute的话:

1
2
3
4
5
.container{ position: relative; }
input{
position: absolute;
right: 0;
}

垂直方向变换同理,只是如果需要bottom:0的话,需要给父元素加上足够的padding-bottom值,这样才不会出现DOM重叠的情况。

方法四:transform

思路和direction比较接近…先把父元素翻过去,再把子元素翻回来。这种思路在一些斜切的元素上也有所体现;但是其实吧………偶尔它会有定位漂移的情况,重新定位也是挺累人的…同样只能纯倒序。

1
2
.container{ transform: scaleX(-1); }
input,ul{ transform: scaleX(-1); }

scaleX(-1)改成rotateY(180deg)也可以嗯…奇淫技巧~问题大概是兼容性(你懂)。

方法五:display

这是个适用于多行元素的解决方案。display中涉及元素排序的属性不多,唯独table家族。话说Table布局虽然早就远离了我们,但是它带来的布局语法糖还真的是…鉴于这个是在多行场景下使用的解决方法,前面的HTML结构也要稍稍改一下:

1
2
3
4
5
6
7
<div class="container">
<ul>
<li>菜单1</li>
<li>菜单2</li>
</ul>
<input type="text" placeholder="搜索" />
</div>
1
2
3
4
\* 这里是移动版的CSS *\
.container{ display: table; }
input{ display: table-header-group; }
ul{ display: table-footer-group; }

这个方法的缺陷是,最多只能支持3个元素的重排序,不过顺序倒是比较自由。表格组提供的属性有:table-header-grouptable-row-grouptable-footer-group,对应<thead><tbody><tfoot>元素,不过很多人都不知道这仨元素了吧2333……

方法六:flex

如果在欧美地区,我肯定要把这个方法放在第一位…从我3年前第一次听说flex,到现在,我对flex的态度始终不变…什么时候你把兼容性给我搞好了再来找我(敲桌子)。对于一个支持大概是12年开始的“最新版语法”的设备,它写起来差不多是介样:

1
2
3
.container{ display: flex; }
ul{ order: 1; }
input{ order: -1; }

来,Read after me,师~呜~昂~~爽~。顺序自由、位置自由、Everything is 自由!Freedom!

而关于如何区分“最新版”的问题,主要看display

  • 如果它是box或者box-{*},那么这是09年的最古老版语法。
  • 如果它是flexbox,那么这是11年的中间版语法(老外叫它tweener)。
  • 如果它和我这个写的一样,是flex,那么这就是最新版了。

所以关于兼容性处理的问题(扭头)…来下一个话题……

方法七: gird

这是个比较新的方法,我有八成的把握这完全都是被bootstrap的gird system迫害的,MDN上也只有英法两种语言的文档…语法支持从Chrome 57/FF 52开始,然后我默默地看了一下我的Chrome版本…它赫然写着…55.0.2883.87 m……

这一节我们就PASS了。诶嘿。

留个文档的传送门有兴趣的小伙伴请自取→【传送门】

总结

CSS很强大,基本上就是想象x无穷大,不过我们还是应该回归传统,内容的归内容,样式的归样式。在保证HTML代码逻辑性和可读性的前提下,用上述奇淫技巧处理视觉上的各类问题。

大家过年好,我是我家猫。

本部落格采用DISQUS评论系统,如果您无法见到留言框,可前往我的GitHub微博提Issue(留言)。
为您带来了不便我也很尴尬╮(╯_╰)╭