CSS文字两端对齐与字母间距

31

有没有办法使用CSS自动地将每行单词的字母间距调整到一个定义好的宽度,从而实现对文本的自动调整?

例如,“Something like this”看起来就像这样:

"Something like this" would look something like this

是否有一种不影响其他样式的方法来应用这种样式到我的文本中?我认为纯CSS并没有这个选项(至少不是在CSS3之前的版本,CSS3似乎有一个 text-justify 属性,但目前支持得不够好),所以js解决方案也是可以的。


你是否愿意使用特定的JS库来实现这个功能,还是只使用原生JS? - David Thomas
@David:jQuery 是首选,但这是一个相当简单的任务,所以我认为可以在不同框架之间进行移植而没有问题。 - vgru
10个回答

13

这里有一个脚本可以实现此功能。它可能不太美观,但也许您可以修改它以满足您的需求。(已更新以处理调整大小)

function SplitText(node) {
  var text = node.nodeValue.replace(/^\s*|\s(?=\s)|\s*$/g, "");

  for (var i = 0; i < text.length; i++) {
    var letter = document.createElement("span");
    letter.style.display = "inline-block";
    letter.style.position = "absolute";
    letter.appendChild(document.createTextNode(text.charAt(i)));
    node.parentNode.insertBefore(letter, node);

    var positionRatio = i / (text.length - 1);
    var textWidth = letter.clientWidth;

    var indent = 100 * positionRatio;
    var offset = -textWidth * positionRatio;
    letter.style.left = indent + "%";
    letter.style.marginLeft = offset + "px";

    //console.log("Letter ", text[i], ", Index ", i, ", Width ", textWidth, ", Indent ", indent, ", Offset ", offset);
  }

  node.parentNode.removeChild(node);
}

function Justify() {
  var TEXT_NODE = 3;
  var elem = document.getElementById("character_justify");
  elem = elem.firstChild;

  while (elem) {
    var nextElem = elem.nextSibling;

    if (elem.nodeType == TEXT_NODE)
      SplitText(elem);

    elem = nextElem;
  }
}
#character_justify {
  position: relative;
  width: 40%;
  border: 1px solid red;
  font-size: 32pt;
  margin: 0;
  padding: 0;
}

#character_justify * {
  margin: 0;
  padding: 0;
  border: none;
}
<body onload="Justify()">
  <p id="character_justify">
    Something<br/> Like
    <br/> This
  </p>
</body>


1
谢谢,它运行得很好。对于那些感兴趣的人来说,这个脚本通过id查找一个div,在计算的缩进位置插入一个单独的div,并且然后删除初始的div。 - vgru
还有一个小问题,就是字符的位置是固定间隔而不是它们之间有固定的间距。当你有不同宽度的字符(比如“WiW”)时,这看起来很奇怪。我想知道是否可以在字母之间添加空格,并像每个字符都是一个单词一样使用浏览器对齐,但如果末尾有<br/>,它们就无法对齐。你有什么建议吗? - vgru

9

CSS只有一个解决方案,即text-justify: distribute https://www.w3.org/TR/css-text-3/#text-justify,但目前支持度非常低。

A small experiment using text-align-last: justify and adding spaces between letters.

div{
 display:inline-block;
 text-align: justify;
 text-align-last: justify;
 letter-spacing: -0.1em;
}
<div>
S o m e t h i n g<br>
l i k e<br>
t h i s
</div>


这是一个不错的“技巧”,但是当添加空格和整个句子时,它很快就会崩溃。但是,我还是给了你一个赞。 - Fusseldieb

4
我知道这是一个旧话题,但我最近晚上遇到了这个问题。 我使用表格找到了一个合适的解决方案。
每一个字母都应该放在<td> </td>里。我知道看起来很繁琐,但如果你只需要做一个词或两个词,那么也可以轻松完成。或者如果太多的话,你总是可以使用JS去填充它。然而,这只是CSS非常通用的解决方案。
使用letter-spacing可以使字母正确分布。根据表格的宽度,您应该试着调整一下它。
#justify {
  width: 300px;
  letter-spacing: 0.5em;
}

<table id="justify">
  <tbody>
    <tr>
      <td>J</td>
      <td>U</td>
      <td>S</td>
      <td>T</td>
      <td>I</td>
      <td>F</td>
      <td>Y</td>
    </tr>
  </tbody>
</table>

点击此处查看示例

跨浏览器安全,几乎没有任何差异,只是CSS。

我在我的网站上使用了它,该网站支持英语和西班牙语。我的名字下面的西班牙语子标题有一个额外的字母,会使宽度超出范围。使用上面解释的表格,可以自动分配相同的宽度。如果手动进行间距设置,则需要为每种语言定义一个完整的条件。


2
取消你的踩赞是因为你有一些道理:这通常是针对范围有限的情况。此外,我喜欢你的网站。但我想如果我要“核弹攻击”(物理上分离字母),我仍然会使用flexbox或inline block。表格带有其他布局奇怪之处(即它们与其他块级框不同)。 - harpo
在我看来,这绝对是最好、最干净的方法。是的,一个简单的脚本可以为您创建并填充表格。比这里其他选项要好得多。 - ElDoRado1239
不幸的是,letter-spacing 会在单词末尾添加一个空格,这在其他右对齐内容中看起来不好。 - Robert Synoradzki

3
这里有另一种方法,使用我为这个问题编写的jQuery代码片段:Stretch text to fit width of div

演示

HTML:

<div class="stretch">Something</div>
<div class="stretch">Like</div>
<div class="stretch">This</div>

jQuery :

$.fn.strech_text = function () {
    var elmt = $(this),
        cont_width = elmt.width(),
        txt = elmt.html(),
        one_line = $('<span class="stretch_it">' + txt + '</span>'),
        nb_char = elmt.text().length,
        spacing = cont_width / nb_char,
        txt_width;

    elmt.html(one_line);
    txt_width = one_line.width();

    if (txt_width < cont_width) {
        var char_width = txt_width / nb_char,
            ltr_spacing = spacing - char_width + (spacing - char_width) / nb_char;

        one_line.css({
            'letter-spacing': ltr_spacing
        });
    } else {
        one_line.contents().unwrap();
        elmt.addClass('justify');
    }
};


$(document).ready(function () {
    $('.stretch').each(function () {
        $(this).strech_text();
    });
});

2

1

我找到了另一种使用纯CSS实现这个的方法,但是你需要拼出你的单词。

在我的情况下,这是唯一有效的解决方案(一些字母有类),而且它还产生了最直接的右对齐方式,而不需要使用hack。

.box {
  width: min-content;
  border: solid red;
}

.word {
  display: flex;
  justify-content: space-between;
}
<div class="box">
  <div class="word">
    <span>S</span>
    <span>o</span>
    <span>m</span>
    <span>e</span>
    <span>t</span>
    <span>h</span>
    <span>i</span>
    <span>n</span>
    <span>g</span>
    <span>&nbsp;</span>
    <span>w</span>
    <span>i</span>
    <span>c</span>
    <span>k</span>
    <span>e</span>
    <span>d</span>
  </div>

  <div class="word">
    <span>t</span>
    <span>h</span>
    <span>i</span>
    <span>s</span>
    <span>&nbsp;</span>
    <span>w</span>
    <span>a</span>
    <span>y</span>
  </div>

  <div class="word">
    <span>c</span>
    <span>o</span>
    <span>m</span>
    <span>e</span>
    <span>s</span>
  </div>
</div>


0

我知道这个问题很老了,但为什么不在每个字母之间加一个空格,然后使用text-align:justify呢?这样每个字母都会被视为一个“单词”,并相应地进行对齐。


2
可以这样做,没错,但问题是如何在不混合标记和表现的情况下实现。这种类型的解决方案类似于使用表格而不是CSS进行页面布局,但在这种情况下,您还会失去SEO积分,因为搜索引擎将无法将它们识别为完整单词。这个问题已经在CSS3中得到了解决。 - vgru

0
我刚刚从Tony B的方法中制作了一个JQuery脚本。 这是JSFiddle https://jsfiddle.net/7tvuzkg3/7/
此脚本创建一个表格,每个字符占一行。它适用于完整的句子。 我不确定这是否完全优化。

justifyLetterSpacing("sentence");

function justifyLetterSpacing(divId) {

 // target element
 domWrapper = $('#' + divId).clone().html('');
 // construct <td>
 $('#' + divId).contents().each(function(index){
      // store div id to td child elements class
   var tdClass = divId ;
      // split text 
   $textArray = $(this).text().split('');
      // insert each letters in a <td>
   for (var i = 0; i < $textArray.length; i++) {
        // if it's a 'space', replace him by an 'html space'
        if( $textArray[i] == " " )  {
            $('<td>')
                .addClass(tdClass)
                .html("&nbsp;&nbsp;")
                .appendTo(domWrapper);
        }// if it's a char, add it
        else{  
            $('<td>')
                .addClass(tdClass)
                .text($textArray[i])
                .appendTo(domWrapper);
        }
   }
 });
    // create table
    table = 
    $( "<table id='"+divId+"'/>" ).append( 
        $( "<tbody>" ).append( 
            $( "<tr>" ).append( 
                ( domWrapper ).children('td') 
            ) 
        )
    );
    // replace original div
 $('#' + divId).replaceWith( table );
} 
#sentence {
  width : 100%;
  background-color : #000;
  color : #fff;
  padding : 1rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="sentence">LOREM IPSUM DOLOR</div>


0

我通常会尽快回答问题。这正好是同样的时间(十年后)=)

myText.innerHTML = myText.textContent
    .split(/\s+/g)
    .map((line) => line.trim().split("").join(" "))
    .join("<br>");
#myText {
    display: inline-block;
    text-align: justify;
    text-align-last: justify;
    letter-spacing: -0.125em;
    font-family: sans-serif;
}
<div id="myText">Something like this</div>


0

处理这个问题的另一种方法可能是使用"vw"大小单位。该单位类型可用于字体大小属性,表示窗口宽度的百分比。

免责声明:虽然不完全符合您的要求,但无需脚本编写。它可以调整文本大小,但也会根据页面的宽度进行缩放。

例如,

.heading {
  font-size: 4vw;
}

将当前字体中一个字符的宽度设为窗口宽度的4%。

如果您希望根据窗口宽度将字体大小锁定到最小值,则可以使用媒体查询。

@media only screen and (max-width: 768px) {
    font-size: 2rem;
}

使用浏览器检查器来调整字体大小属性的值,以适应您的应用程序。
“vw”单位适用于IE9+、iOS 8.3+、Android 4.4+和所有其他主流浏览器。不必过于担心移动设备的支持问题,因为您可以使用媒体查询来为这些设备设置正确的大小,如上所述。

http://caniuse.com/#feat=viewport-units

https://css-tricks.com/viewport-sized-typography/

视口单位是一种强大的方式,可以用很少的代码来缩放您网站的许多不同方面。


但我不认为它会改变字距? - vgru
不,它并不是。这是一种稍微不同的方法。您正在配置文本大小以适应容器。然后,当调整窗口大小时,整个文本块会随着窗口宽度调整。这绝对是一种替代方法,而不是问题的100%答案,但如果不可能或不需要使用脚本方法,则可以接受。 - Neil Monroe

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