CSS: Last element on line
Solution 1
Interesting question! Here's what I consider a "low-tech" solution with jQuery that does the trick:
$(function() {
var lastElement = false;
$("ul > li").each(function() {
if (lastElement && lastElement.offset().top != $(this).offset().top) {
lastElement.addClass("nobullet");
}
lastElement = $(this);
}).last().addClass("nobullet");
});
The algorithm is not hard to follow, but here's the idea: iterate over the elements, taking advantage that they all have the same properties (size, margin, display inline etc) that affect their position when the browser computes layout. Compare the vertical offset of each item with that of the previous one; if they differ, the previous one must have been at the end of the line so mark it for special treatment. Finally, mark the very last item in the set for special treatment as well, since by definition it is the last item in the line on which it appears.
IMHO the fact that this is a Javascript-based solution (can it be done without, I wonder?) is no problem at all here, as even if the script does not run there is only going to be an extremely slight visual degradation of your webpage.
Solution 2
I am facing the same situation, and doing this in a responsive design. here is my CSS only solution.
div {
overflow: hidden;
margin: 1em;
}
div ul {
list-style: none;
padding: 0;
margin-left: -4px;
}
div ul li {
display: inline;
white-space: nowrap;
}
div ul li:before {
content: " \00b7";
}
<div>
<ul>
<li>item 1</li>
<li>item B</li>
<li>item 3</li>
<li>item IV</li>
<li>the long item</li>
<li>item 6</li>
<li>item 7</li>
<li>item awesome</li>
<li>give me your money</li>
<li>contact</li>
<li>menu item more</li>
<li>CSS is awesome</li>
<li>CSS3 is great</li>
<li>more</li>
<li>last item</li>
</ul>
</div>
Solution 3
I actually found a flaw in Jon's solution: In the rare situation where two (or more) li
s would fit on a row, but the two li
s plus the bullet wouldn't fit, they would render next to each other sans bullet. (Having the bullet there originally would cause the two li
s to be on separate lines, applying the class nobullet
and reducing the spacing, moving the second li
up a line.)
Here's an example of the flaw: http://jsfiddle.net/W2ULx/61/ (Notice in the first line, the last two li
s render with no bullet between them. The only thing changed from the original fiddle is the width of the ul
to force the issue.)
The simple solution I found was to change in the CSS
ul li.nobullet:after { content: none; }
to
ul li.nobullet:after { color: transparent; }
so that instead of removing the spacing, just makes it invisible. Anything that would have broken to a new line still will break to a new line, instead of being bumped up a line by the removed bullet.
Solution 4
I wanted a version that would be visually centered and would also deal with the re-layout bug Randall elegantly handled. This solution also adds a middle dot and space to the first item on each line, which counter-balances the middle dot and space on the end of each line. You might wish to remove this if you left-align your menu.
I also switched to offset().left in the code because Firefox wasn't working with offset().top.
The code is below, but here is a link so you can more easily see it working. http://kpao.typepad.com/files/middle-dot-separated-list-v2.html
<html>
<head>
<title>Wildlife Conservation Network programs menu</title>
<style>
body, div, p, div, li, a {font-family:"Avenir Next","Segoe UI",sans-serif; font-size:15px;}
a {color:royalblue; text-decoration:none;}
a:hover, a:active {text-decoration:underline;}
ul.menu {background-color:#f2f2f2; text-align:center; padding:1em 0; margin:0;}
ul li {display:inline; white-space:nowrap;}
ul li::before {content:""; padding-right:3px;}
ul li::after {content:"\00a0\00b7"; padding-left:3px;}
ul li.firstdot::before, ul li:first-child::before {content:"\00b7\00a0"; color:transparent;}
ul li.lastdot::after, ul li:last-child::after {color:transparent;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
function midDotIt() {
var lastElement = false;
$("ul li").each(function() {
if (lastElement && lastElement.offset().left > $(this).offset().left) {
$(lastElement).addClass("lastdot");
$(this).addClass("firstdot");
} else if (lastElement) {
$(lastElement).removeClass("lastdot");
$(this).removeClass("firstdot");
}
lastElement = $(this);
});
}
</script>
</head>
<body onload="midDotIt();" onresize="midDotIt();">
<ul class="menu">
<li><a href="https://wildnet.org/wildlife-programs/african-wild-dog">African Wild Dog</a></li>
<li><a href="https://wildnet.org/wildlife-programs/andean-cat">Andean Cat</a></li>
<li><a href="https://wildnet.org/wildlife-programs/cheetah-botswana">Cheetah - Botswana</a></li>
<li><a href="https://wildnet.org/wildlife-programs/cheetah-namibia">Cheetah - Namibia</a></li>
<li><a href="https://wildnet.org/wildlife-programs/cotton-top-tamarin">Cotton-Top Tamarin</a></li>
<li><a href="https://wildnet.org/wildlife-programs/elephant">Elephant</a></li>
<li><a href="https://wildnet.org/wildlife-programs/elephant-crisis-fund">Elephant Crisis Fund</a></li>
<li><a href="https://wildnet.org/wildlife-programs/ethiopian-wolf">Ethiopian Wolf</a></li>
<li><a href="https://wildnet.org/wildlife-programs/grevys-zebra">Grevy's Zebra</a></li>
<li><a href="https://wildnet.org/wildlife-programs/lion-ewaso">Lion - Ewaso</a></li>
<li><a href="https://wildnet.org/wildlife-programs/lion-niassa-0">Lion - Niassa</a></li>
<li><a href="https://wildnet.org/wildlife-programs/lion-recovery-fund">Lion Recovery Fund</a></li>
<li><a href="https://wildnet.org/wildlife-programs/okapi">Okapi</a></li>
<li><a href="https://wildnet.org/wildlife-programs/penguin">Penguin</a></li>
<li><a href="https://wildnet.org/wildlife-programs/saiga-antelope">Saiga Antelope</a></li>
<li><a href="https://wildnet.org/wildlife-programs/sharks-rays">Sharks and Rays</a></li>
<li><a href="https://wildnet.org/wildlife-programs/small-wild-cats">Small Wild Cats</a></li>
<li><a href="https://wildnet.org/wildlife-programs/snow-leopard">Snow Leopard</a></li>
<li><a href="https://wildnet.org/wildlife-programs/spectacled-bear">Spectacled Bear</a></li>
<li><a href="https://wildnet.org/what-we-do/scholarships">Scholarship Program</a></li>
</ul>
</body>
</html>
benesch
Updated on June 01, 2022Comments
-
benesch almost 2 years
I've got an unordered [inline] list of links that wraps across two lines:
<ul> <li><a href="http://google.com">Harvard Medical School</a></li> <li><a href="http://google.com">Harvard College</a></li> ... </ul>
I add the dot separator via a CSS pseudo-element:
#widget-links li { display: inline; } #widget-links li:after { content: " \00b7"; }
Unfortunately, the separator appears after the last element on each line. With just one line, I'd simply grab
:last-child
and remove the psuedo-element.Any nifty tricks to hide that last dot with more than one line? I'm open to weird CSS, or JavaScript if absolutely necessary.
-
benesch about 12 yearsAgreed: this is beautiful. Thank you much, Jon!
-
mhenry1384 over 7 yearsFor responsive: function removeSeparatorAtEndOfLine() { var lastElement = false; // stackoverflow.com/a/9847817/24267 $(".FiveNumbers .Columns .Column").each(function () { if (lastElement) { if (lastElement.offset().top !== $(this).offset().top) { lastElement.addClass("LastInLine"); } else { lastElement.removeClass("LastInLine"); } } lastElement = $(this); }).last().addClass("LastInLine"); } $(removeSeparatorAtEndOfLine); $(window).resize(removeSeparatorAtEndOfLine);
-
Dave C over 6 yearsIt's definitely useful and clever, but unfortunately only works for left aligned lists. Also to make sure there is equal space between the dot, I recommend: div ul li:before {content: "\00b7\00a0";} This gives more wiggle room to the negative margin for fonts with different metrics. I used div ul {margin-left: -.4em;} which I found will work with most fonts.