最近工作中做了几件事情都与页面元素定位相关,所以这里将工作中遇到的问题以及解决方法记录在博客里,以便日后查阅。
叠压
有一个任务是做一个列表组件,列表中的每一行都要向上叠压上一行的底边,注意,是叠压,不是接壤。
问题分析:
利用相对定位(position:relative)来制造相对于行(row)的偏移量,使行内元素向上偏移,并叠压上一行的行内元素的底边。
既然是相对定位,那就不能让每一行的定位基准点基于上一行的底边。因为,基准点不会因为上一行元素被CSS搞过之后而同时发生偏移。
举例说明:2个div上下排列,第一个div(class="div1")height为100px,并且向上偏移-10px。第二个div(class="div2")height也是100px,希望叠压到div1的底边10px,所以也设置了top: -10px。如果div1的基准点Y轴坐标=0px,那么,在div1没有发生偏移的情况下,div2的基准点Y轴坐标= div1.top + div1.height,也就是0px + 100px = 100px。现在,div1.top = -10px,即向上偏移10px,按理说,div2的基准点= -10px + 100px = 90px。可惜,现实并非如此。div2的基准点并没有任何改变。所以,div2.top = -10px 依旧无法叠压到div1的底边。只有当div2.top=-20px才可能叠压到div1底边10px处。有人说此处应该让div1的高度增加10px,这样,div2就能叠压到div1了。我做了尝试,发现当div1的高度增加10px后,div2的原始基准点Y轴坐标也跟着+10px。如此,重新套用公式:div2的定位基准点Y轴坐标 = div1的定位基准点Y轴坐标 + div1高度,重新得到div2的定位基准点Y轴坐标为110px。110px-10px的向上偏移量=100px,而div1虽然高度增加到了110px,可是它向上偏移了-10px,div2还是叠压不到div1的底边。
解决思路:
就像问题分析中开头说的那样,解决方法很简单,就是不要让后续元素的定位基准点基于前一个会改变位置的元素。如下图:
这时原先的元素排列结构。这种结构中,每个要向上偏移的元素定位基准点就是上一个也需要变动位置的元素的左下角。这样是不能实现我们的需求的。只要在元素结构上稍加改变,就可以了,见下图,改变后的元素结构:
在原来每个元素内部再添加一个box元素。将偏移设置在这个box元素上。因为每个浅蓝色的box元素都是基于其上层box元素(黑色边框的div)的,而非前面一个需要变动位置的box元素,所以每个浅蓝色的box元素进行偏移时、增加高度时,都不会改变下一个浅蓝色box的定位基准点。而且,每个浅蓝色box元素的高度增加,也不会导致其上层box元素(黑色边框的div)高度改变,因为浅蓝色box元素改变了其top属性后,它就被认为是个浮动元素。一个浮动元素不会撑大包含它的上层box元素。所以第二个黑框div,以及第三个黑框div的定位基准点都不会发生改变。如此一来,我们便可以实现浅蓝色box元素相互叠压的效果了。
实现代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> body { margin: 20px; } .nav-menu-bar { height: 500px; width: 350px; overflow-x: auto; } .menu-item-slot { height: 50px; width: 100%; } .nav-menu-bar .menu-item { background-color: rgba(128,176,224, 1.0); /*rgba()#6699cc;*/ border-radius: 8px 8px 0px 0px; box-shadow: 0px -5px 5px -2px #375e8c; position: relative; top: -8px; height: 58px; /* ------ Be careful ------ */ width: 100%; overflow: hidden; } .menu-item .content { margin-top: 8px; margin-left: 8px; width: 94%; height: 72%; vertical-align: top; overflow-x: hidden; color: #fafafa; } .nav-menu-bar .menu-item-slot:hover { transition: height 0.3s; height: 200px; } .nav-menu-bar .menu-item-slot:first-child:hover { transition: height 0.3s; height: 208px; } .nav-menu-bar .menu-item-slot:first-child .menu-item:hover { transition: height 0.3s; height: 208px; } .nav-menu-bar .menu-item:hover { transition: height 0.3s; height: 208px; } .nav-menu-bar .menu-item-slot:first-child { height: 58px; } .nav-menu-bar .menu-item-slot:first-child .menu-item { box-shadow: none; top: 0px; } .nav-menu-bar .menu-item-slot:last-child .menu-item { border-radius: 8px 8px 8px 8px; } </style> </head> <body> <div class="nav-menu-bar"> <div class="menu-item-slot"> <div class="menu-item"> <div class="content">Created in 1998, its name is derived from the World Wide Web,</div> </div> </div> <div class="menu-item-slot"> <div class="menu-item"> <div class="content">Created in 1998, its name is derived from the World Wide Web,</div> </div> </div> <div class="menu-item-slot"> <div class="menu-item"> <div class="content">Created in 1998, its name is derived from the World Wide Web,</div> </div> </div> <div class="menu-item-slot"> <div class="menu-item"></div> </div> </div> </body> </html>