根据前一个元素的宽度设置 HTML 元素的填充

问题描述 投票:0回答:2

我正在将莎士比亚剧本格式化为 HTML。因为莎士比亚用韵律写作,所以习惯上缩进不在韵律第一拍开始的行,如下所示:

p.indent { padding-left: 100pt; }

<h4>HERMIA</h4>
<p>O me!</p>
<h5>[To Helena]</h5>
<p class="indent">You juggler, you cankerblossom,</p>
<p>You thief of love! What, have you come by night</p>
<p>And stol’n my love’s heart from him?</p>
<h4>HELENA</h4>
<p class="indent">Fine, i’ faith.</p>
<p>Have you no modesty, no maiden shame,</p>
<p>No touch of bashfulness? What, will you tear</p>
<p>Impatient answers from my gentle tongue?</p>
<p>Fie, fie, you counterfeit, you puppet, you!</p>

赫米亚

我啊!

[致海伦娜]

        你这个杂耍者,你这个腐烂花,
你这个爱情小偷!怎么,你晚上来了吗
还偷走了我爱人的心?

海伦娜

        好吧,我相信。
你有没有矜持,没有少女羞,
没有一点羞涩的感觉吗?什么,你会流泪吗
我温柔的舌头不耐烦地回答?
呸呸你个冒牌货你个傀儡你!

但是,最好缩进到前一行的宽度,而不是缩进固定的量。这会产生更接近这个的外观:

赫米亚

我啊!

[致海伦娜]

   你这个杂耍者,你这个腐烂花,
你这个爱情小偷!怎么,你晚上来了吗
还偷走了我爱人的心?

海伦娜

                 好吧,我相信。
你有没有矜持,没有少女羞,
没有一点羞涩的感觉吗?什么,你会流泪吗
我温柔的舌头不耐烦地回答?
呸呸你个冒牌货你个傀儡你!

在所需的解决方案中,每个

p.indent
元素的左填充量应等于最近的先前
p
元素的宽度(通常不是最近的先前元素,如
h4
h5
元素可能会介入)。

我认为我不能用纯 CSS 做到这一点,但我之前对此感到惊讶。如果没有,那么简单的JS?

javascript html css css-selectors
2个回答
0
投票

起初,我以为我可以只读取标题 / 中单词的长度,但如果它是大写或小写,那其实并不相同,而且这不是一个成功的方法。

您确定要手动放置那些“.indent”类吗?标题后面的任何内容怎么样?任何标题后的第一段?无论哪种方式,您使用的工具都是相同的。

对于每个 .indent 段落,确定最近的前一个同级标题 ( 到 ) 您可以使用 .previousSibling https://developer.mozilla.org/en-US/docs/Web/API/Element/previousElementSibling - - 然后要获取标题中实际字体/文本的宽度 - 你有点需要一个跨度或一些不是块级元素(非全角)的子元素/所以,你可以把渲染时就在那里 - 或者用 JS 添加它。然后您可以使用 getBoundingClientRect() https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect 检查它们 - 然后您可以检查该宽度并使用它来设置缩进它的同级段落。我认为这就像您所得到的一样简单。或者,您可以抓取所有元素,然后向下使用 nextSibling 并获取标题后的第一段。


0
投票

我怀疑这是否可以单独使用 css 来实现。

Javascript 确定缩进

应用缩进相当简单。 IE 设置

padding-left
值。
要找到要填充的金额,我们需要知道
<p>
标签对是什么。 一旦我们收集了所有对,我们就可以找出最后一个字符的位置并使用它来缩进下一行。

function getLastCharacterCoordinates(element) {
  const textNode = element.firstChild;
  const textLength = textNode.length;
  if (textLength === 0) return null;

  const range = document.createRange();
  // Set the range to select only the last character
  range.setStart(textNode, textLength - 1);
  range.setEnd(textNode, textLength);
  const rect = range.getBoundingClientRect();
  return {
    x: rect.left,
    y: rect.top
  };
}

function setIndent(element, indentSize) {
  element.style.paddingLeft = `${indentSize}px`
}

function findPairs() {
  // returns an array of pairing <p> tags, 
  // where the next line should start at the end of the previous line.
  const boundary = document.getElementById("boundary");
  const children = Array.from(boundary.children);
  // Reduce to find pairs of <p> tags separated by any other tag
  const result = children.reduce((acc, child, index, arr) => {
    // If the current element is <p> and there is a next element
    if (child.tagName === 'P' && index < arr.length - 2) {
      const nextTag = arr[index + 1].tagName; // Check the tag in between
      const nextP = arr[index + 2]; // The tag two steps ahead
      // If the element two steps ahead is also a <p> and there is another tag in between
      if (nextP.tagName === 'P' && nextTag !== 'P') {
        // we found a pair
        acc.push([child, nextP]);
      }
    }
    return acc;
  }, []);
  return result;
}

// call the functions and apply the indents:
const pairs = findPairs()
pairs.forEach(pair => {
  const cord = getLastCharacterCoordinates(pair[0])
  setIndent(pair[1], cord.x)
})
p,
h1,
h2,
h3,
h4,
h5 {
  /* remove default browser margins */
  margin: 0;
}
<div id="boundary">
  <h4>HERMIA</h4>
  <p>O me!</p>
  <h5>[To Helena]</h5>
  <p>You juggler, you cankerblossom,</p>
  <p>You thief of love! What, have you come by night</p>
  <p>And stol’n my love’s heart from him?</p>
  <h4>HELENA</h4>
  <p>Fine, i’ faith.</p>
  <p>Have you no modesty, no maiden shame,</p>
  <p>No touch of bashfulness? What, will you tear</p>
  <p>Impatient answers from my gentle tongue?</p>
  <p>Fie, fie, you counterfeit, you puppet, you!</p>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.