三种方式实现动态元素水平居中
今天临下班的时候隔壁组的同事拉住我跟我讨论一个问题,想要实现的功能如下:
在一个div中有多个水平排列的div,但这些div的宽度不定,并且可以动态增加或者减少。要求这些div组始终居中排列。如图:
看了一下他的代码,是用浮动来做的,但是所有的div都靠左排列。因为块下班了,两个人急急忙忙调试了一会儿没能得到正确的结果,于是下班后想好好研究一下。最终找到了三种实现的方式,写出来跟大家一起讨论讨论。
尝试一:使用Float+margin:auto+js
我就沿着他的float思路继续思考。如果使用float的话,被浮动的元素始终会靠左或者靠右排列,只有将其父元素居中,这些元素才有可能居中放置。不然的话要动态改动他们的margin-left或者margin-right才能实现效果。
那么如何实现父元素居中呢,如果是定宽的元素那好办,直接"margin: 0 auto"就可以实现。但是这里的父元素的大小是不固定的,要随着子元素增减而改变。继续走下去的办法只有用JS去控制父元素的宽度。写了代码进行实验,是可以做到。
1 <!DOCTYPE> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <style type="text/css"> 6 #content{ 7 margin: 0 auto; //父元素水平居中 8 height: 202px; 9 background-color: lightblue; 10 } 11 #content div{ 12 width: 100px; 13 height: 200px; 14 float: left; //子元素向左浮动 15 border: 1px solid blue; 16 background-color:gray; 17 } 18 #toolbar{ 19 margin: 20px auto; 20 text-align: center; 21 } 22 #footer{ 23 clear: both; 24 } 25 </style> 26 27 <script type="text/javascript"> 28 function doLayout(){ 29 var contentDiv = document.getElementById("content"); 30 var children = contentDiv.children; 31 var width = 0; 32 for(var i = 0, l = children.length; i < l; i ++){ 33 width += children[i].offsetWidth; 34 } 35 36 contentDiv.style.width = width+"px"; 37 } 38 function addDiv(){ 39 var contentDiv = document.getElementById("content"); 40 var newDiv = document.createElement("Div"); 41 newDiv.innerHTML = "new added div"; 42 contentDiv.appendChild(newDiv); 43 doLayout(); 44 } 45 </script> 46 47 </head> 48 <body onload="doLayout()"> 49 <div id="page"> 50 <div id="header"><h1>自动水平居中</h1></div> 51 <div id="content"> 52 <div id="div1"> 53 <p>13123</p> 54 <span>13123</span> 55 </div> 56 <div id="div2"> 57 <a href="#">13123</a> 58 <p>13123</p> 59 <span>13123</span> 60 </div> 61 </div> 62 <div id="toolbar"> 63 <input type="button" value="Add Float Div" onClick="addDiv()"/> 64 </div> 65 <div id="footer"> 66 <p>没人关注的页脚</P> 67 </div> 68 </div> 69 </body> 70 </html>
尝试二:使用inline-block
使用JS当然可以解决这样的问题,但到底只使用css能不能实现呢,毕竟这应该属于一个布局的问题。于是想到了前几天看的一篇关于inline-block代替float实现瀑布流的文章,就想试试这里也能否使用inline-block实现这个水平居中的效果。
于是开始查找inline-block的定义和用法:
inline-block:This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.
意思是:inline-block会触发元素呈现成一个行级别的块包含对象,这个对象内部的元素呈现成块级元素,而这个元素本身呈现成行级别的元素。 我的理解是,对与它的父元素以及兄弟元素,它是一个行级别的元素,可以与其他行级别元素同行放置;但对于它内部的元素,它是块级元素,及内部的元素不需要额外的设置来触发BFC。
经过一定的尝试和调试,终于在text-align:center的配合下,基本实现了想要的效果:
1 <!DOCTYPE> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <style type="text/css"> 6 #content{ 7 text-align:center; //内部元素居中 8 height: 200px; 9 background-color: lightblue; 10 } 11 #content div{ 12 width: 100px; 13 height: 200px; 14 display:inline-block; 15 border: 1px solid blue; 16 background-color:gray; 17 } 18 #toolbar{ 19 margin: 20px auto; 20 text-align: center; 21 } 22 #footer{ 23 clear: both; 24 } 25 </style> 26 27 <script type="text/javascript"> 28 function addDiv(){ 29 var contentDiv = document.getElementById("content"); 30 var newDiv = document.createElement("Div"); 31 contentDiv.appendChild(newDiv); 32 } 33 </script> 34 </head> 35 <body> 36 <div id="page"> 37 <div id="header"><h1>自动水平居中</h1></div> 38 39 <div id="content"> 40 <div id="div1"> 41 </div> 42 <div id="div2"> 43 </div> 44 </div> 45 46 <div id="toolbar"> 47 <input type="button" value="Add Float Div" onClick="addDiv()"/> 48 </div> 49 <div id="footer"> 50 <p>没人关注的页脚</P> 51 </div> 52 </div> 53 </body> 54 </html>
但是在尝试放入了一些块级元素到各个div中的时候,发现当内部元素高度不一样的时候,各个块的排列就不能对齐了:
这可能就是内部的块级元素产生了换行的原因吧,但是也不能确定,有时间仔细研究一下,也希望知道的高手能指点一下。
但是我还是找到了解决的办法,就是vertical-align,在设置成top之后,每个元素内部都从顶端开始排布,所以也就能对齐了。
1 <!DOCTYPE> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <style type="text/css"> 6 #content{ 7 text-align:center; 8 height: 202px; 9 background-color: lightblue; 10 } 11 #content div{ 12 width: 100px; 13 height: 200px; 14 display:inline-block; 15 border: 1px solid blue; 16 vertical-align: top; 17 background-color:gray; 18 } 19 #toolbar{ 20 margin: 20px auto; 21 text-align: center; 22 } 23 #footer{ 24 clear: both; 25 } 26 </style> 27 28 <script type="text/javascript"> 29 function addDiv(){ 30 var contentDiv = document.getElementById("content"); 31 var newDiv = document.createElement("Div"); 32 newDiv.innerHTML = "new added div"; 33 contentDiv.appendChild(newDiv); 34 } 35 </script> 36 </head> 37 <body> 38 <div id="page"> 39 <div id="header"><h1>自动水平居中</h1></div> 40 41 <div id="content"> 42 <div id="div1"> 43 <p>13123</p> 44 <span>13123</span> 45 </div> 46 <div id="div2"> 47 <a href="#">13123</a> 48 <p>13123</p> 49 <span>13123</span> 50 </div> 51 </div> 52 53 <div id="toolbar"> 54 <input type="button" value="Add Float Div" onClick="addDiv()"/> 55 </div> 56 <div id="footer"> 57 <p>没人关注的页脚</P> 58 </div> 59 </div> 60 </body> 61 </html>
至此,使用inline-block顺利解决了问题。但是在查阅资料的时候都说inline-block有浏览器兼容的问题,自己在chrome,firefox和IE10试了之后都没发现问题。也算是一种解决方案吧。
尝试三:使用position:relative实现
在查阅水平居中的过程当中,还看到有同学说可以使用position:relative加上float来实现,于是也尝试了一下。确实也是可以的:
1 <!DOCTYPE> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <style type="text/css"> 6 #content{ 7 float: left; 8 position:relative; 9 left: 50%;//父元素相对左50% 10 height: 202px; 11 } 12 #content div{ 13 float: left; 14 position:relative; 15 right: 50%;//子元素相对右50% 这里写成left:-50%也能工作 16 width: 100px; 17 height: 200px; 18 border: 1px solid blue; 19 background-color:gray; 20 } 21 #toolbar{ 22 clear:both; 23 margin: 20px auto; 24 text-align: center; 25 } 26 #footer{ 27 clear: both; 28 } 29 </style> 30 31 <script type="text/javascript"> 32 function addDiv(){ 33 var contentDiv = document.getElementById("content"); 34 var newDiv = document.createElement("Div"); 35 newDiv.innerHTML = "new added div"; 36 contentDiv.appendChild(newDiv); 37 } 38 </script> 39 </head> 40 <body> 41 <div id="page"> 42 <div id="header"><h1>自动水平居中</h1></div> 43 44 <div id="content"> 45 <div id="div1"> 46 <p>13123</p> 47 <span>13123</span> 48 </div> 49 <div id="div2"> 50 <a href="#">13123</a> 51 <p>13123</p> 52 <span>13123</span> 53 </div> 54 </div> 55 56 <div id="toolbar"> 57 <input type="button" value="Add Float Div" onClick="addDiv()"/> 58 </div> 59 <div id="footer"> 60 <p>没人关注的页脚</P> 61 </div> 62 </div> 63 </body> 64 </html>
这里先普及一下polistion:relative的概念:
relative : 对象不可层叠,但将依据left,right,top,bottom等属性在正常文档流中偏移位置。
这个解释与一般的理解有点偏差,我最开始的时候也是理解成相对定位,以为是相对父节点的,但实际上相对的是正常情况下自己的位置。所以也就很容易解释,代码中的父节点相对其父节点向右移动50%后它的开始就正好在正中间,然后子元素都相对自身向左偏移50%,自然也就能将自己的中心放在整体的中间。也就实现了居中排放的效果。
至此,这个自动水平居中的问题也算完美解决了。技术这种东西,都是取之于民用之于民,希望能够给大家一些帮助,也希望能跟大家一起探讨更多的问题。