如何动态更改标题的宽度以确保行长均匀
How to dynamically change width of a headline to ensure even line lengths
我想弄清楚 The Washington Post website 如何强制主标题如此漂亮地中断,而不管实际文本或屏幕宽度如何。据我所知,如果 h1 的 class 为 headline
,则动态计算其宽度以达到效果。我知道这是用 JavaScript 完成的,并且想象它不是 hard-coded 那么实际计算的宽度是如何以某种方式认识到标题将如何中断(防止高度可变的行长度、孤儿等)。我只是无法找到控制此功能的 JS。
这是正常加载页面的示例:
以及删除了 headline
class 的示例:
(您也可以在页面加载时注意到差异,大概是在 JavaScript 开始之前。)
谢谢!
这就是你想要的。显然,因为有些单词比其他单词长,所以并非所有行的长度都完全相同。下面的代码保留了浏览器创建的 数量 换行符。然后,它调整换行符的位置以确保 或多或少 均匀的行长度。
P.S.: 尝试 运行 下面没有 JS 的代码,你会看到区别
let h1 = document.querySelector('h1')
let text = h1.textContent
let splitText = text.split(' ')
let getContentBoxHeight = elem => {
let elemStyle = window.getComputedStyle(elem)
let elemHeightWithPadding = parseInt(elemStyle.getPropertyValue('height'))
let elemPadding = parseInt(elemStyle.getPropertyValue('padding-top')) + parseInt(elemStyle.getPropertyValue('padding-bottom'))
return elemHeightWithPadding - elemPadding
}
let getContentBoxWidth = elem => {
let elemStyle = window.getComputedStyle(elem)
let elemWidthWithPadding = parseInt(elemStyle.getPropertyValue('width'))
let elemPadding = parseInt(elemStyle.getPropertyValue('padding-left')) + parseInt(elemStyle.getPropertyValue('padding-right'))
return elemWidthWithPadding - elemPadding
}
// return the number of line breaks created by the browser
let breakPointAmount = (() => {
let body = document.querySelector('body')
let dummyH1 = document.createElement('h1')
let oneLineHeight
let totalLineHeight = getContentBoxHeight(h1)
dummyH1.appendChild(document.createTextNode('M'))
body.appendChild(dummyH1)
oneLineHeight = getContentBoxHeight(dummyH1)
dummyH1.remove()
return Math.round(totalLineHeight / oneLineHeight) - 1
})()
// refine the number of line breaks created by the browser
let breakPoints = (() => {
let denominator = breakPointAmount + 1
let points = []
let h1Length
h1.style.width = 'max-content'
h1Length = getContentBoxWidth(h1)
h1.style.width = ''
for (let i = 0; i < breakPointAmount; i++) {
points.push(Math.round(h1Length * (i + 1) / denominator))
}
return points
})()
// determine where that same number of break points should go in text
let indexesToBreak = Array(breakPointAmount).fill(1)
let cumulativeLength = 0
let cumulativeText = ''
for (let i = 0; i < splitText.length; i++) {
let word = splitText[i]
let calculateLength = word => {
let body = document.querySelector('body')
let dummyH1 = document.createElement('h1')
let length
dummyH1.appendChild(document.createTextNode(word))
dummyH1.style.width = 'max-content'
body.appendChild(dummyH1)
length = getContentBoxWidth(dummyH1)
dummyH1.remove()
return length
}
cumulativeText += word + ' '
cumulativeLength = calculateLength(cumulativeText)
for (let j = 0; j < indexesToBreak.length; j++) {
if (indexesToBreak[j] === 1) {
indexesToBreak[j] = {
index: i,
currentMin: Math.abs(cumulativeLength - breakPoints[j])
}
} else {
if (cumulativeLength - breakPoints[j] < indexesToBreak[j].currentMin) {
indexesToBreak[j] = {
index: i,
currentMin: Math.abs(cumulativeLength - breakPoints[j])
}
}
}
}
}
// insert break points at updated locations into text
let newText = (function() {
let final = ''
let itbIndex = 0
for (let i = 0; i < splitText.length; i++) {
final += `${splitText[i]} `
if (indexesToBreak[itbIndex] && i === indexesToBreak[itbIndex].index) {
final += '<br>'
itbIndex += 1
}
}
return final.trim()
})()
// add text with new break points to page
h1.innerHTML = newText
h1 {
text-align: center;
}
<h1>Some Long Title that Requires Line Breaking To Ensure Even Line Lengths</h1>
我想弄清楚 The Washington Post website 如何强制主标题如此漂亮地中断,而不管实际文本或屏幕宽度如何。据我所知,如果 h1 的 class 为 headline
,则动态计算其宽度以达到效果。我知道这是用 JavaScript 完成的,并且想象它不是 hard-coded 那么实际计算的宽度是如何以某种方式认识到标题将如何中断(防止高度可变的行长度、孤儿等)。我只是无法找到控制此功能的 JS。
这是正常加载页面的示例:
以及删除了 headline
class 的示例:
(您也可以在页面加载时注意到差异,大概是在 JavaScript 开始之前。)
谢谢!
这就是你想要的。显然,因为有些单词比其他单词长,所以并非所有行的长度都完全相同。下面的代码保留了浏览器创建的 数量 换行符。然后,它调整换行符的位置以确保 或多或少 均匀的行长度。
P.S.: 尝试 运行 下面没有 JS 的代码,你会看到区别
let h1 = document.querySelector('h1')
let text = h1.textContent
let splitText = text.split(' ')
let getContentBoxHeight = elem => {
let elemStyle = window.getComputedStyle(elem)
let elemHeightWithPadding = parseInt(elemStyle.getPropertyValue('height'))
let elemPadding = parseInt(elemStyle.getPropertyValue('padding-top')) + parseInt(elemStyle.getPropertyValue('padding-bottom'))
return elemHeightWithPadding - elemPadding
}
let getContentBoxWidth = elem => {
let elemStyle = window.getComputedStyle(elem)
let elemWidthWithPadding = parseInt(elemStyle.getPropertyValue('width'))
let elemPadding = parseInt(elemStyle.getPropertyValue('padding-left')) + parseInt(elemStyle.getPropertyValue('padding-right'))
return elemWidthWithPadding - elemPadding
}
// return the number of line breaks created by the browser
let breakPointAmount = (() => {
let body = document.querySelector('body')
let dummyH1 = document.createElement('h1')
let oneLineHeight
let totalLineHeight = getContentBoxHeight(h1)
dummyH1.appendChild(document.createTextNode('M'))
body.appendChild(dummyH1)
oneLineHeight = getContentBoxHeight(dummyH1)
dummyH1.remove()
return Math.round(totalLineHeight / oneLineHeight) - 1
})()
// refine the number of line breaks created by the browser
let breakPoints = (() => {
let denominator = breakPointAmount + 1
let points = []
let h1Length
h1.style.width = 'max-content'
h1Length = getContentBoxWidth(h1)
h1.style.width = ''
for (let i = 0; i < breakPointAmount; i++) {
points.push(Math.round(h1Length * (i + 1) / denominator))
}
return points
})()
// determine where that same number of break points should go in text
let indexesToBreak = Array(breakPointAmount).fill(1)
let cumulativeLength = 0
let cumulativeText = ''
for (let i = 0; i < splitText.length; i++) {
let word = splitText[i]
let calculateLength = word => {
let body = document.querySelector('body')
let dummyH1 = document.createElement('h1')
let length
dummyH1.appendChild(document.createTextNode(word))
dummyH1.style.width = 'max-content'
body.appendChild(dummyH1)
length = getContentBoxWidth(dummyH1)
dummyH1.remove()
return length
}
cumulativeText += word + ' '
cumulativeLength = calculateLength(cumulativeText)
for (let j = 0; j < indexesToBreak.length; j++) {
if (indexesToBreak[j] === 1) {
indexesToBreak[j] = {
index: i,
currentMin: Math.abs(cumulativeLength - breakPoints[j])
}
} else {
if (cumulativeLength - breakPoints[j] < indexesToBreak[j].currentMin) {
indexesToBreak[j] = {
index: i,
currentMin: Math.abs(cumulativeLength - breakPoints[j])
}
}
}
}
}
// insert break points at updated locations into text
let newText = (function() {
let final = ''
let itbIndex = 0
for (let i = 0; i < splitText.length; i++) {
final += `${splitText[i]} `
if (indexesToBreak[itbIndex] && i === indexesToBreak[itbIndex].index) {
final += '<br>'
itbIndex += 1
}
}
return final.trim()
})()
// add text with new break points to page
h1.innerHTML = newText
h1 {
text-align: center;
}
<h1>Some Long Title that Requires Line Breaking To Ensure Even Line Lengths</h1>