What is a nice way to do leading dots in a table of contents with CSS?
Example:
Link.............Chapter 1
Link.............Chapter 2
Link............开发者_JS百科.Chapter 3
This is the best CSS-only solution I have found for this issue of dot leaders:
http://www.w3.org/Style/Examples/007/leaders.en.html
HTML
<ul class="leaders">
<li><span>Salmon Ravioli</span> <span>7.95</span></li>
<li><span>Fried Calamari</span> <span>8.95</span></li>
<li><span>Almond Prawn Cocktail</span> <span>7.95</span></li>
<li><span>Bruschetta</span> <span>5.25</span></li>
<li><span>Margherita Pizza</span> <span>10.95</span></li>
</ul>
CSS2/CSS3
ul.leaders {
max-width: 40em;
padding: 0;
overflow-x: hidden;
list-style: none
}
ul.leaders li:before {
float: left;
width: 0;
white-space: nowrap;
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
}
ul.leaders span:first-child {
padding-right: 0.33em;
background: white
}
ul.leaders span + span {
float: right;
padding-left: 0.33em;
background: white
}
EXAMPLE: https://codepen.io/ykessler/pen/PoaYGYG
We create the dot leaders with a ‘:before’ pseudo-element attached to the LI elements. The pseudo-element fills the whole width of the list item with dots and the SPANs are put on top. A white background on the SPANs hides the dots behind them and an ‘overflow: hidden’ on the UL ensures the dots do not extend outside the list.
I used an arbitrary 80 dots, which is enough to fill about 38em, hence the maximum width on the list.
Building up on @Nico O‘s answer, there is no need for the un-semantic .dots
element.
.toc li {
display: flex;
}
.toc li .title {
order: 1;
}
.toc li .chapter {
order: 3;
}
.toc li::after {
background-image: radial-gradient(circle, currentcolor 1px, transparent 1.5px);
background-position: bottom;
background-size: 1ex 4.5px;
background-repeat: space no-repeat;
content: "";
flex-grow: 1;
height: 1em;
order: 2;
}
<ul class="toc">
<li>
<span class="title">Foo</span>
<span class="chapter">Chapter 1</span>
</li>
<li>
<span class="title">Bar</span>
<span class="chapter">Chapter 2</span>
</li>
</ul>
We take advantage of the fact that we can order the children of our flex container however we want, and the fact that a pseudo element behaves like a child of where it was defined. The key is the flex-grow
rule. a flex-grow
of 1
while all other siblings have the default 0
will grow to the remaining space even though it has no content.
This will work until the .title
and .chapter
elements together fill all the space. Then the ::after
pseudo element will have a width
of 0
and the dotted border won’t be displayed, even though the .title
and .chapter
will wrap their content. So if you’re sure that won’t happen, and your viewers use modern browsers this might be the optimal solution.
We create the dots using a radial-gradient background. We space repeat the background along the x-axis (background-repeat: space no-repeat
) to prevent any dot from being clipped at the middle and positioned on the bottom. The background size is three times as wide as the dot to create adequate space between them. Also note that we add some blur around the edge of each dot (0.5px) for anti-aliasing.
Kudos to @Denis Savenko for coming up with using radial gradient to create the dots in a different answer.
Taken from this article on Leader Dots with CSS:
The field label is wrapped in a div which has a small image of a dot applied repeatedly in the x direction as a background. This alone would cause the dots to flow under the text. So to nullify that effect, the text itself is then wrapped in a span where the background color is set to match the color of the background of the containing element.
Here is the CSS:
.dots { background: url('dot.gif') repeat-x bottom; } .field { background-color: #FFFFFF; }
To apply this to the example form, you would just use it as:
<div class="dots"> <span class="field">LastName</span> </div>
Here's a image to use for the dot: https://i.stack.imgur.com/otJN0.png
Demo in Stack Snippets
.dots {
background: url('https://i.stack.imgur.com/otJN0.png') repeat-x bottom;
}
.field {
background-color: #FFFFFF;
}
.link {
width: 150px;
display: inline-block;
}
<div class="row">
<div class="dots link">
<span class="field">Link</span>
</div>
<span class="chapter">
Chapter 1
</span>
</div>
<div class="row">
<div class="dots link">
<span class="field">Link</span>
</div>
<span class="chapter">
Chapter 2
</span>
</div>
<div class="row">
<div class="dots link">
<span class="field">Link</span>
</div>
<span class="chapter">
Chapter 3
</span>
</div>
It's possible to combine the classic technique of "leaders" described by the w3c with the joy of flexbox (thanks to @nootrope)
Here is an alternative approach, for Modern Browsers and IE 10+.
DEMO: https://codepen.io/ykessler/pen/gOKYwmm
.article {
display: flex;
}
.article .item,
.article .price {
flex: 1 0 auto;
}
.article .dots {
flex: 0 1 auto;
margin: 0 5px;
/*Allows too long content to be hidden.*/
overflow: hidden;
}
.dots::before {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
}
<div class="article">
<span class="item">Salmon Ravioli</span>
<span class="dots"></span>
<span class="price">7.95</span>
</div>
<div class="article">
<span class="item">Fried Calamari</span>
<span class="dots"></span>
<span class="price">8.95</span>
</div>
<div class="article">
<span class="item">Almond Prawn Cocktail</span>
<span class="dots"></span>
<span class="price">7.95</span>
</div>
<div class="article">
<span class="item">Bruschetta</span>
<span class="dots"></span>
<span class="price">5.25</span>
</div>
<div class="article">
<span class="item">Margherita Pizza</span>
<span class="dots"></span>
<span class="price">10.95</span>
</div>
This is a very flexible way to display leading dots using the current font, and without relying on images.
I mashed-up a couple examples to create what I think is a pretty good solution. Doesn't rely on background color to hide the leader dots. Works on IE8 too.
http://jsfiddle.net/westy808/g0d8x8c5/1/
<ul class="leaders">
<li><span>Item</span><span>12.234</span></li>
<li><span>Another Item</span><span>1,000.25</span></li>
</ul>
ul.leaders li { clear: both; }
ul.leaders li span:first-child {
float: left;
padding: 0 .4em 0 0;
margin: 0;
}
ul.leaders li span + span {
float: right;
padding: 0 0 0 .4em;
margin: 0;
}
ul.leaders li:after {
content: "";
display: block;
overflow: hidden;
height: 1em;
border-bottom: 1px dotted;
}
Many this css hack's don't work with transtarent background or to difficult. You can use modern flex and background-gradient for dotted (it's look more polished, then table dotted). Like this:
.contacts-row {
display: flex;
width: 500px;
}
.dots {
display: block;
background: radial-gradient(circle, rgba(0,0,0,.62) 1px, transparent 1px) repeat-x;
background-size: 20px 28px;
flex-grow: 10;
}
<div class="contacts-row">
<b>E-mail: </b>
<span class="dots"></span>
<span class="text">test@email</span>
</div>
<div class="contacts-row">
<b>Phone: </b>
<span class="dots"></span>
<span class="text">test-phone</span>
</div>
Acutally the W3C has a working draft describing the functionality you are looking for
http://www.w3.org/TR/css3-gcpm/#leaders
Even back in 2005 A List Apart published an article for it. (http://www.alistapart.com/articles/boom) Unfortunately It doesn't seem to work for me and I haven't found much more. But maybe it's worth keeping it in mind that one day in the near future will be possible with CSS only :)
Here is my approach, using element with dotted border-style instead of image or content, make it flex and put it between "Link" and "Chapter".
.toc {
width: 500px;
}
.row {
flex-direction: row;
display: flex;
}
.flex-dots {
border-top-style: dotted;
border-top-width: 1px;
max-height: 1px;
margin-top: 0.5em;
}
.flex-dots-vcenter {
flex-direction: row;
display: flex;
}
[flex] {
flex: 1;
}
<div class="toc">
<div class="row">
<span class="field1">Link 1</span>
<div class="flex-dots-vcenter" flex><span class="flex-dots" flex></span></div>
<span class="field2">Chapter 1</span>
</div>
<div class="row">
<span class="field1">Link 20</span>
<div class="flex-dots-vcenter" flex><span class="flex-dots" flex></span></div>
<span class="field2">Chapter 20</span>
</div>
<div class="row">
<span class="field1">Link 300</span>
<div class="flex-dots-vcenter" flex><span class="flex-dots" flex></span></div>
<span class="field2">Chapter 300</span>
</div>
</div>
Leading dots with CSS grids
.leaders {
list-style: none;
margin: 0;
padding: 0;
}
.leaders li {
width: 100%;
display: grid;
grid-template-columns: auto 1fr auto;
grid-gap: 5px;
justify-items: start;
align-items: center;
justify-content: start;
}
.dots {
border-bottom: 1px dashed #000;
width: 100%;
}
<ul class="leaders">
<li>
<span>Grilled Cheese</span>
<span class="dots"></span>
<span>7.95</span>
</li>
<li>
<span>Wonton Soup</span>
<span class="dots"></span>
<span>8.95</span>
</li>
<li>
<span>Waffles</span>
<span class="dots"></span>
<span>7.95</span>
</li>
<li>
<span>Shrimp Etouffee</span>
<span class="dots"></span>
<span>15.25</span>
</li>
</ul>
Dot leaders can be be done without spans or classes. Here's a responsive solution for HTML tables, modified to center the dot leader vertically:
http://codepen.io/Paulie-D/pen/bpMyBQ
table {
width: 90%;
margin:100px auto;
table-layout:fixed;
border-collapse: collapse;
}
td {
padding:1em 0 0 0;
vertical-align:bottom;
}
td span{
background-color:#fff;
}
td:first-child {
text-align: left;
font-weight: 700;
overflow: hidden;
position: relative;
}
td:first-child::after {
content: '';
position: absolute;
bottom: .4em;
width:1500px;
height:0px ;
margin-left: 1em;
border-bottom:2px dotted grey;
}
td:last-child {
text-align:right;
width:3em;
}
I needed to make it easy for my client to edit a price list on their website, so I created the raw content as a simple html table with two columns. This is super easy to edit in any CMS
Then, building on the previous answers and with the goal of being able to handle data formatted as a table, I used the following. I tried the dotted-bottom-border approach, but that is pretty ugly. So I went with the "dots-as-content" approach.
.toc table {
width: unset;
margin: 0 auto;
margin-top: 1ex;
display: block;
}
.toc table tbody {
display: block;
}
.toc table tr {
display: flex;
}
.toc table tr td {
width: auto !important;
}
.toc table tr td:first-child {
order: 1;
white-space: nowrap;
}
.toc table tr td:last-child {
order: 3;
white-space: nowrap;
}
.toc table tr:after {
flex-grow: 1;
order: 2;
content: ". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . ";
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
}
<div class="toc">
<table>
<tbody>
<tr>
<td>
Product 1
</td>
<td>$123,456</td>
</tr>
<tr>
<td>Product 2</td>
<td>$12,345</td>
</tr>
</tbody>
</table>
</div>
.dots { display: inline-block; width: 325px; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis; }
.dot
{
display: inline-block;
width: 185px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
}
I'm late to the party but we recently had to do this at work and I ended up using a module like this:
http://codepen.io/ryanve/pen/rrBpJq
.dot-leader {
position: relative;
overflow: hidden; /* clip the dots */
}
.dot-leader__left {
position: relative;
display: inline-block;
}
.dot-leader__left::after {
color: gray;
content: ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .";
font-weight: normal;
display: inline-block;
position: absolute;
white-space: nowrap;
margin-left: 5px; /* space left of dots */
}
.dot-leader__right {
background: white; /* cover the dots */
display: inline-block;
position: absolute;
right: 0;
padding-left: 5px; /* space right of dots */
}
with markup that uses li.dot-leader
<ul class="is-no-padding">
<li class="dot-leader">
<span class="dot-leader__left">Pizza</span>
<span class="dot-leader__right">$100</span>
</li>
</ul>
or dl.dot-leader
<dl class="dot-leader">
<dt class="dot-leader__left">Pizza</dt>
<dd class="dot-leader__right">$100</dd>
</dl>
None of the other solutions worked for me. Here is my solution which:
- Respects width of parent divs.
- Doesn't use white background tricks which don't allow for dynamic environments.
- Doesn't use a picture of a dot, so the dot can always match the other font colors.
- Worth both ways and with varying or different values to present
Leader Dots: http://jsfiddle.net/g0d8x8c5/127/
HTML
<div class="main">
<p>Example # 1</p>
<div class="container">
<div class="row">
<span>$150</span><span class="dots"></span><span>remaining credit</span>
</div>
<div class="row">
<span class="spacer"></span><span>30</span><span class="dots"></span><span>remaining days</span>
</div>
</div>
<p>Example # 2</p>
<div class="container">
<div class="row">
<span>Food Item #1</span><span class="dots"></span><span>$12.95</span>
</div>
<div class="row">
<span>Food Item #22</span><span class="dots"></span><span>$7.95</span>
</div>
</div>
</div>
CSS
.main {
/* to prove it respects width of outer containers */
width: 320px;
}
.row {
display: flex;
}
.dots {
/* shorthand - flex: 1 1 auto */
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
}
.dots:before {
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . ";
}
.row span:first-child,
.row span:last-child {
/* shorthand - flex: 0 0 auto */
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
.row span:first-child {
padding-right: 0.33em;
}
.row span:last-child {
padding-left: 0.33em;
}
.spacer {visibility: hidden}
.spacer:before {content: "$"}
Great question and great answers.
I found that many of these working answers broke down when alternating background colours are required for the li
elements. Here is my contribution which emends this.
This is based on nootrope's excellent solution on this page. Their "leaders" class can be re-added if required.
ul{
padding: 0;
overflow-x: hidden;
margin:0 0 24pt;
list-style: none;
list-style-type:none;
}
ul li{
background:white;
}
ul li:nth-child(odd){
background:lightgrey;
}
ul li:before {
float:left;
width:0;
white-space:nowrap;
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . ";
}
ul span:first-child {
padding: 0 0.33em 0 0.8em;
background:inherit;
}
ul span + span{
float: right;
padding: 0 0.8em 0 0.33em;
background:inherit;
}
The main part that makes this work is the careful padding
and background:inherit;
in the ul span
sections.
Note also that adding more of the "filler" dots in ul li:before
allows this to stretch to wider elastic layouts.
Hoping that this helps you.
Just faced this problem for the first time of my >10 years career in frontend. Yay, it's not easy as I thought!
I read all solutions in the web, including this thread, and found nothing I'll like.
Here's my responsive solution using flexbox: https://codepen.io/Grawl/pen/qBXrBWg
I added animated gradient background to the demo and changed text color to blue to demonstrate that my solution is working without background tricks
The trick I used is with hidden colon after left part:
.optionName-colon {
position: relative;
color: transparent;
display: inline-block;
}
.optionName-colon::after {
content: "";
position: absolute;
top: 0.9em;
left: 0;
display: block;
width: 100em;
border-bottom: 1px dotted var(--text-color);
}
<div>
<span class="optionName">
<span class="optionName-label">Name</span>
<span class="optionName-colon">:</span>
</span>
<strong>Value</strong>
</div>
The leaders is pseudo starting on end of left part and ending in overflow.
So, without CSS it renders like this “Name: Value”, and with CSS it renders like “Name ........ Value”.
The simplest solution:
<div style="display: flex; width: 20em;">
<div>Link</div>
<div style="border-bottom: 1px dotted black ; flex-grow: 1;"></div>
<div>Chapter1</div>
</div>
精彩评论