Smart fluid javascript navigation helper

2019-05-26 16:17发布

I am trying to create a javascript algorithm for an ul menu that stretches out li elements to use the available width (100%).

I was thinking about an algorithm with this flow:

1. calculate the entire available with
2. substract the total elements width to see what's left
3. iterate the elements and substract 1px from the left width and assign 
   it to the smallest li until the iterator runs out of width

Is this a good approach or will this be too laggy because it could mean a few hundred iterations?

EDIT: The comments/answers provided don't hold a good answer yet, as perhaps one or many a elements hold lengthy text and these shouldn't get any extra length. The problem needs an algoritmic solution as only the smallest element can be accounted the left over pixel after each iteration so the menu is efficiently strectched

UPDATE: For those confused this is the way I want it to stretch:

1. A bank has a total bankroll of 100 dollars
2. Jack has a 40% cut, Dennis has 6%, Minny has 1%
3. The bank starts handing out moneyz, 1 dollar each time starting with the
   poorest kid.
4. In the end Jack has 40% while Dennis and Minny have both 30%

Where the cuts stand for the number of characters in a li's child a node

Note: I have read a solution in pure css using table display but that really isn't any good as the underlying <a> elements don't seem to stretch with the parent element that way.

3条回答
三岁会撩人
2楼-- · 2019-05-26 17:05

Add each element to an array (var elems) of objects like { "width": 0, "number": 0, "LIs": [] }, sort the array by the widths, then get the amount of extra space you have. After that (pseudo code follows):

    if(elems.length > 1) {
        while(extraSpaceLeft > 0) {
            leastWidth = elems object with lowest width;
            secondLeastWidth = elems object with second lowest width;
            toAdd = min(abs(leastWidth - secondLeastWidth),extraSpaceLeft);
            toAdd -= toAdd % leastWidth.number;
            extraSpaceLeft -= toAdd;
            leastWidth += toAdd/leastWidth.number;
            if(leastWidth.width === secondLeastWidth) combine the two objects
            else if(leastWidth.width > secondLeastWidth) swap the two objects in the array
        }
    } else { elems[0].width += extraSpaceLeft; }

    set the element width of each elem based on the elems widths

This is really rough pseudo-code, and the logic may not be exactly right, but it should be a lot faster than adding one pixel at a time.

查看更多
Animai°情兽
3楼-- · 2019-05-26 17:09

You could also do it with a pure css rather than a javascript approach by using the display: table property on the ul element and display: table-cell on the li elements :

See this fiddle :

http://jsfiddle.net/ERsrf/

If you want to force the li elements to have the same width, add this property to the ul element :

table-layout:fixed;
查看更多
Explosion°爆炸
4楼-- · 2019-05-26 17:11

This answer may be a bit progressive, as it relies on flexbox doing the heavy lifting. Flexbox is only starting to be supported by IE10, so it's likely to be another 5 years before these techniques can be reliably used in a production environment unless you want to ignore support for IE.

The simple solution is to make the <ul> a row flexbox and flex all the <li> elements equally:

ul {
    display: flex;
    flex-direction: row;
    list-style: none;
    padding: 0;
}

li {
    flex: 1;
}

Of course, in practice you'll need to add browser prefixes, so the CSS will bulk up a bit.

Flexbox fiddle

查看更多
登录 后发表回答