在HTML中创建一个单列垂直列表非常简单,只需要使用UL和LI标签,或者甚至BR标签即可。但是,如果想要创建一个能够根据可用空间动态调整列数的多列垂直列表,那么就需要一些额外的技巧。本文将介绍一种不依赖于JavaScript或CSS3列特性的创新方法来实现这一需求。
一种针对水平有序列表的解决方案是使用固定宽度的浮动元素。以下是一个示例代码,它展示了如何使用浮动元素来创建一个多列垂直列表:
<div style="float:left;width:120px;">
Archery<br />
Ballooning<br />
Biking
</div>
<div style="float:left;width:120px;">
Bungee Jumping<br />
Coasteering<br />
Dancing
</div>
<div style="float:left;width:120px;">
Driving<br />
Gliding<br />
Motor Racing
</div>
<div style="float:left;width:120px;">
Murder Mystery<br />
Off-Roading<br />
Paintballing
</div>
当有足够的宽度时,这段代码会按照以下方式呈现:
但是,随着可用宽度的减少,列表会根据需要进行换行,尽管水平顺序可能得以保持,但在完全换行之前,垂直顺序并没有得到保持。此外,如果一些浮动的div具有不同的高度,即使水平顺序也可能因为浮动元素被“智能”放置而崩溃。
问题在于无法控制浮动元素的换行顺序。如果能够以某种方式告诉第二个浮动元素在第四个元素换行之前就换行到第一个元素下面,那么就可以解决问题了。然而,总是最后一个浮动元素被换行。
解决方案是使用嵌套的浮动元素,并设置浮动元素的宽度和最小宽度属性,以限制列表块的换行顺序。原型浮动元素现在看起来像这样:
<div style="float:left;width:50%;min-width:110px;">
CONTENT
</div>
这些元素被嵌套在一起,使得每一对相邻的列表项或块,每个都在一个浮动的div中,都被包含在一个上级浮动的div中。
<div style="float:left;width:50%;min-width:110px;">
<div style="float:left;width:50%;min-width:110px;">
Archery<br />
Ballooning<br />
Biking
</div>
<div style="float:left;width:50%;min-width:110px;">
Bungee Jumping<br />
Coasteering<br />
Dancing
</div>
</div>
<div style="float:left;width:50%;min-width:110px;">
<div style="float:left;width:50%;min-width:110px;">
Driving<br />
Gliding<br />
Motor Racing
</div>
<div style="float:left;width:50%;min-width:110px;">
Murder Mystery<br />
Off-Roading<br />
Paintballing
</div>
</div>
这样,得到了以下的DOM结构:
随着可用宽度的减少,百分比宽度导致每列收缩,直到一列达到其最小宽度限制。首先达到这一点的是内部div(红色),因此当通过一个临界阈值时,外部div(蓝色)变得足够窄,以至于它们无法在不换行的情况下容纳内部div,所以看到了以下情况:
如所见,垂直顺序得以保持。
本文的主要目的是展示上述构建自适应多列垂直列表的“技巧”。为了说明服务器端的要求,包括了一个VB.NET的示例方法,它为一个具有8列的列表执行所需的渲染。
Public Function HTMLMultiColumnList(ByVal listitems As List(Of String), ByVal widthpixels As Integer) As String
Dim output As New StringBuilder()
' Calculate the number of items required in each block, and the number of blocks that will have an extra item to cope with the remainder.
Dim itemsperblock As Integer = CInt(Math.Floor((listitems.Count) / 8))
Dim blockswithextraitems As Integer = listitems.Count - (itemsperblock * 8)
' Build the sublists
Dim sublists(8) As List(Of String)
Dim counter As Integer = 0
For i As Integer = 0 To 8 - 1
sublists(i) = New List(Of String)
Dim itemsthisblock As Integer = itemsperblock
If i < blockswithextraitems Then
itemsthisblock += 1
For k As Integer = 0 To itemsthisblock - 1
If counter < listitems.Count Then
sublists(i).Add(listitems(counter))
counter += 1
End If
Next
Next
' Render the sublists with nested float divs
Dim divopen As String = String.Format( _
"", _
widthpixels.ToString)
Dim divclose As String = ""
For i As Integer = 0 To 7
If i Mod 4 = 0 Then
output.Append(divopen)
If i Mod 2 = 0 Then
output.Append(divopen)
output.Append(divopen)
output.Append(String.Join("", sublists(i).ToArray()))
output.Append(divclose)
End If
End If
If i Mod 2 = 1 Then
output.Append(divclose)
End If
If i Mod 4 = 3 Then
output.Append(divclose)
End If
Next
Return output.ToString()
End Function