Есть ли в моем абзаце разрыв столбца? Сколько строк в нем?

В CSS есть концепция вдов и сирот, поэтому в браузере есть способ узнать, сколько строк пересекают границу столбца (или, если печатается, страницы).

Есть ли способ узнать это в JavaScript?

Это может быть сделано очень неприятным и хрупким способом с использованием геометрии элементов, но это кажется довольно нежелательным результатом.

Например: https://codepen.io/notionparallax/pen/BvLZeB

document.querySelectorAll("p, h1, h2, h3, h4, h5").forEach(
    (x) => {

      let boxW    = Math.round(x.getBoundingClientRect().width);
      let clientW = Math.round(x.clientWidth);
      if (boxW !== clientW) {
        console.log(x);
        x.classList.add("has-break");
      }

      try {
        if (x.nextElementSibling.offsetLeft !== x.offsetLeft) {
          console.log(x);
          x.classList.add("end-of-column");
        }
      } catch(error) {}

    }
)

В библиотеке, такой как Paged.js, есть концепция токена разрыва, который указывает, где в элементе происходит разрыв (если действительно есть разрыв). Я полагаю, что такого рода вещи могли бы стать возможными благодаря Гудини. Мне интересно посмотреть, есть ли способ опроса элемента, чтобы увидеть, переносится ли он на следующую страницу/столбец, используя обычные методы.

Случай использования

Я хочу знать, где происходит разрыв элемента, чтобы я мог увидеть, должен ли я вернуться к DOM и поставить разрыв перед предшествующим заголовком. Это частично обрабатывается вдовами и сиротами для самого элемента, но я хотел бы иметь возможность иметь более тонкое управление, чтобы, например, глава не начиналась прямо внизу страницы. Я бы согласился с двумя строками абзаца между двумя абзацами, но абзац, следующий за заголовком, должен получить немного больше передышки.

Обновить

Меня не интересуют решения для варианта использования, меня интересуют ответы на вопрос в заголовке. Вариант использования иллюстрирует одно из возможных применений интересующей меня информации, а не единственную причину вопроса.

Ответы

Ответ 1

Вы можете добавить page-break-before: always; для тега, это установит разрыв страницы перед тегом. Например, добавление этого CSS в h1 создаст новую страницу перед каждым заголовком h1

h1 {
  page-break-before: always;
}
<div>
  <h1>Page 1</h1>
  <p>content here</p>
  <h1>Page 2</h1>
  <p>content here</p>
</div>

Ответ 2

🎈 Простое решение

Во-первых, давайте исправим правило для сирот для абзацев, например:

p {
  orphans: 2;
}

Тогда сироты правят для заголовков:

h1 + p {
  orphans: 4;
}

.new-chapter {
  break-before: column;
}

Наконец, нам нужно js, чтобы добавить класс new-chapter в h1, чтобы предотвратить new-chapter заголовков от абзаца:

document.querySelectorAll("h1 + p").forEach(p => {
  const h1 = p.previousElementSibling
  if (h1.offsetLeft !== p.offsetLeft) {
    h1.classList.add('new-chapter')
    h1.style.opacity = 0.99
  }
  // after inserting css class need to refresh dom
  setTimeout(() => {
    h1.style.opacity = 1
  }, 2000)
})

Проверьте EMDEMO

Ответ 3

Добавление этого ответа только для будущих читателей в том случае, если API, упомянутый ниже, становится стандартной реализацией в основных браузерах и упрощает js, необходимые для идентификации разрывов столбцов в элементах. Нижеследующее в настоящее время не полезно в производственном коде, поскольку ни один из основных браузеров, о котором я знаю, полностью не реализует приведенный ниже API на момент ответа.

Существует API объектной модели CSS под названием GeometryUtils с getBoxQuads() который возвращает объекты, представляющие каждый фрагмент CSS узла. Единственный браузер, о котором я знаю, где он в основном реализован во время этого ответа - это Firefox Nightly.

Этот метод позволяет довольно просто идентифицировать разрывы внутри элемента, поскольку он возвращает объект DOMQuad для каждого фрагмента CSS узла, поэтому вы можете сделать что-то вроде...

let frags = document.querySelector('p').getBoxQuads().length;

... где frags представляет количество фрагментов CSS для выбранного элемента. Если элемент имеет более 1 фрагмента, то происходит разрыв. Вам все еще потребуются дополнительные js для определения количества строк и т.д., Но это позволит вам отделить эти усилия от элементов с разрывом. Если вы заинтересованы в экспериментировании с getBoxQuads() как показано выше, вам необходимо загрузить Firefox Nightly.