如何使用CSS + HTML排除对话行中前导连字符的对齐?

3
我正在博客中编写小说,文本是水平对齐的(就像印刷书籍一样)。然而,这会对对话行产生负面影响,因为前导连字符和下一个单词之间的距离也被调整了。最终,对于不同的对话行,第一个单词没有对齐。是否可能使用某些CSS + HTML技巧来克服此问题?是否可能在Google Docs或Libre Office Writer中实现类似效果?谢谢。
样本截图(请忽略实际措辞 - 这只是为了说明情况)。如您所见,第一个单词(在两种情况下都是“Good”)没有左对齐(我不关心其他单词)。

Sample text

实际上,我想把一个前导连字符、后跟一个空格和一个单词的组合视为一个单词。我尝试了以下方法:
dstart::before { content: "\2014\00a0"; }</style><br/>
<span class="dstart">Good</span>

但是我的浏览器(Firefox)仍然识别空格字符并执行类似的对齐。我认为,如果其中一个主要浏览器不接受我的方法,则没有必要在其他浏览器中进行检查。
以下解决了这个问题:
<span style="padding-right: 0.5em;">-</span>Good...

然而,在复制/粘贴时,计划文本中连字符和“Good”之间将没有空格,因此仍然不可接受

请在您的结果中添加一张截图。 - shadeed9
如果你是在 HTML CSS 页面中编写你的故事,那么是可以的。但这取决于具体情况,你需要详细说明你想要实现什么样的页面或截图。 - Shail
@shadeed9 抱歉表述不清楚。请查看我添加的截图。 - Alexander Iurovetski
Rounin的建议(选项2)非常有趣。虽然我不能在我的情况下使用,但我决定将他的答案标记为解决方案。原因很简单:我正在使用WordPress.com Premium(不是.org),因此我只能更改CSS或纯HTML(任何嵌入脚本的尝试都会被阻止)。对其他使用例如Blogger的人来说,这个解决方案可能仍然非常有用。 - Alexander Iurovetski
抱歉,实际上这个解决方案只是添加了前导破折号,但并没有解决对齐的原始问题。 - Alexander Iurovetski
3个回答

2

最终,我自己找到了解决方案。对于占用了你们大量时间的Rounin和Oriol,我感到非常抱歉,同时也非常感谢你们真诚的帮助。正如我所提到的,我需要一个前导连字符、空格和第一个单词被视为一个单词。因此,不需要任何样式或特殊列表,只需简单地使用–&ensp;或类似的东西即可:

<!DOCTYPE HTML>
<html>

<head>
 <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
 <meta content="utf-8" http-equiv="encoding">

 <style>
     p { margin-top: 0; margin-bottom: 0; text-align: justify; }
 </style>
</head>

<body>
 <p>&ensp;Good morning, Alex-Ben-Charlie-David-Eugene-Frederick-George-Harry-Ian-Jake-Keith-Lachlan.</p>
 <p>&ensp;Good morning, Alex-Ben-Charlie-David-Eugene-Frederick, George-Harry-Ian-Jake-Keith-Lachlan-Mark.</p>
 <p>&ensp;Good morning, Mr. Pickwick.</p>
</body>
</html>

在这种情况下,页面上的文本按预期显示,并且复制/粘贴也按预期工作。我使用段落包装器<p>,因为在WordPress中,当我像这样写东西时,它会隐式注入:

–&ensp;早上好,Alex-Ben-Charlie-David-Eugene-Frederick-George-Harry-

–&ensp;早上好,Alex-Ben-Charlie-David-Eugene-Frederick, George-Harry-Ian-Jake-Keith-Lachlan-Mark。

–&ensp;早上好,Pickwick先生。

而且,当我从我的页面上复制/粘贴纯文本时,每个块都用空行分隔。是的,我希望它是这样,因为对于纯文本来说,这样阅读起来更容易。


好主意。请注意,默认值为text-justify: auto,这取决于实现,因此某些UA可能仍会添加额外的空间。text-justify: inter-word会更安全,因为它仅在单词分隔符处调整间距,而不包括像&ensp;这样的固定宽度空格。但是,该属性的浏览器支持较少。 - Oriol
这是一个很好的方法。现在我已经看到了你自己的解决方案,我对你一直追求的目标有了更清晰的理解。我知道你不能向你的WP设置添加脚本,但是,考虑到HTML不适合标记文学对话,你的解决方案和我下面发布的.js脚本的修改版本的结合(其中将'&#8212; &nbsp; &nbsp;'替换为'<span>&#8212;&ensp;</span>')可能是标记文学对话的开始,它真正像文学对话一样,不需要在每个话语之前手动插入_em dashes_。 - Rounin
感谢Oriol和Rounin的赞美之词。非常感谢Oriol引起了对text-justify的关注 - 我从未使用过它(尽管在寻找用于调整的CSS时看到过它)。我将检查inter-word选项,并可能包括它。关于Rounin的建议 - 如果允许JS,那么它看起来很有趣,但请记住,最好尽可能接近纯文本,因为归根结底,它是一段文本,不仅要显示,还要编辑 :) 因此,我想尽可能避免HTML标记。 - Alexander Iurovetski
很抱歉无法分享实际文本的链接。这是一个相当有趣的科幻故事,但是用俄语写的。希望有一天能够翻译它。然而,在那种情况下,我担心它会从文学作品变成不合适的作品。 - Alexander Iurovetski

1
你可以使用浮动让它脱离文档流:
.quote::before {
  content: "\2014\00a0";
  float: left;
}

.quote::before {
  content: "\2014\00a0";
  float: left;
}
.quote { text-align: justify; }
.quote::after { content: ""; width: 100%; display: inline-block; }
<div class="quote">Good morning Alex-Ben-Charlie</div>

然而,破折号似乎是内容的一部分,因此最好将其包含在真实元素中,而不是伪元素中。

.dash {
  float: left;
}
.quote { text-align: justify; }
.quote::after { content: ""; width: 100%; display: inline-block; }
<div class="quote">
  <span class="dash">&nbsp;</span>Good morning Alex-Ben-Charlie
</div>


非常感谢Oriol提供的详细建议。不幸的是,这会导致任何文本行都被拉伸,无论有多少单词。而纯粹的对齐将有条件地拉伸一行文本——我的粗略估计是该文本行的宽度至少应超过半页。当我删除 content: ""; 后,整个效果就像是纯粹的对齐。抱歉,恐怕我设定了太严格的限制。 - Alexander Iurovetski
@AlexanderIurovetski 不确定你在说什么。无论单词数量如何,对齐始终会进行调整。我的答案不会改变这种行为,只是防止破折号和第一个单词之间出现空格。 - Oriol
请尝试这个:**<style> div { float-left; text-align: justify; } </style><div>- 早上好,皮克威克先生。</div>**。 如果窗口足够宽,就不会被拉伸到整个窗口宽度。但是当您缩小窗口宽度时,文本将在某些点上被拉伸。如果您无法重现,请将内容缩小到前两个单词。在您的示例中,拉伸效果始终有效(直到删除 content: ""; 但在这种情况下,我们遇到了对齐的初始问题)。 - Alexander Iurovetski

0

一个解决方案可能是使用无序列表[1]标记您的对话,其中每个列表项都有一个破折号作为自定义符号。

看这个例子:

ul {
text-align: left;
list-style: none;
}

li {
margin-bottom: 20px;
}

li::before {
content: '\2014 \00a0 \00a0 \00a0';
}
<ul>
<li>Good morning, Alex-Ben-Charlie-David-Eugene-Frederick-George-Harry-Ian-Jake-Keith-Lachlan.</li>
<li>Good morning, Mr. Pickwick.</li>
</ul>

[1] 我知道用<ul><li>来标记文学对话并不是最明显的选择,但由于HTML5的<dialog>元素已经被重新定义了其原本的用途(参见:http://html5doctor.com/a-little-more-conversation-with-dialog/),并且现在处于实验阶段(参见:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog),目前还没有特定的元素来标记对话。

======

选项2

如果您需要在复制/粘贴时保留普通文本中的连字符,另一种选择可能是以下示例,在页面加载后,脚本会自动在每个<li>的开头插入一个em dash

var dialogue = document.getElementsByClassName('dialogue')[0];
var exchanges = dialogue.getElementsByTagName('li');

for (var i = 0; i < exchanges.length; i++) {
exchanges[i].innerHTML = '&#8212; &nbsp; &nbsp;' + exchanges[i].innerHTML;
}
ul {
text-align: left;
list-style: none;
}
<ul class="dialogue">
<li>Good morning, Alex-Ben-Charlie-David-Eugene-Frederick-George-Harry-Ian-Jake-Keith-Lachlan.</li>
<li>Good morning, Mr. Pickwick.</li>
</ul>


1
非常感谢Rounin提供如此全面的示例。实际上,我也考虑过无序列表。不幸的是,我不得不拒绝这种方法,因为在复制/粘贴时保留连字符对我来说非常重要。这也是我拒绝另一种方法的原因,该方法保留连字符并使用填充进行间距。恐怕我设置了太多限制。目前,前导连字符和第一个单词之间的间距是次要问题,与任何解决方案引起的副作用相比。 - Alexander Iurovetski
如果我们考虑以下内容 - 在复制/粘贴时保留连字符对我来说非常重要 - 这就排除了使用::before::after伪元素,因为它们是文档的展示部分(即不属于文档的内容部分)。相反,您可以在文档的其余部分加载后,使用脚本自动插入真实内容到文档中。我已经在上面发布了一个演示(参见:选项2)。 - Rounin
选项2非常有趣,我决定将您的答案标记为解决方案,尽管我无法在我的情况下使用。原因很简单:我正在使用WordPress.com高级版(而不是.org),因此我只能更改CSS或纯HTML(任何嵌入脚本的尝试都会被阻止)。这个解决方案对于其他使用者仍然可能非常有用,例如博客作者。 - Alexander Iurovetski
使用 li 可能是个好主意。但这并不能防止破折号和第一个单词之间的额外空格。事实上,我不知道这如何解决问题。这种做法让我感到困惑。 - Oriol
抱歉Rounin,我必须同意Oriol的观点。当我自己尝试了你的第二个选项时,它并没有真正起作用。是的,它会将破折号添加为符号,但它并没有解决最初的问题:如果我为ul定义**text-align:justify;**,那么我又回到了第一点——破折号和第一个单词之间的间距再次变化(请参见我的原始截图)。很抱歉,我不得不取消你的建议中的解决方案标记。 - Alexander Iurovetski

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