I need to implement dot leaders after first line of text using CSS to use it over texture/image background.
Expected behaviour:
I saw a few implementation of dot leaders over the internet. They all use one of the techniques below:
<div class=item1>
<span class=text1>
Text
</span>
<span class=price1>
$100
</span>
</div>
.item1 {
display: flex;
}
.text1 {
flex-grow: 1;
position: relative;
overflow: hidden;
}
.text1::after {
content: '';
position: absolute;
bottom: 0;
border-bottom: 1px dotted grey;
width: 100%;
}
.price1 {
align-self: flex-end;
}
<div class=item2>
<span class=text2>
<span class=bg2>
Text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
.item2 {
display: flex;
justify-content: space-between;
position: relative;
mix-blend-mode: darken;
}
.item2::before {
content: '';
position: absolute;
top: 1em;
left: 0;
right: 0;
border-bottom: 1px grey dotted;
}
.bg2 {
background: white;
position: relative;
z-index: 1;
}
<div class=item3>
<span class=text3>
Text
</span>
<span class=dots3></span>
<span class=price3>
$100
</span>
</div>
.item3 {
display: flex;
align-items: flex-start;
}
.dots3 {
flex-grow: 1;
border-bottom: 1px dotted grey;
min-width: 10px;
height: 1em;
}
They are all shown here: https://jsfiddle.net/rzmLg4yu/62/
Each of these techniques has its own pitfalls in my case.
Is there more solutions to this case?
But what if the text before the dot leader is so long that it wraps over several lines? The row of dots has to be lower in that case, not behind the first line of the text, but behind the last. Without the proposed new features for CSS level 3 we cannot solve that in the general case, but we can still make it look reasonable in simple cases.
The CSS rules are the same as before, except that we now use the selector 'ul.leaders li:after' instead of 'ul.leaders li:before'. And there is one extra subtlety: because the dots are now logically after the last text, they will be drawn over, instead of under it.
The row of dots has to be lower in that case, not behind the first line of the text, but behind the last. Without the proposed new features for CSS level 3 we cannot solve that in the general case, but we can still make it look reasonable in simple cases. We have to assume then that the text after the leader is short enough that it won't wrap.
The CSS rules are the same as before, except that we now use the selector 'ul.leaders li:after' instead of 'ul.leaders li:before'. And there is one extra subtlety: because the dots are now logically after the last text, they will be drawn over, instead of under it.
Technic 3 can be improved to get rid of the wrapping gaps:
body {
color: grey;
}
.width {
width: 300px;
padding: 5px;
resize: horizontal;
overflow: hidden;
abackground: linear-gradient(45deg, yellow, black);
background-repeat: repeat-x;
background-size: 200px 100%;
}
.item3 {
display: flex;
align-items: flex-start;
}
.dots3 {
flex-grow: 1;
border-bottom: 1px dotted grey;
min-width: 10px;
height: 1em;
}
.text3 {
padding-right: 0px;
text-align: justify; /* <--- */
}
<div class=width>
<div class=item3>
<span class=text3>
3 Text text
</span>
<span class=dots3></span>
<span class=price3>
$100
</span>
</div>
<div class=item3>
<span class=text3>3 Text text text text text text text text text text text text text text text text</span>
<span class=dots3></span>
<span class=price3>
$100
</span>
</div>
text-align: justify;
will space the words evenly.
I think your issue with the second technic is because of white background color right?
because of .bg2 {background: white;...}
?
Otherwise, you should've used mix-blend-mode: lighten;
to demonstrate the issue:
body {
color: grey;
padding: 20px;
}
.width {
width: 230px;
padding: 5px;
resize: horizontal;
overflow: auto;
background: linear-gradient(90deg, yellow, black);
background-repeat: repeat-x;
background-size: 200px 100%;
}
div>div {
background-color: white;
border: 2px solid green;
}
.simpleDiv1 {
mix-blend-mode: darken;
}
.simpleDiv2 {
margin-top: 20px;
mix-blend-mode: lighten;
}
<div class=width>
<div class=simpleDiv1>darken blend. Simple text without any styles and stuff.</div>
<div class=simpleDiv2>lighten blend. Simple text without any styles and stuff.</div>
</div>
If you use darken blend then any normal text will disappear with that background, let alone dot leaders.
Technic two without background white:
body {
color: grey;
padding: 20px;
}
.width {
width: 230px;
padding: 5px;
resize: horizontal;
overflow: hidden;
abackground: linear-gradient(90deg, yellow, black);
background-repeat: repeat-x;
background-size: 200px 100%;
}
.item2 {
display: flex;
justify-content: space-between;
position: relative;
mix-blend-mode: darken;
text-decoration-line: underline;
text-decoration-style: solid;
text-decoration-color: white;
text-decoration-thickness: 2px;
}
.item2::before {
content: '\00a0';
height: calc(1em - 0.5px);
position: absolute;
top: 0;
left: 0;
right: 0;
border-bottom: 1px dotted gray;
z-index: -1;
}
<div class=width>
<div class=item2>
<span class=text2>
2 Text text
</span>
<span class=price2>
$100
</span>
</div>
<div class=item2>
<span class=text2>
2 Text text text text text text text text text text text text text text text text
</span>
<span class=price2>
$100
</span>
</div>
</div>
Technic three can be improved if we are willing to break words while wrapping:
body {
color: grey;
}
.width {
width: 300px;
padding: 5px;
resize: horizontal;
overflow: hidden;
abackground: linear-gradient(45deg, yellow, black);
background-repeat: repeat-x;
background-size: 200px 100%;
}
.item3 {
display: flex;
align-items: flex-start;
}
.dots3 {
flex-grow: 1;
border-bottom: 1px dotted grey;
min-width: 10px;
height: 1em;
}
.text3 {
padding-right: 0px;
word-break: break-all;
}
<div class=width>
<div class=item3>
<span class=text3>
3 Text text
</span>
<span class=dots3></span>
<span class=price3>
$100
</span>
</div>
<div class=item3>
<span class=text3>3 Text text text text text text text text text text text text text text text text</span>
<span class=dots3></span>
<span class=price3>
$100
</span>
</div>
word-break: break-all
. If your font-size is 1em, then this way the maximum gap will be less than 1em, because browser won't be able to fit a letter less than 1em space.
I suggest using the value multiply
for the mix-blend-mode
property. In the case of dark text, it gives a sharper result even on a gradient background. Look the first demo.
We can simplify layout of the second technique with a help of the ::first-line
pseudo-element. It can be used with "only a small subset of CSS properties", but this subset contains all background-related properties.
I think this also gives a better result against mix-blend-mode: darken
. Compare the second and third demo.
And the gap
property helps to set the minimum gap between the text and the price.
There are three demos in the snippet below:
mix-blend-mode: multiply
in action.mix-blend-mode: darken
on two layouts - with an extra bg
block and with the ::first-line
pseudo-element.https://codepen.io/glebkema/pen/NWapXPQ?editors=1100
body {
color: grey;
}
.width {
width: 300px;
padding: 5px;
resize: horizontal;
overflow: hidden;
background: linear-gradient(45deg, yellow, black);
background-repeat: repeat-x;
background-size: 200px 100%;
}
.item2 {
display: flex;
justify-content: space-between;
position: relative;
mix-blend-mode: darken;
gap: 10px; /* 3) */
}
.multiply .item2 {
mix-blend-mode: multiply; /* 1) */
}
.item2::before {
content: '';
position: absolute;
top: 1em;
left: 0;
right: 0;
border-bottom: 1px grey dotted;
}
.bg2 {
background: white;
position: relative;
z-index: 1;
}
.price4,
.text4 {
z-index: 1;
}
.price4,
.text4::first-line { /* 2) */
background: white;
}
<h4><code>mix-blend-mode: multiply;</code></h4>
<div class="width multiply">
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text text text text text text text text text text text text text text text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
<br />
<div class=item2>
<span class=text4>
4 Text text
</span>
<span class=price4>
$100
</span>
</div>
<div class=item2>
<span class=text4>
4 Text text text text text text text text text text text text text text text text text
</span>
<span class=price4>
$100
</span>
</div>
</div>
<h4><code>mix-blend-mode: darken;</code> (2nd method before 4th)</h4>
<div class="width">
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text text text text text text text text text text text text text text text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
<br />
<div class=item2>
<span class=text4>
4 Text text
</span>
<span class=price4>
$100
</span>
</div>
<div class=item2>
<span class=text4>
4 Text text text text text text text text text text text text text text text text text
</span>
<span class=price4>
$100
</span>
</div>
</div>
<h4><code>mix-blend-mode: darken;</code> (4th method before 2nd)</h4>
<div class="width">
<div class=item2>
<span class=text4>
4 Text text
</span>
<span class=price4>
$100
</span>
</div>
<div class=item2>
<span class=text4>
4 Text text text text text text text text text text text text text text text text text
</span>
<span class=price4>
$100
</span>
</div>
<br />
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
<div class=item2>
<span class=text2>
<span class=bg2>
2 Text text text text text text text text text text text text text text text text text
</span>
</span>
<span class=price2>
<span class=bg2>
$100
</span>
</span>
</div>
</div>
Even the W3C official source has some disparity. You may see inconsistent rendering or poor support for invented features (such as non-monospace/preformatted, lead zero padding, varied currency widths).
Using a shim or Web Component such as Leader-Line would be advisable. I would recommend you experiment with dash-animation to increase visibility on busy backgrounds (at the expense of annoying someone with a busy leader).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With