我正在为音节上方有和弦的歌曲文本寻找一种基于HTML的表示方式,如下所示:
Am C D F
There is a house in New Orleans
现在,我不在乎HTML最终会是什么样子,但有一个重要的约束:目的不仅是显示,而且是以语义上有意义的表示进行存储。具体来说,这些歌曲是从基于LaTeX的语法转换而来的,应该可以恢复其原始形式,并且可以在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网格来避免重叠。
您可以指定一个由1列和2行组成的网格模板,然后使用类来告诉内容应该放入哪一行。网格将很好地填充,并根据需要创建隐含的新列。如果你在一行中有一系列和弦或文本,它甚至可以工作,而不需要在换行元素中换行和弦/文本对。
对于连字符,如果可能的话,我会为需要连字符的音节添加一个额外的类,然后使用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>
编辑:上述方法的一个缺点是,如果没有样式,内容很难理解。
more语义方法可以是将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, ' 0a0');
}
<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
属性的元素上设置为该属性的值然后在所有.lyric
元素中使用它来设置:before
伪元素的内容,如果变量未定义,则回退到非中断空间。这一点很重要,因为它将文本推入没有和弦的.lyric
跨度的最底层,并保持文本水平对齐。