Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex quotes in HTML

I am trying to format quotes the old-fashioned way. — Is there any way to go from this input:

<p>He argued that <q>the King by his proclamation or other ways cannot change any part of the common law, or statute law, or the customs of the realm</q> and concluded that…</p>

to this output (as displayed on the browser):

He argued that “the King by his procla-
“ mation or other ways cannot change any
“ part of the common law, or statute law,
“ or the customs of the realm” and con-
cluded that…

In the example above, hyphenation, alignment and line length are set arbitrarily and for illustration purpose. They aren’t of any concern.

I would like that, when a line breaks inside the <q>, each consequent lines (that are in the <q>), when displayed, be preceded by a quotation mark (so as the reader would visually isolate the quote). It is an old-fashioned way of formatting indirect speech.

The best I could come up with so far is an unsatisfactory pseudo-workaround using <blockquote> combined with text-shadow in CSS:

* {font-family: monospace; line-height: 1.4em; width: 25em; margin: 0;}

blockquote { position: relative; padding-left: 1.2em; text-indent: -1.2em; overflow-y: hidden;}

blockquote::before {content:"“"; position: absolute; top: 1.4em; left: 1.2em; text-shadow: 0 1.4em 0 #000, 0 2.8em 0 #000, 0 4.2em 0 #000;}
<p>He argued that <blockquote>“the King by his proclamation or other ways cannot change any part of the common law, or statute law, or the customs of the realm”</blockquote> and concluded that…</p>

(Which may vaguely resemble what I wanted (kinda), but ultimately does not work given the block nature of <blockquote>; furthermore, when set inline, the desired effect of the quotation marks being set to the left is lost.)

Edit: acknowledging answers.

Obviously, we are going the JS route. I’ve considered:

  • Find browser-computed line breaks, and replace each one with "<br>&ldquo;&nbsp;"(eventually leading to multiple issues in justified texts—therefore not ideal);
  • @A-Haworth suggestion of “[a] method to find the line breaks [with] a dummy element, gradually add[ing] the text and spot[ting] when it gets higher.”

But I just don’t know how to do any of these things. Also, there must be a solution I haven’t thought of.

Any idea?

Last Edit (Feb 16, 2022)

No one, really?

like image 597
Rotie Avatar asked Aug 31 '26 02:08

Rotie


1 Answers

It probably can't be done in an easy way. I tried to write a small function that might help you. The solution needs to be finalized, but you can take the basic idea. if you need a dynamic solution, use resize observer, as indicated in the example.

function quote(el, leftPad = 16) {
  const txt = el.textContent.trim().split(" ");
  const ctx = document.createElement("canvas").getContext("2d");
  const styleList = getComputedStyle(el);
  ctx.font = `${styleList.fontWeight} ${styleList.fontSize} "${styleList.fontFamily}"`;
  const maxWidth = el.clientWidth;
  let paragraph = [];
  let line = "";
  let lineWidth = 0;
  let blockquote = false;
  const symbolMap = new Map();
  let firstLineBreak = false;
  let quoteRowCount = 0;

  const getWordLength = (word) => {
    let wordWidth = 0;
    for (let i = 0; i < word.length; i++) {
      if (!symbolMap.has(word[i])) {
        symbolMap.set(word[i], ctx.measureText(word[i]).width);
      }
      wordWidth += symbolMap.get(word[i]);
    }
    return wordWidth;
  };

  for (let i = 0; i < txt.length; i++) {
    const word = txt[i] + " ";
    const width = getWordLength(word);
    lineWidth += width;
    if (txt[i].search('"') >= 0) blockquote = !blockquote;
    if (lineWidth > maxWidth) {
      paragraph.push(line);
      if (!firstLineBreak && blockquote) {
        line = '<br><span class="newline"></span>';
        firstLineBreak = true;
        quoteRowCount++;
      } else {
        if (blockquote) quoteRowCount++;
        line = "";
      }
      lineWidth = leftPad + width;
    }
    line += word;
  }
  if (line.trim() !== "") paragraph.push(line);
  el.innerHTML = paragraph.join("<wbr>");

  const newLineElement = el.querySelector(".newline");
  if (newLineElement) newLineElement.style.height = `${quoteRowCount}em`;
}

const el = document.querySelector("p");
quote(el);
// or if you need ResizeObserver =>
//new ResizeObserver(() => quote(el)).observe(el);
p {
  width: 220px;
  font-size: 16px;
  font-family: Arial;
  padding: 0;
  box-sizing: content-box;
}

.newline {
  display: block;
  width: 1em;
  padding-right: 1em;
  float: left;
  overflow: hidden;
  box-sizing: border-box;
  word-break: break-word;
}

.newline:before {
  content: '""""""""""""""""""""""""';
}
<p>
  He argued that "the King by his proclamation or other ways cannot change any part of the common law, or statute law, or the customs of the realm" and concluded that…
</p>
like image 74
Oleg Barabanov Avatar answered Sep 01 '26 16:09

Oleg Barabanov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!