admin管理员组

文章数量:1405543

I'm trying to get a dynamic amount of elements to show across 5 elements using CSS3 column-count, but when I expand the list item heights on hover, it occasionally causes jumping (an element going to the next column).

You can see the behavior here

I'm assuming it's because column-count uses the height to calculate which item goes where or something...how can we have it work as intended?

If I try to increase the height of <ol>, they bee 4 columns or even 3 columns because the elements fill up the first column, then start the 2nd column, and so on.

I'm trying to get a dynamic amount of elements to show across 5 elements using CSS3 column-count, but when I expand the list item heights on hover, it occasionally causes jumping (an element going to the next column).

You can see the behavior here

I'm assuming it's because column-count uses the height to calculate which item goes where or something...how can we have it work as intended?

If I try to increase the height of <ol>, they bee 4 columns or even 3 columns because the elements fill up the first column, then start the 2nd column, and so on.

Share Improve this question edited Apr 26, 2014 at 23:05 theintellects asked Apr 24, 2014 at 4:33 theintellectstheintellects 1,3703 gold badges16 silver badges31 bronze badges 3
  • 4 I think it is the normal behaviour of columns: if the content of one column overflow it in height, it goes to the next. – ʞᴉɯ Commented Apr 26, 2014 at 23:08
  • do you have to use column-count? It may be easier to do this in, for example, a borderless table. – pennstatephil Commented Apr 26, 2014 at 23:12
  • I found this. Did you try it? JSFIDDLE. – yeshansachithak Commented Apr 27, 2014 at 12:57
Add a ment  | 

3 Answers 3

Reset to default 5 +25

In short, CSS3 columns are not the right solution for what you are trying to do. (If I understand correctly, you want the hovered element to overflow its parent container by going outside its box. However, CSS3 columns are designed such that overflow will continue at the top of the next column, and there's no way that I'm aware of to change this behavior).

I would remend using a different approach to achieve the UI you're after, such as using JQuery to insert wrappers around each column.

However, if you're set on using column-count, you may be able to hack it by doing something like this:

JSFiddle:

http://jsfiddle/p6r9P/

CSS:

ol li:nth-child(5n) {
  padding-bottom: 40px;
}

JQuery:

function togglePadding(li, status) {
    var index = li.index();
    var target = (index % 5 === 4) ? li : li.siblings().eq(index + 3 - (index % 5));
    target.stop(true).animate({
        "padding-bottom": (status === "on") ? "40px" : 0
    });
}

$('a.song').each(function () {
    var origwidth = $(this).width();
    var origheight = $(this).height();
    $(this).hover(function () {
        togglePadding($(this).parent(), "off");
        $(this).stop(true).animate({
            width: origwidth * 2,
            height: origheight * 2
        })
    }, function () {
        $(this).stop(true).animate({
            width: origwidth,
            height: origheight
        });
        togglePadding($(this).parent(), "on");
    });
    $(this).clone(true).attr({
        "class": "song-detail"
    }).css({
        "z-index": 1,
        "background-color": "#CCC"
    }).appendTo('ol').wrap("<li></li>");
});

This is just a rough demo and would need to be cleaned up for production. Basically the strategy is to add a 40px padding "buffer" after every 5th element (the end of a column). When an element is hovered, we find the sibling at the end of its column and animate its padding to 0.

But you can see that if you run your mouse over several elements quickly in succession, sometimes the boxes will shudder as one box temporarily jumps up to the next column. CSS3 column-count REALLY wants to balance those columns.

So I would remend using a different approach, but feel free to play with that and see if you can get it working.

**EDIT: One way to do it without column-count**

Since you're already using JQuery, you could have it wrap every X elements in a <div class="col">, and use those divs as your columns.

JSFiddle: http://jsfiddle/QhTvH/

JQuery:

var container;
var i = 0;
var numCols = 5;
var colCount = Math.ceil($('.songs a').length / numCols);

$('.songs a').each(function () {
    if (i % colCount === 0) {
        container = $('<div class="col"></div>').appendTo(".songs");
    }
    $(this).appendTo(container);
    i++;
});

CSS:

.songs .col {
    max-width: 18%;
    overflow: hidden;
    display: inline-block;
    vertical-align: top;
    margin: 0 5px;
}
.songs a {
    display: block;
    margin: 10px 10px;
    background-color: #EEE;
    width: 200px;
    height: 40px;
    cursor: pointer;
    text-overflow:ellipsis;
    overflow: hidden;
    white-space: nowrap;
}

HTML:

<section class="songs">
  <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">Titanic</a>
  <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">Titanic2</a>
  etc...
</section>

You could as well, find out how much space remains in the last col and fill it to even the columns.

DEMO codepen \0/ DEMO fiddle from yours.

The jQuery added :

var col = 5; // number of columns
var liH =50; // average height ol li, including margins
var nbli = $('ol li').length; // how many do we have ?
var olH = nbli*liH; // total height of ol
var colnbli = Math.ceil(nbli/col); // how many li would it make if each column is fully filled ?
var colH = colnbli*liH; // what's average height of each col 
var ceilOlH= colH*col; //what's total height of columns together
var olH = nbli*liH; // what's real height of ol ?
var fixLiH = ceilOlH - olH; // how much difference do i have ?
var fixcol  =  $('<li style="height:'+fixLiH+'px;width:50%;padding:0; "></li>').appendTo('ol'); // let's see if we can fill the remaining gap

and the CSS

li:hover ~li:last-child {
  margin-top:-10px ;
  display:block
}

To match with animate and avoid jumping lis , add a transition to li for the margin:

ol li {
  display:inline-block;
  margin: 5px 10px;
  transition:0.5s;/* to match jQuery animate */
}

Add/remove <li>s to see if this is what you looked for or reset column-count:5; in both CSS and var col = 5 ;

Have you tried to use the a tag as container? And animate a inner div (or other)

Js Fiddle here: http://jsfiddle/keypaul/Yk2du/41/

html

<ol>
    <li>
        <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">
            <div>Titanic</div>
        </a>
    </li>
    <li>
        <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">
            <div>Titanic</div>
        </a>
    </li>
    <li>
        <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">
            <div>Titanic</div>
        </a>
    </li>
    <li>
        <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">
            <div>Titanic</div>
        </a>
    </li>
    <li>
        <a class="song" data-src="songs/Titanic.mp3" style="width: 187px;">
            <div>Titanic</div>
        </a>
    </li>
</ol>

js

$('a.song').each(function() {
    var origwidth = $(this).width();
    var origheight = $(this).height();
    $(this).hover(
        function() {
            $(this).find('div').stop().animate({width: origwidth * 2, height: origheight * 2});
        }, function() {
            $(this).find('div').stop().animate({width: origwidth, height: origheight});
        });
    $(this).clone(true).attr({"class":"song-detail"}).css({"z-index": 1, "background-color":"#CCC"}).appendTo('ol').wrap("<li></li>");
});

css

ol {
  padding: 0px;
  list-style: decimal-leading-zero inside;
  color: #000;
  font-size: 0.9em;
  -moz-column-count: 5;
  -webkit-column-count: 5;
  column-count: 5;
}

ol li {
  display: inline-block;
  margin: 5px 10px;
}

ol li a {
  background-color: #EEE;
  display: block;
  width: 200px;
  height: 40px;
  cursor: pointer;
  text-overflow:ellipsis;
  white-space: nowrap;
  margin: 0;
    position:relative;
}

ol li a div {
    position:absolute;
    top:0;left:0;
    width:187px;
    height:40px;
    background:red;
}

本文标签: javascriptCSS columncount elements jumping across columnsStack Overflow