具有视觉效果的语义歌曲标记 "chord stacking"
Semantic song markup with visual "chord stacking"
我正在寻找一种基于 HTML 的表示形式,用于在音节上方带有和弦的歌曲文本,采用以下方式:
Am C D F
There is a house in New Orleans
现在,我不在乎 HTML 到底长什么样子,但有一个重要的约束:目的不仅是显示,而且是以语义上有意义的表示形式存储。具体来说,这些歌曲是从 LaTeX-based 语法转换而来的,应该可以以其原始形式恢复,并且在 HTML 中可读且易于处理。所以没有仅仅为了演示目的而花哨的结构,也没有 JavaScript(是的,我已经看过 UltimateGuitar 是如何做到的,这完全不是我想要的)。我需要每个元素都与某个逻辑部分直接对应,就像原始格式一样。
另一方面,这让我很难设计一个呈现堆叠和弦的 CSS。基本规则是你有一个由文本部分和和弦部分组成的“盒子”,整个盒子的宽度应该是两个部分的最大值,每个部分可以包含任意长的文本:
Am Cmaj7/G Am G F Am/G E7 F#sus4 A
longstuff short multichord more end. e - ternal
装箱结构是预先知道的,所以你可以假设它是给定的:
((Am) (longstuff))
((Cmaj7/G) (short))
((Am G) (multichord))
((F Am/G) (more))
end.
((E7) ())
((F#sus4 A) (e))ternal
请注意,在最后一个框中,单词被连字符连接以补偿第一个音节上的两个和弦。我担心这会使 CSS 变得非常困难,因此它可能会以稍微不同的方式表示,例如
((F#sus4 A) (e) (ternal))
你可以想出替代方案,只要它们仍然具有简洁的语义。这是我到目前为止的想法:
.verse {
line-height: 3rem;
font-family: serif;
}
.cbox {
border: 1px solid;
}
.chord {
position: absolute;
transform: translate(0, -1.1rem);
font-weight: bold;
font-family: monospace;
user-select: none;
font-size: large;
}
<p class="verse">
Test
<span class="cbox"><span class="chord">Abc</span>X</span>
<span class="cbox"><span class="chord">Abc</span>Xyzwv</span>
<span class="cbox"><span class="chord">Abc</span>Xyzw</span>abc
sd
<br/>
Test
<span class="cbox"><span class="chord">Abc De</span>Xy</span>zwv
sd
<br/>
<span class="cbox"><span class="chord">Ab</span>xyz</span>
<span class="cbox"><span class="chord">Abc#sus4/C</span>Zyzw xyz</span>
<span class="cbox"><span class="chord">Am</span>xyzw</span>
<br/>
<span class="cbox"><span class="chord">D</span>xyz</span>
<span class="cbox""><span class="chord">E7</span></span>
two
<span class="cbox"><span class="chord">E7</span>th</span>ree
</p>
选择尺寸和边框进行调试。如您所见,顶部(弦)部分的宽度未被考虑在内(因为 position: absolute
阻止了这一点)。
我尝试了其他一些变体,包括这个:<span class="cbox" data-w="2" data-c="Am">longstuff</span>
,其中 data-w
是和弦名称中的字母数,用于跨度的 min-width
, 并且 data-c
被放入 before
伪元素中,但我仍然没有成功获得正确的宽度。
关于断字问题,我完全不知道。
我可能会使用 XHTML,虽然我想这不会有太大的不同。
我建议使用 CSS grid 来避免重叠。
你可以指定一个1列2行的网格模板,然后用classes告诉内容应该放在哪一行。网格将很好地填充并根据需要创建隐式新列。如果您有一系列连续的和弦或文本,它甚至可以工作,而无需在包装元素中包装 chord/text 对。
对于断字,如果可能的话,我会在需要断字的音节中添加额外的 class,然后使用 CSS.
中的伪元素创建连字符
这是一个工作示例。希望这会有所帮助。这是一个有趣的挑战。
.line {
display: grid;
justify-content: start;
grid-template-columns: auto;
grid-template-rows: auto auto;
grid-auto-flow: column;
gap: 0 0.6em;
margin-bottom: 1em;
}
.chord {
grid-row-start: 1;
}
.text {
grid-row-start: 2;
}
.hyphenated:after {
content: ' - '
}
<span class="line">
<span class="chord">Am</span>
<span class="text">longstuff</span>
<span class="chord">Cmaj7/G</span>
<span class="text">short</span>
<span class="chord">Am G</span>
<span class="text">multichord</span>
<span class="chord">F Am/G</span>
<span class="text">more</span>
<span class="text">end.</span>
<span class="chord">E7</span>
<span class="chord">F#sus4 A</span>
<span class="text hyphenated">e</span>
<span class="text">ternal</span>
</span>
<hr>
<p class="verse">
<span class="line">
<span class="chord">C</span>
<span class="text">Frosty the</span>
<span class="chord">C7</span>
<span class="text">snowman</span>
</span>
<span class="line">
<span class="text">was a</span>
<span class="chord">F</span>
<span class="text">jolly</span>
<span class="chord">F#dim</span>
<span class="text">happy</span>
<span class="chord">C</span>
<span class="text">soul</span>
<span class="chord">C7</span>
</span>
<span class="line">
<span class="text">with a</span>
<span class="chord">F</span>
<span class="text">corncob</span>
<span class="chord">F#dim</span>
<span class="text">pipe and a</span>
<span class="chord">C</span>
<span class="text">button</span>
<span class="chord">A7</span>
<span class="text">nose</span>
</span>
<span class="line">
<span class="text">and two</span>
<span class="chord">Dm7</span>
<span class="text">eyes made</span>
<span class="chord">G7</span>
<span class="text">out of</span>
<span class="chord">C</span>
<span class="text">coal.</span>
<span class="chord">C7</span>
</span>
</p>
编辑:上述方法的一个缺点是,如果没有样式,内容很难理解。
更多语义方法可以将CSS网格与自定义data-*
属性和CSS变量回退中定义的内容结合起来。这样,和弦将作为属性存储,而不是散布在歌词中的标记文本。
.verse {
line-height: 2;
}
.lyric {
display: inline-grid;
grid-template-columns: auto;
grid-template-rows: auto auto;
line-height: 1;
}
.lyric[data-chord] {
--chord: attr(data-chord);
}
.lyric:before {
content: var(--chord, '[=12=]a0');
}
<p class="verse">
<span class="lyric" data-chord="C">Frosty the</span>
<span class="lyric" data-chord="C7">snowman</span>
<br>
<span class="lyric">was a</span>
<span class="lyric" data-chord="F">jolly</span>
<span class="lyric" data-chord="F#dim">happy</span>
<span class="lyric" data-chord="C">soul</span>
<span class="lyric" data-chord="C7"></span>
<br>
<span class="lyric">with a</span>
<span class="lyric" data-chord="F">corncob</span>
<span class="lyric" data-chord="F#dim">pipe and a</span>
<span class="lyric" data-chord="C">button</span>
<span class="lyric" data-chord="A7">nose</span>
<br>
<span class="lyric">and two</span>
<span class="lyric" data-chord="Dm7">eyes made</span>
<span class="lyric" data-chord="G7">out of</span>
<span class="lyric" data-chord="C">coal.</span>
<span class="lyric" data-chord="C7"></span>
</p>
这会为每个 .lyric
跨度创建一个单列、两行的内联网格。 --chord
的值设置为 data-chord
属性 的值,仅在具有 属性 的元素上。 然后使用在 all .lyric
元素中设置 :before
伪元素的内容,如果变量是不明确的。这很重要,因为它会将 .lyric
没有和弦的跨度的文本推入底行,并使文本保持水平对齐。
我正在寻找一种基于 HTML 的表示形式,用于在音节上方带有和弦的歌曲文本,采用以下方式:
Am C D F
There is a house in New Orleans
现在,我不在乎 HTML 到底长什么样子,但有一个重要的约束:目的不仅是显示,而且是以语义上有意义的表示形式存储。具体来说,这些歌曲是从 LaTeX-based 语法转换而来的,应该可以以其原始形式恢复,并且在 HTML 中可读且易于处理。所以没有仅仅为了演示目的而花哨的结构,也没有 JavaScript(是的,我已经看过 UltimateGuitar 是如何做到的,这完全不是我想要的)。我需要每个元素都与某个逻辑部分直接对应,就像原始格式一样。
另一方面,这让我很难设计一个呈现堆叠和弦的 CSS。基本规则是你有一个由文本部分和和弦部分组成的“盒子”,整个盒子的宽度应该是两个部分的最大值,每个部分可以包含任意长的文本:
Am Cmaj7/G Am G F Am/G E7 F#sus4 A
longstuff short multichord more end. e - ternal
装箱结构是预先知道的,所以你可以假设它是给定的:
((Am) (longstuff))
((Cmaj7/G) (short))
((Am G) (multichord))
((F Am/G) (more))
end.
((E7) ())
((F#sus4 A) (e))ternal
请注意,在最后一个框中,单词被连字符连接以补偿第一个音节上的两个和弦。我担心这会使 CSS 变得非常困难,因此它可能会以稍微不同的方式表示,例如
((F#sus4 A) (e) (ternal))
你可以想出替代方案,只要它们仍然具有简洁的语义。这是我到目前为止的想法:
.verse {
line-height: 3rem;
font-family: serif;
}
.cbox {
border: 1px solid;
}
.chord {
position: absolute;
transform: translate(0, -1.1rem);
font-weight: bold;
font-family: monospace;
user-select: none;
font-size: large;
}
<p class="verse">
Test
<span class="cbox"><span class="chord">Abc</span>X</span>
<span class="cbox"><span class="chord">Abc</span>Xyzwv</span>
<span class="cbox"><span class="chord">Abc</span>Xyzw</span>abc
sd
<br/>
Test
<span class="cbox"><span class="chord">Abc De</span>Xy</span>zwv
sd
<br/>
<span class="cbox"><span class="chord">Ab</span>xyz</span>
<span class="cbox"><span class="chord">Abc#sus4/C</span>Zyzw xyz</span>
<span class="cbox"><span class="chord">Am</span>xyzw</span>
<br/>
<span class="cbox"><span class="chord">D</span>xyz</span>
<span class="cbox""><span class="chord">E7</span></span>
two
<span class="cbox"><span class="chord">E7</span>th</span>ree
</p>
选择尺寸和边框进行调试。如您所见,顶部(弦)部分的宽度未被考虑在内(因为 position: absolute
阻止了这一点)。
我尝试了其他一些变体,包括这个:<span class="cbox" data-w="2" data-c="Am">longstuff</span>
,其中 data-w
是和弦名称中的字母数,用于跨度的 min-width
, 并且 data-c
被放入 before
伪元素中,但我仍然没有成功获得正确的宽度。
关于断字问题,我完全不知道。
我可能会使用 XHTML,虽然我想这不会有太大的不同。
我建议使用 CSS grid 来避免重叠。
你可以指定一个1列2行的网格模板,然后用classes告诉内容应该放在哪一行。网格将很好地填充并根据需要创建隐式新列。如果您有一系列连续的和弦或文本,它甚至可以工作,而无需在包装元素中包装 chord/text 对。
对于断字,如果可能的话,我会在需要断字的音节中添加额外的 class,然后使用 CSS.
中的伪元素创建连字符这是一个工作示例。希望这会有所帮助。这是一个有趣的挑战。
.line {
display: grid;
justify-content: start;
grid-template-columns: auto;
grid-template-rows: auto auto;
grid-auto-flow: column;
gap: 0 0.6em;
margin-bottom: 1em;
}
.chord {
grid-row-start: 1;
}
.text {
grid-row-start: 2;
}
.hyphenated:after {
content: ' - '
}
<span class="line">
<span class="chord">Am</span>
<span class="text">longstuff</span>
<span class="chord">Cmaj7/G</span>
<span class="text">short</span>
<span class="chord">Am G</span>
<span class="text">multichord</span>
<span class="chord">F Am/G</span>
<span class="text">more</span>
<span class="text">end.</span>
<span class="chord">E7</span>
<span class="chord">F#sus4 A</span>
<span class="text hyphenated">e</span>
<span class="text">ternal</span>
</span>
<hr>
<p class="verse">
<span class="line">
<span class="chord">C</span>
<span class="text">Frosty the</span>
<span class="chord">C7</span>
<span class="text">snowman</span>
</span>
<span class="line">
<span class="text">was a</span>
<span class="chord">F</span>
<span class="text">jolly</span>
<span class="chord">F#dim</span>
<span class="text">happy</span>
<span class="chord">C</span>
<span class="text">soul</span>
<span class="chord">C7</span>
</span>
<span class="line">
<span class="text">with a</span>
<span class="chord">F</span>
<span class="text">corncob</span>
<span class="chord">F#dim</span>
<span class="text">pipe and a</span>
<span class="chord">C</span>
<span class="text">button</span>
<span class="chord">A7</span>
<span class="text">nose</span>
</span>
<span class="line">
<span class="text">and two</span>
<span class="chord">Dm7</span>
<span class="text">eyes made</span>
<span class="chord">G7</span>
<span class="text">out of</span>
<span class="chord">C</span>
<span class="text">coal.</span>
<span class="chord">C7</span>
</span>
</p>
编辑:上述方法的一个缺点是,如果没有样式,内容很难理解。
更多语义方法可以将CSS网格与自定义data-*
属性和CSS变量回退中定义的内容结合起来。这样,和弦将作为属性存储,而不是散布在歌词中的标记文本。
.verse {
line-height: 2;
}
.lyric {
display: inline-grid;
grid-template-columns: auto;
grid-template-rows: auto auto;
line-height: 1;
}
.lyric[data-chord] {
--chord: attr(data-chord);
}
.lyric:before {
content: var(--chord, '[=12=]a0');
}
<p class="verse">
<span class="lyric" data-chord="C">Frosty the</span>
<span class="lyric" data-chord="C7">snowman</span>
<br>
<span class="lyric">was a</span>
<span class="lyric" data-chord="F">jolly</span>
<span class="lyric" data-chord="F#dim">happy</span>
<span class="lyric" data-chord="C">soul</span>
<span class="lyric" data-chord="C7"></span>
<br>
<span class="lyric">with a</span>
<span class="lyric" data-chord="F">corncob</span>
<span class="lyric" data-chord="F#dim">pipe and a</span>
<span class="lyric" data-chord="C">button</span>
<span class="lyric" data-chord="A7">nose</span>
<br>
<span class="lyric">and two</span>
<span class="lyric" data-chord="Dm7">eyes made</span>
<span class="lyric" data-chord="G7">out of</span>
<span class="lyric" data-chord="C">coal.</span>
<span class="lyric" data-chord="C7"></span>
</p>
这会为每个 .lyric
跨度创建一个单列、两行的内联网格。 --chord
的值设置为 data-chord
属性 的值,仅在具有 属性 的元素上。 然后使用在 all .lyric
元素中设置 :before
伪元素的内容,如果变量是不明确的。这很重要,因为它会将 .lyric
没有和弦的跨度的文本推入底行,并使文本保持水平对齐。