HTML: 防止在一些标点符号前面有空格之前换行
HTML: Prevent line breaks before some punctuation characters preceeded by a whitespace
在法语排版惯例中,很少有标点符号像 ;
、:
或 ?
必须在前面加上白色 space。当标点位于其 HTML 容器的边界时,这会导致不必要的换行。
Voulez-vous coucher avec moi ce soir ? Non, merci.
变成
Voulez-vous coucher avec moi ce soir
? Non, merci.
objective就是这样得到的:
Voulez-vous coucher avec moi ce
soir ? Oui, bien sûr.
我没有找到任何方法来避免在使用 CSS 的那些字符之前换行。此外:
- 由于现有数据和人体工程学限制,在每次出现之前手动添加
不是一种选择。
- 使用 CSS
whitespace: nowrap;
不是一个选项,因为它必须在所有其他情况下发生。
我正在考虑使用全局 javascript 函数 运行 a str.replace(" ?", " ?");
但我无法弄清楚一些事情:
- 如何以及何时触发它
- 如何select适当的标签
- 如何仅替换 innerText(即不是属性内容)
有什么建议吗?
注意: 共享相同的 objective 但有一个纯粹的 CSS 约束,我这里没有。
理想情况下,您应该用硬 space 服务器端 而不是客户端来替换 space,因为如果如果您在客户端执行此操作,您会遇到更新内容时内容会回流的问题,这会导致明显的 flash/movement.
大多数情况下,您会在文本节点中遇到此问题,例如:
<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>
这是一个元素(p
元素),里面有一个文本节点。
可能 space 在一个文本节点中,标点符号在另一个文本节点中:
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
那里,"Voulez-vous coucher avec moi ce soir"和space在一个文本节点中(在span
中),但标点符号在另一个文本节点中(在p
中).我假设这种情况很少见,我们不需要担心。
在文本节点中处理它相对容易:
fixSpaces(document.body);
function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;
case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0");
break;
}
}
实例:
// Obviously, you wouldn't have this in a `setTimeout` in your
// real code, you'd call it directly right away
// as shown in the answer
console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);
function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;
case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0");
break;
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>
您可以在 body
末尾的 script
标记中,就在结束 </body>
元素之前。
但是再说一次:如果你能在服务器端做这个,那就更好了,避免回流。
如果我们想尝试处理一个文本节点以 space 结尾而下一个以标点符号开头的情况,如上所示:
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
...一种方法是获取所有文本节点的数组,然后查看是否有一个以 space 结尾,下一个以标点符号开头。这是不完美的,因为它不会尝试处理以 space 结尾的文本节点位于块元素末尾的情况(例如,标点符号在视觉上总是位于不同的行上) ,但总比没有好。唯一的缺点是你最终会得到块元素,最后有一个额外的硬space。
fixSpaces(document.body);
function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;
case 3: // Text node
array.push(node);
break;
}
return array;
}
function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}
console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);
function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;
case 3: // Text node
array.push(node);
break;
}
return array;
}
function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
将您的问题映射到上述内容:
How and when triggering it
将它放在body
末尾的script
元素中会很早就触发它,但是在内容在DOM中之后我们就可以对其进行操作了.
How to select the appropriate tags
我们忽略 标签 并在文本节点级别工作。
How to replace innerText only (ie not properties content)
通过处理文本节点级别。属性不是文本节点,因此我们不处理它们。
在法语排版惯例中,很少有标点符号像 ;
、:
或 ?
必须在前面加上白色 space。当标点位于其 HTML 容器的边界时,这会导致不必要的换行。
Voulez-vous coucher avec moi ce soir ? Non, merci.
变成
Voulez-vous coucher avec moi ce soir
? Non, merci.
objective就是这样得到的:
Voulez-vous coucher avec moi ce
soir ? Oui, bien sûr.
我没有找到任何方法来避免在使用 CSS 的那些字符之前换行。此外:
- 由于现有数据和人体工程学限制,在每次出现之前手动添加
不是一种选择。 - 使用 CSS
whitespace: nowrap;
不是一个选项,因为它必须在所有其他情况下发生。
我正在考虑使用全局 javascript 函数 运行 a str.replace(" ?", " ?");
但我无法弄清楚一些事情:
- 如何以及何时触发它
- 如何select适当的标签
- 如何仅替换 innerText(即不是属性内容)
有什么建议吗?
注意:
理想情况下,您应该用硬 space 服务器端 而不是客户端来替换 space,因为如果如果您在客户端执行此操作,您会遇到更新内容时内容会回流的问题,这会导致明显的 flash/movement.
大多数情况下,您会在文本节点中遇到此问题,例如:
<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>
这是一个元素(p
元素),里面有一个文本节点。
可能 space 在一个文本节点中,标点符号在另一个文本节点中:
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
那里,"Voulez-vous coucher avec moi ce soir"和space在一个文本节点中(在span
中),但标点符号在另一个文本节点中(在p
中).我假设这种情况很少见,我们不需要担心。
在文本节点中处理它相对容易:
fixSpaces(document.body);
function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;
case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0");
break;
}
}
实例:
// Obviously, you wouldn't have this in a `setTimeout` in your
// real code, you'd call it directly right away
// as shown in the answer
console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);
function fixSpaces(node) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
fixSpaces(child);
}
break;
case 3: // Text node
node.nodeValue = node.nodeValue.replace(/ ([;?!])/g, "\u00a0");
break;
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p>Voulez-vous coucher avec moi ce soir ? Non, merci.</p>
您可以在 body
末尾的 script
标记中,就在结束 </body>
元素之前。
但是再说一次:如果你能在服务器端做这个,那就更好了,避免回流。
如果我们想尝试处理一个文本节点以 space 结尾而下一个以标点符号开头的情况,如上所示:
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
...一种方法是获取所有文本节点的数组,然后查看是否有一个以 space 结尾,下一个以标点符号开头。这是不完美的,因为它不会尝试处理以 space 结尾的文本节点位于块元素末尾的情况(例如,标点符号在视觉上总是位于不同的行上) ,但总比没有好。唯一的缺点是你最终会得到块元素,最后有一个额外的硬space。
fixSpaces(document.body);
function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;
case 3: // Text node
array.push(node);
break;
}
return array;
}
function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}
console.log("Before...");
setTimeout(() => {
fixSpaces(document.body);
console.log("After");
}, 1000);
function gatherText(node, array = []) {
switch (node.nodeType) {
case 1: // Element
for (let child = node.firstChild;
child;
child = child.nextSibling) {
array = gatherText(child, array);
}
break;
case 3: // Text node
array.push(node);
break;
}
return array;
}
function fixSpaces(node) {
const texts = gatherText(node);
for (let i = 0, len = texts.length; i < len; ++i) {
const text = texts[i];
const str = text.nodeValue = text.nodeValue.replace(/ ([;?|])/g, "\u00A0");
if (i < len - 1 && str[str.length - 1] === " " && /^[;?!]/.test(texts[i + 1].nodeValue)) {
// This node ends with a space and the next starts with punctuation,
// replace the space with a hard space
text.nodeValue = str.substring(0, str.length - 1) + "\u00A0";
}
}
}
p {
font-size: 14px;
display: inline-block;
width: 220px;
border: 1px solid #eee;
}
<p><span>Voulez-vous coucher avec moi ce soir </span>? Non, merci.</p>
将您的问题映射到上述内容:
How and when triggering it
将它放在body
末尾的script
元素中会很早就触发它,但是在内容在DOM中之后我们就可以对其进行操作了.
How to select the appropriate tags
我们忽略 标签 并在文本节点级别工作。
How to replace innerText only (ie not properties content)
通过处理文本节点级别。属性不是文本节点,因此我们不处理它们。