使用CSS或JS突出每行的第一个字符

4
我需要突出每行的第一个字符,就像下面的示例图一样。所有内容都在单个段落中,无论分辨率如何变化,它都应该表现相同。

enter image description here

我已经尝试使用flex box和脚本来处理第一个子元素,但是我无法找到解决方案。

任何帮助都将不胜感激。


请查看 http://github.com/xdamman/js-line-wrap-detector (参见 https://dev59.com/uW865IYBdhLWcg3wl_o3#20956711) - 需要略微扩展以在每行的第一个<span>元素上添加另一个类,以通过 ::first-letter 进行定位。 如果段落没有固定宽度,请注意重新排列。 - Conan
4个回答

5

试试这个:

p::first-letter {
  font-weight: bold;
  color: #8A2BE2;
}
<p>Hi there</p>
<p>Color first!</p>

编辑: 好的,既然你需要每行都在一个段落中,那么你需要使用脚本来完成这个任务。

var allLines = document.querySelector("p").innerHTML.split("\n");
allLines = allLines.filter(function(x){return x !== ""}).map(function(x){
return "<span>" + x.charAt(0) + "</span>" + x.substr(1);
}).join("<br/>");
document.querySelector("p").innerHTML = allLines;
span {
  color: red;
}
<p>
TEXT
SOME MORE TEXT
</p>


内容是从文本区域编写的,我无法将其放入多个p标签中,所有内容都在一个单独的p标签中,如果需要建议,可能需要多个p标签,但这是不可能的。 - Naveen Setty
这个方法在某种程度上是有效的——问题要求获取段落中每个新行的第一个字母。你的解决方案适用于每个段落标签的第一个字母。 - Sterling Archer

4

使用CSS响应式解决方案,使用mix-blend-mode,但IE和Edge不支持该功能。

思路是使用有固定宽度(最大字母宽度)的彩色叠加层和mix-blend-mode: screen;仅为每行的第一个字母上色。

您需要使用等宽字体,这样如果第一个字母很窄,颜色就不会溢出到下一个字母。

p {
  position: relative;
  font-family: monospace; /** to have constant character width **/
  font-size: 28px;
  background: white;
}

p::before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  background: red;
  mix-blend-mode: screen;
  pointer-events: none; /** to enable selected of the text under the pseudo element **/
  color: transparent; /** to hide the character **/
  content: 'W'; /** a character in your font to use as width **/
}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis euismod orci. Morbi ullamcorper augue ipsum, at consectetur turpis dictum sed. Phasellus bibendum tellus eu aliquet congue. Morbi ultrices aliquam purus, id semper diam aliquet eget. Nulla
  at tellus lacus. Curabitur massa lectus, auctor et lobortis vel, sodales non diam. Pellentesque gravida tortor ac ex porta congue. Ut vestibulum arcu ex, ac lacinia tortor pulvinar id. Nulla sagittis, lectus at luctus dignissim, orci nulla interdum
  ex, at euismod nibh ipsum et lacus. Suspendisse potenti. Quisque ac eros nunc. Suspendisse sit amet dolor diam. Phasellus blandit commodo mi, at aliquam mi facilisis ut. Vestibulum lacinia enim tempor nunc elementum suscipit. Praesent ligula ipsum,
  venenatis et tellus at, imperdiet tempus lectus. Pellentesque consequat magna augue, at vestibulum sem facilisis nec.</p>


1
你需要使用等宽字体,这对于解决方案来说是一个相当严格的要求。 - ESR
1
我同意。然而,这只是“一个解决方案”,而不是“唯一的解决方案”,它可能适合某些人的需求。对于流行字体,例如Roboto(Roboto Mono)和Open Sans(Droid Sans Mono),都有等效的单色字体。 - Ori Drori

3

可以尝试这种方法(可能不是最好的,但它完全有效):

var content = document.getElementById('content').innerHTML
var doYourThing = function(){
  var formattedContent = content.replace(/(\w)/g,'<span>$1</span>')
  document.getElementById('formatted').innerHTML = formattedContent

  var characters = document.getElementsByTagName('span')
  var refPosition = characters[0].getBoundingClientRect().left

  for (character of characters){
    if(character.getBoundingClientRect().left <= refPosition){
      character.style.textTransform = "capitalize"
      character.style.color = "red"
    }
  }
}
doYourThing()
window.onresize = doYourThing
<p id="content">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Neque nisi minima veritatis ipsa magnam culpa ipsam dolores. Deserunt rerum, quod unde consequatur consectetur harum omnis sequi, voluptatum quaerat quasi illo?
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae, esse, repellendus sed voluptate facere magni quis beatae corrupti odio id! Labore voluptatem soluta harum esse, at atque deserunt nesciunt ipsa.
</p>
<p id="formatted" style="background-color:#fee"></p>

您可以根据自己的需求进行定制。祝您好运。 JSFiddle


2

简单方法

实现这个结果的简单方法是使用 split("\n") 获取所有行,然后用一个适当的类将每行的第一个字母替换为自身,放入包含在 <span> 中,并最后使用 join("<br/>") 连接行并将它们放回原来的父元素中。

var lines = document.querySelector("p").innerHTML.split("\n");
for(var key in lines)
 lines[key] = "<span class='first-letter'>" + lines[key].substr(0, 1) + "</span>" + lines[key].substr(1);
document.querySelector("p").innerHTML = lines.join("<br/>");
span.first-letter {
  font-weight: bold;
  color: red;
}
<p>This is a line 
This is another line 
This is yet another line</p>

另一种(语义正确的)方式

另一个选项是像之前一样使用split("\n"),但实际上用<p>标签包装每一行。然后将这些行join()起来并用它们替换原始父元素。这利用了::first-letter CSS伪元素来为这些类设置样式,比之前的方法更加语义正确。

var lines = document.querySelector("p").innerHTML.split("\n");
for(var key in lines)
 lines[key] = "<p>" + lines[key] + "</p>";
document.querySelector("p").outerHTML = lines.join("");
p::first-letter {
  font-weight: bold;
  color: red;
}
/* This is a quick fix to make paragraphs display same as if the were all part of the same one, alter this based on your page's style and your needs. */
p + p {
  margin-top: -16px;
}
<p>This is a line 
This is another line 
This is yet another line</p>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接