5

I want to emphasise the last 3 characters of a string, example:

123456789

Easy to wrap the last three with <strong> or <span class="">, but I was wondering if it could be done with CSS only? So the html would be something like:

<span class="mytext">123456789</span>

With the emphasis added in CSS mytext class?

Tony H
  • 337
  • 2
  • 9
  • 2
    you can style first letter, but not a generic substring – cloned Apr 10 '20 at 08:01
  • Something simillar: https://stackoverflow.com/questions/23569441/is-it-possible-to-apply-css-to-half-of-a-character – Manos Kounelakis Apr 10 '20 at 08:01
  • 1
    No, it cannot be done without wrapping those characters in an additional element. Even in the answer given you have an additional wrapping element `::after`. – connexo Apr 10 '20 at 08:13
  • Tell us what's the purpose of doing that, maybe we can help – Saadi Toumi Fouad Apr 10 '20 at 08:32
  • @SaymoinSam it is to make the last three characters stand out, as they are what the user is usually trying to read. – Tony H Apr 11 '20 at 09:54
  • @connexo Yes, it would seem jquery or server side separation of the strings will be the easiest way to go sadly. I knew of the `inital-letter` feature alluded to by @cloned, so figured there may be a way of doing it in CSS. – Tony H Apr 11 '20 at 09:57

3 Answers3

2

Here is a crazy idea using filter and SVG to simulate a bold effect on the last 3 digits.

Works only on chrome

.mytext {
  display: inline-block;
  margin: 10px;
  font-size: 50px;
  font-family: monospace;
  position: relative;
  filter: drop-shadow(0px 0px 0px black);
}

.mytext:after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 3ch;
  backdrop-filter: url(#shadow);
}
<span class="mytext">123456789</span>

<span class="mytext" style="font-size:25px">123456789568</span>
<span class="mytext" style="font-size:25px">123568</span>



<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
  <defs>
  <filter id="shadow" color-interpolation-filters="sRGB" x="-50%" y="-50%" height="200%" width="200%">
<!-- Take source alpha, offset it by angle/distance and blur it by size -->
<feOffset id="offset" in="SourceAlpha" dx="0" dy="0" result="SA-offset"/>
<feGaussianBlur id="blur" in="SA-offset" stdDeviation="1" result="SA-o-blur"/>
<!-- Apply a contour by using a color curve transform on the alpha and clipping the result to the input -->

<feComponentTransfer in="SA-o-blur" result="SA-o-b-contIN">
  <feFuncA id="contour" type="table" tableValues="0 1 0.65 0.5 0.55 0.6 0.65 0.55 0.4 0.1 0"/>
</feComponentTransfer>

<feComposite operator="in" in="SA-o-blur" in2="SA-o-b-contIN" result="SA-o-b-cont"/>

<!-- Adjust the spread by multiplying alpha by a constant factor --> <feComponentTransfer in="SA-o-b-cont" result="SA-o-b-c-sprd">
  <feFuncA id="spread-ctrl" type="linear" slope="11"/>
</feComponentTransfer>

<!-- Adjust color and opacity by adding fixed offsets and an opacity multiplier -->
<feColorMatrix id="recolor" in="SA-o-b-c-sprd" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="SA-o-b-c-s-recolor"/>

<!-- Generate a reasonably grainy noise input with baseFrequency between approx .5 to 2.0. And add the noise with k1 and k2 multipliers that sum to 1 -->
<feTurbulence result="fNoise" type="fractalNoise" numOctaves="6" baseFrequency="1.98"/>
<feColorMatrix in="fNoise" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 7 -3" result="clipNoise"/>
<feComposite id="noisemix" operator="arithmetic" in="SA-o-b-c-s-recolor" in2="clipNoise" k1="0" k2="1" result="SA-o-b-c-s-r-mix"/>

<!-- Merge the shadow with the original -->
<feMerge>
  <feMergeNode in="SA-o-b-c-s-r-mix"/>
  <feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
  </defs>
</svg>

enter image description here

I used the following link to generate the filter: https://codepen.io/mullany/pen/sJopz

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
2

Just a crazy idea, that actually get a display a little bit wrong.

Just post it to give some ideas for someone else to improve it.

.mytext {
  display: inline-block;
  margin: 10px;
  font-size: 50px;
  font-family: monospace;
  position: relative;
  color: black;
  text-shadow: -1px -1px 0px white, -1px 0px 0px white,  -1px 1px 0px white, 
  0px -1px 0px white,   0px 0px 0px white, 0px 1px 0px white,   
  1px -1px 0px white, 1px 0px 0px white, 1px 1px 0px white;
}

.mytext:after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 3ch;
  background-color: white;
  mix-blend-mode: difference;
}
<span class="mytext">123456789</span>

<span class="mytext" style="font-size:25px">123456789568</span>
<span class="mytext" style="font-size:25px">123568</span>
vals
  • 61,425
  • 11
  • 89
  • 138
1

::before and ::after Pseudo-elements { content: attr() } Values

Demo 1

  1. Use the pseudo-elements ::before and ::after
  2. Add data-before="0123456" and data-after="789" to the element
  3. Set the pseudo-elements with content: attr(data-before) and content: attr(data-after) and font-weight: 900

ch Unit of Measurement and Monospaced Fonts

Demo 2

  1. Set the following at the top of the CSS:

     :root, body { font: 100 3.5vw/0.75 Consolas, monospace; }
    

    All font related properties will reference this ruleset. Not only will this facilitate consistency, it is also very responsive.

  2. 1ch = the width of a zero character: "0" from the current font-family. If your font-family a monospace typeface then all of your characters are exactly the same width.


Demo 1

Note: There are two examples: one without text content and two with text content.

section {
  font: 400 16px/1.45 Consolas;
  background: gold;
  color: blue;
}

.count::before {
  content: attr(data-before);
}

.count::after {
  content: attr(data-after);
  font-weight: 900;
}

.B {
  font-size: 0;
}

.B::before,
.B::after {
  font-size: 1rem
}

.C::after {
  content: attr(data-mask);
  position: relative;
  left: -3ch;
  z-index: 1;
  font-weight: 900;
}
<section class='count A' data-before='0123456' data-after='789'></section>

<section class='count B' data-before='0123456' data-after='789'>0123456789</section>

<section class='count C' data-mask='789'>0123456789</section>

Demo 2

Note: This demo is a more complex version of the third example in Demo 1

:root,
body {
  font: 100 3.5vw/0.75 Consolas, monospace;
}

.box {
  border: 0;
  margin: 0 auto 50px;
  padding: 0;
  outline: 5px solid tomato;
  max-width: max-content;
  max-height: calc(3.5vw * .75);
  white-space: nowrap;
}

section {
  display: inline-block;
  position: relative;
  border: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  max-width: max-content;
  white-space: nowrap;
  letter-spacing: 0.1ch;
  background: gold;
  color: navy;
}

.D {
  z-index: 1;
}

.E {
  z-index: 0;
  margin-left: -1ch;
  font-weight: 900;
  color: red;
}

.red50-3 {
  max-width: calc(50% - 3ch);
}

.mov50-3 {
  right: calc(50% - 3ch);
}
<article class='box'>
  <section class='D red50-3'>0123456789</section>
  <section class='E mov50-3'>0123456789</section>
</article>
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • As it would require work either in javascript or server side to make the split strings it will not give any benefit to me. But interesting all the same thank you. – Tony H Apr 11 '20 at 09:52
  • @TonyH Ur...eh? JavaScript?...Nope, no JavaScript...Server side?...Nope, purely client side. In fact, it's only static HTML and CSS. Keep in mind there are only a handful of techniques that can facilitate dynamic behavior using only CSS and HTML. Even so, my answer isn't even dynamic...everything is hard coded HTML/CSS. – zer00ne Apr 12 '20 at 00:20
  • I mean if you have the string `0123456789` in the database on server side, you will have to do something either server side or in JS to create the substrings `0123456` and `789`. Trivial, but what I was looking to avoid. – Tony H Apr 13 '20 at 11:38
  • See **Demo 2** the caveat is that a duplicate tag is needed. The JS needed to duplicate a tag and its text is: `const x = document.querySelector(selector).outerHTML; document.body.innerHTML += x;` and the classes would be arranged as well. Keep in mind you are asking for a way to handle primitive values via CSS...impossible, CSS is presentation not a programming language. – zer00ne Apr 14 '20 at 12:37