最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Display list in several columns and keep the number of elements per column equal when their heights are different -

programmeradmin4浏览0评论

I simply need to have an unordered list displayed in 3 columns, but without vertical alignment.

Is there a way to remove the gap between the list element no. 2 and no. 5 in this example?

I already tried flexbox, float, table, column and grid layout and can't figure it out, although it looks simple at first glance.

A JS solution would also be OK, but i can't alter the HTML output. And i don't know the item's heights, so i don't need a solution with fixed pixel values.

If there is a solution for this, the following sorting would also be a nice gimmick, but i think i may figure that one out after i get a starting point:

1 3 5
2 4

ul { 
  list-style-type: none; 
  padding: 0;
  color: white; 
  text-align:center;
}

.small { 
  height: 30px
}

.large {
  height: 200px
}

li {
  background:red;
}

li:nth-child(2n) { 
  background:blue;
}

ul {
  display: grid; 
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
<ul>
  <li class="large">1</li>
  <li class="small">2</li>
  <li class="small">3</li>
  <li class="small">4</li>
  <li class="small">5</li>
</ul>

I simply need to have an unordered list displayed in 3 columns, but without vertical alignment.

Is there a way to remove the gap between the list element no. 2 and no. 5 in this example?

I already tried flexbox, float, table, column and grid layout and can't figure it out, although it looks simple at first glance.

A JS solution would also be OK, but i can't alter the HTML output. And i don't know the item's heights, so i don't need a solution with fixed pixel values.

If there is a solution for this, the following sorting would also be a nice gimmick, but i think i may figure that one out after i get a starting point:

1 3 5
2 4

ul { 
  list-style-type: none; 
  padding: 0;
  color: white; 
  text-align:center;
}

.small { 
  height: 30px
}

.large {
  height: 200px
}

li {
  background:red;
}

li:nth-child(2n) { 
  background:blue;
}

ul {
  display: grid; 
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
<ul>
  <li class="large">1</li>
  <li class="small">2</li>
  <li class="small">3</li>
  <li class="small">4</li>
  <li class="small">5</li>
</ul>

Desired result:

Note: This is NOT a question about a masonry layout with only CSS. In the linked answer, the item no. 4 (in the first column) would float into the second row, as a masonry layout is trying to have equal heights for the resulting columns. The question here is about to have the same amount of items in every column (until there are no items left). I already tried the solution over there and it didn't work unsurprisingly.

Share Improve this question edited Mar 15 at 20:57 Spectric 32.4k6 gold badges29 silver badges54 bronze badges asked Mar 14 at 22:23 SetylSetyl 6908 silver badges11 bronze badges 0
Add a comment  | 

2 Answers 2

Reset to default 1

You can use CSS columns by setting column-count: 3; avoiding breaks inside list items, and always breaking after even items:

ul {
  column-count: 3;

  list-style-type: none;
  padding: 0;
  color: white;
  text-align: center;
}

.small {
  height: 30px;
}

.large {
  height: 200px;
}

li {
  break-inside: avoid-column;

  background: red;
}

li:nth-child(2n) {
  break-after: column;

  background: blue;
}
<ul>
  <li class="large">1</li>
  <li class="small">2</li>
  <li class="small">3</li>
  <li class="small">4</li>
  <li class="small">5</li>
</ul>

Use Javascript to split the list items into three new lists. Then add the three new lists as children of the original list.

This is our starting point: a single list

<ul id="ul1">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>

This is the goal: three lists

<ul id="ul1">
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <ul>
    <li>5</li>
    <li>6</li>
    <li>7</li>
  </ul>
  <ul>
    <li>8</li>
    <li>9</li>
    <li>10</li>
  </ul>
</ul>

Here is a working example, which, as an added bonus, determines a random height for each item.

const getRandomIntInclusive = (min, max) => {
  const minCeiled = Math.ceil(min)
  const maxFloored = Math.floor(max)
  return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled)
}

const ul1 = document.getElementById('ul1')
const items = Array.from(ul1.children)
const columns = []
const itemColumnIndex = []

/* how many items per column to make all columns the same length, and how many items left over? */
const itemsPerColumn = Math.floor(items.length / 3)
const remainder = items.length % 3

// construct three lists, one for each column
for (let i = 0; i < 3; i++) {
  columns.push(document.createElement('ul'))
  // how many items should be in this column?
  const itemsThisColumn = itemsPerColumn + (i < remainder ? 1 : 0)
  // add n items to the array containing the index of this column
  for (let j = 0; j < itemsThisColumn; j++) {
    itemColumnIndex.push(i)
  }
}

// process all items
for (let i = 0; i < items.length; i++) {
  // assign a random height
  items[i].style.height = getRandomIntInclusive(30,100) + 'px'
  // move the item into the appropriate list
  columns[itemColumnIndex[i]].appendChild(items[i])
}

// add the three lists as children of the original list 
columns.forEach(c => {
  ul1.appendChild(c)
})
ul {
  list-style-type: none; 
  margin: 0;
  padding: 0;
  color: white; 
}

#ul1 { 
  display: grid; 
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1em;
  
  li {
    display: flex;
    justify-content: center;
    align-items: center;
    background:red;
  }

  li:nth-child(2n) { 
    background:blue;
  }
}
<ul id="ul1">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
</ul>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论